History

fix(server): handle OpenCode text response format in commit message g… (#2202)

Abdul Azeez committed 6 months ago

Commit 37965da1 parent 57b59b54 files · +184 −68Browse files

Showing the changes to apps/server/src/git/Layers/OpenCodeTextGeneration.test.ts (1 of 4 files). Show all

Unified · Split

apps/server/src/git/Layers/OpenCodeTextGeneration.test.ts+73−8
@@ -17,7 +17,9 @@ const runtimeMock = vi.hoisted(() => { · 16 unmodified lines
1717 promptUrls: [] as string[],
1818 authHeaders: [] as Array<string | null>,
1919 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,
2123 };
2224
2325 return {
@@ -63,12 +65,15 @@ vi.mock("../../provider/opencodeRuntime.ts", async () => { · 39 unmodified lines
6365 return (
6466 runtimeMock.state.promptResult ?? {
6567 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+ }),
7075 },
71− },
76+ ],
7277 },
7378 }
7479 );
@@ -198,7 +203,7 @@ it.layer(OpenCodeTextGenerationTestLayer)("OpenCodeTextGenerationLive", (it) => · 123 unmodified lines
198203 }).pipe(Effect.provide(TestClock.layer())),
199204 );
200205
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", () =>
202207 Effect.gen(function* () {
203208 runtimeMock.state.promptResult = { data: {} };
204209 const textGeneration = yield* TextGeneration;
@@ -213,7 +218,67 @@ it.layer(OpenCodeTextGenerationTestLayer)("OpenCodeTextGenerationLive", (it) => · 8 unmodified lines
213218 })
214219 .pipe(Effect.flip);
215220
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");
217282 }),
218283 );
219284 });