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.ts (1 of 4 files). Show all

Unified · Split

apps/server/src/git/Layers/OpenCodeTextGeneration.ts+57−11
@@ -19,10 +19,10 @@ import { · 18 unmodified lines
1919 } from "../Prompts.ts";
2020 import { type TextGenerationShape, TextGeneration } from "../Services/TextGeneration.ts";
2121 import {
22+ extractJsonObject,
2223 sanitizeCommitSubject,
2324 sanitizePrTitle,
2425 sanitizeThreadTitle,
25− toJsonSchemaObject,
2626 } from "../Utils.ts";
2727 import {
2828 createOpenCodeSdkClient,
@@ -35,6 +35,49 @@ import { · 6 unmodified lines
3535
3636 const OPENCODE_TEXT_GENERATION_IDLE_TTL_MS = 30_000;
3737
38+function getOpenCodePromptErrorMessage(error: unknown): string | null {
39+ if (!error || typeof error !== "object") {
40+ return null;
41+ }
42+
43+ const message =
44+ "data" in error &&
45+ error.data &&
46+ typeof error.data === "object" &&
47+ "message" in error.data &&
48+ typeof error.data.message === "string"
49+ ? error.data.message.trim()
50+ : "";
51+ if (message.length > 0) {
52+ return message;
53+ }
54+
55+ if ("name" in error && typeof error.name === "string") {
56+ const name = error.name.trim();
57+ return name.length > 0 ? name : null;
58+ }
59+
60+ return null;
61+}
62+
63+function getOpenCodeTextResponse(parts: ReadonlyArray<unknown> | undefined): string {
64+ return (parts ?? [])
65+ .flatMap((part) => {
66+ if (!part || typeof part !== "object") {
67+ return [];
68+ }
69+ if (!("type" in part) || part.type !== "text") {
70+ return [];
71+ }
72+ if (!("text" in part) || typeof part.text !== "string") {
73+ return [];
74+ }
75+ return [part.text];
76+ })
77+ .join("")
78+ .trim();
79+}
80+
3881 interface SharedOpenCodeTextGenerationServerState {
3982 server: OpenCodeServerProcess | null;
4083 binaryPath: string | null;
@@ -245,17 +288,18 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 204 unmodified lines
245288 ...(input.modelSelection.options?.variant
246289 ? { variant: input.modelSelection.options.variant }
247290 : {}),
248− format: {
249− type: "json_schema",
250− schema: toJsonSchemaObject(input.outputSchemaJson) as Record<string, unknown>,
251− },
252291 parts: [{ type: "text", text: input.prompt }, ...fileParts],
253292 });
254− const structured = result.data?.info?.structured;
255− if (structured === undefined) {
256− throw new Error("OpenCode returned no structured output.");
293+ const info = result.data?.info;
294+ const errorMessage = getOpenCodePromptErrorMessage(info?.error);
295+ if (errorMessage) {
296+ throw new Error(errorMessage);
297+ }
298+ const rawText = getOpenCodeTextResponse(result.data?.parts);
299+ if (rawText.length === 0) {
300+ throw new Error("OpenCode returned empty output.");
257301 }
258− return structured;
302+ return rawText;
259303 },
260304 catch: (cause) =>
261305 new TextGenerationError({
@@ -266,7 +310,7 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 4 unmodified lines
266310 }),
267311 });
268312
269− const structuredOutput =
313+ const rawOutput =
270314 settings.serverUrl.length > 0
271315 ? yield* runAgainstServer({ url: settings.serverUrl })
272316 : yield* Effect.acquireUseRelease(
@@ -278,7 +322,9 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 5 unmodified lines
278322 releaseSharedServer,
279323 );
280324
281− return yield* Schema.decodeUnknownEffect(input.outputSchemaJson)(structuredOutput).pipe(
325+ return yield* Schema.decodeEffect(Schema.fromJsonString(input.outputSchemaJson))(
326+ extractJsonObject(rawOutput),
327+ ).pipe(
282328 Effect.catchTag("SchemaError", (cause) =>
283329 Effect.fail(
284330 new TextGenerationError({