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
19} from "../Prompts.ts";19} from "../Prompts.ts";
20import { type TextGenerationShape, TextGeneration } from "../Services/TextGeneration.ts";20import { type TextGenerationShape, TextGeneration } from "../Services/TextGeneration.ts";
21import {21import {
22 extractJsonObject,
22 sanitizeCommitSubject,23 sanitizeCommitSubject,
23 sanitizePrTitle,24 sanitizePrTitle,
24 sanitizeThreadTitle,25 sanitizeThreadTitle,
25 toJsonSchemaObject,
26} from "../Utils.ts";26} from "../Utils.ts";
27import {27import {
28 createOpenCodeSdkClient,28 createOpenCodeSdkClient,
@@ -35,6 +35,49 @@ import { · 6 unmodified lines
35 35
36const OPENCODE_TEXT_GENERATION_IDLE_TTL_MS = 30_000;36const OPENCODE_TEXT_GENERATION_IDLE_TTL_MS = 30_000;
37 37
38function 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
63function 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
38interface SharedOpenCodeTextGenerationServerState {81interface SharedOpenCodeTextGenerationServerState {
39 server: OpenCodeServerProcess | null;82 server: OpenCodeServerProcess | null;
40 binaryPath: string | null;83 binaryPath: string | null;
@@ -245,17 +288,18 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 204 unmodified lines
245 ...(input.modelSelection.options?.variant288 ...(input.modelSelection.options?.variant
246 ? { variant: input.modelSelection.options.variant }289 ? { variant: input.modelSelection.options.variant }
247 : {}),290 : {}),
248 format: {
249 type: "json_schema",
250 schema: toJsonSchemaObject(input.outputSchemaJson) as Record<string, unknown>,
251 },
252 parts: [{ type: "text", text: input.prompt }, ...fileParts],291 parts: [{ type: "text", text: input.prompt }, ...fileParts],
253 });292 });
254 const structured = result.data?.info?.structured;293 const info = result.data?.info;
255 if (structured === undefined) {294 const errorMessage = getOpenCodePromptErrorMessage(info?.error);
256 throw new Error("OpenCode returned no structured output.");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.");
257 }301 }
258 return structured;302 return rawText;
259 },303 },
260 catch: (cause) =>304 catch: (cause) =>
261 new TextGenerationError({305 new TextGenerationError({
@@ -266,7 +310,7 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 4 unmodified lines
266 }),310 }),
267 });311 });
268 312
269 const structuredOutput =313 const rawOutput =
270 settings.serverUrl.length > 0314 settings.serverUrl.length > 0
271 ? yield* runAgainstServer({ url: settings.serverUrl })315 ? yield* runAgainstServer({ url: settings.serverUrl })
272 : yield* Effect.acquireUseRelease(316 : yield* Effect.acquireUseRelease(
@@ -278,7 +322,9 @@ const makeOpenCodeTextGeneration = Effect.gen(function* () { · 5 unmodified lines
278 releaseSharedServer,322 releaseSharedServer,
279 );323 );
280 324
281 return yield* Schema.decodeUnknownEffect(input.outputSchemaJson)(structuredOutput).pipe(325 return yield* Schema.decodeEffect(Schema.fromJsonString(input.outputSchemaJson))(
326 extractJsonObject(rawOutput),
327 ).pipe(
282 Effect.catchTag("SchemaError", (cause) =>328 Effect.catchTag("SchemaError", (cause) =>
283 Effect.fail(329 Effect.fail(
284 new TextGenerationError({330 new TextGenerationError({