Showing the changes to apps/server/src/git/Layers/OpenCodeTextGeneration.test.ts (1 of 4 files). Show all
Unified · Split
| @@ -17,7 +17,9 @@ const runtimeMock = vi.hoisted(() => { · 16 unmodified lines | ||
| 17 | 17 | promptUrls: [] as string[], |
| 18 | 18 | authHeaders: [] as Array<string | null>, |
| 19 | 19 | closeCalls: [] as string[], |
| 20 | − promptResult: undefined as { data?: { info?: { structured?: unknown } } } | undefined, | |
| 20 | + promptResult: undefined as | |
| 21 | + | { data?: { info?: { error?: unknown }; parts?: Array<{ type: string; text?: string }> } } | |
| 22 | + | undefined, | |
| 21 | 23 | }; |
| 22 | 24 | |
| 23 | 25 | return { |
| @@ -63,12 +65,15 @@ vi.mock("../../provider/opencodeRuntime.ts", async () => { · 39 unmodified lines | ||
| 63 | 65 | return ( |
| 64 | 66 | runtimeMock.state.promptResult ?? { |
| 65 | 67 | data: { |
| 66 | − info: { | |
| 67 | − structured: { | |
| 68 | − subject: "Improve OpenCode reuse", | |
| 69 | − body: "Reuse one server for the full action.", | |
| 68 | + parts: [ | |
| 69 | + { | |
| 70 | + type: "text", | |
| 71 | + text: JSON.stringify({ | |
| 72 | + subject: "Improve OpenCode reuse", | |
| 73 | + body: "Reuse one server for the full action.", | |
| 74 | + }), | |
| 70 | 75 | }, |
| 71 | − }, | |
| 76 | + ], | |
| 72 | 77 | }, |
| 73 | 78 | } |
| 74 | 79 | ); |
| @@ -198,7 +203,7 @@ it.layer(OpenCodeTextGenerationTestLayer)("OpenCodeTextGenerationLive", (it) => · 123 unmodified lines | ||
| 198 | 203 | }).pipe(Effect.provide(TestClock.layer())), |
| 199 | 204 | ); |
| 200 | 205 | |
| 201 | − it.effect("returns a typed missing-output error when OpenCode omits info.structured", () => | |
| 206 | + it.effect("returns a typed empty-output error when OpenCode returns no text parts", () => | |
| 202 | 207 | Effect.gen(function* () { |
| 203 | 208 | runtimeMock.state.promptResult = { data: {} }; |
| 204 | 209 | const textGeneration = yield* TextGeneration; |
| @@ -213,7 +218,67 @@ it.layer(OpenCodeTextGenerationTestLayer)("OpenCodeTextGenerationLive", (it) => · 8 unmodified lines | ||
| 213 | 218 | }) |
| 214 | 219 | .pipe(Effect.flip); |
| 215 | 220 | |
| 216 | − expect(error.message).toContain("OpenCode returned no structured output."); | |
| 221 | + expect(error.message).toContain("OpenCode returned empty output."); | |
| 222 | + }), | |
| 223 | + ); | |
| 224 | + | |
| 225 | + it.effect("parses JSON returned as plain text output", () => | |
| 226 | + Effect.gen(function* () { | |
| 227 | + runtimeMock.state.promptResult = { | |
| 228 | + data: { | |
| 229 | + parts: [ | |
| 230 | + { | |
| 231 | + type: "text", | |
| 232 | + text: 'Here is the result:\n{"subject":"Tighten OpenCode parsing","body":"Handle JSON text output locally."}', | |
| 233 | + }, | |
| 234 | + ], | |
| 235 | + }, | |
| 236 | + }; | |
| 237 | + const textGeneration = yield* TextGeneration; | |
| 238 | + | |
| 239 | + const result = yield* textGeneration.generateCommitMessage({ | |
| 240 | + cwd: process.cwd(), | |
| 241 | + branch: "feature/opencode-reuse", | |
| 242 | + stagedSummary: "M README.md", | |
| 243 | + stagedPatch: "diff --git a/README.md b/README.md", | |
| 244 | + modelSelection: DEFAULT_TEST_MODEL_SELECTION, | |
| 245 | + }); | |
| 246 | + | |
| 247 | + expect(result).toEqual({ | |
| 248 | + subject: "Tighten OpenCode parsing", | |
| 249 | + body: "Handle JSON text output locally.", | |
| 250 | + }); | |
| 251 | + }), | |
| 252 | + ); | |
| 253 | + | |
| 254 | + it.effect("surfaces the upstream OpenCode structured-output error message", () => | |
| 255 | + Effect.gen(function* () { | |
| 256 | + runtimeMock.state.promptResult = { | |
| 257 | + data: { | |
| 258 | + info: { | |
| 259 | + error: { | |
| 260 | + name: "StructuredOutputError", | |
| 261 | + data: { | |
| 262 | + message: "Model did not produce structured output", | |
| 263 | + retries: 2, | |
| 264 | + }, | |
| 265 | + }, | |
| 266 | + }, | |
| 267 | + }, | |
| 268 | + }; | |
| 269 | + const textGeneration = yield* TextGeneration; | |
| 270 | + | |
| 271 | + const error = yield* textGeneration | |
| 272 | + .generateCommitMessage({ | |
| 273 | + cwd: process.cwd(), | |
| 274 | + branch: "feature/opencode-reuse", | |
| 275 | + stagedSummary: "M README.md", | |
| 276 | + stagedPatch: "diff --git a/README.md b/README.md", | |
| 277 | + modelSelection: DEFAULT_TEST_MODEL_SELECTION, | |
| 278 | + }) | |
| 279 | + .pipe(Effect.flip); | |
| 280 | + | |
| 281 | + expect(error.message).toContain("Model did not produce structured output"); | |
| 217 | 282 | }), |
| 218 | 283 | ); |
| 219 | 284 | }); |