Skip to content

Commit dbe7e77

Browse files
keyzouclaude
andcommitted
Extract shared toJsonSchemaObject helper for JSON Schema conversion
Both ClaudeTextGeneration and CodexTextGeneration had identical logic to convert an Effect Schema into a flat JSON Schema object. Move it into textGenerationUtils.ts as a single shared helper. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ac378af commit dbe7e77

3 files changed

Lines changed: 13 additions & 25 deletions

File tree

apps/server/src/git/Layers/ClaudeTextGeneration.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,11 @@ import {
2626
buildCommitMessagePrompt,
2727
buildPrContentPrompt,
2828
} from "./textGenerationPrompts.ts";
29-
import { normalizeCliError, sanitizeCommitSubject, sanitizePrTitle } from "./textGenerationUtils.ts";
29+
import { normalizeCliError, sanitizeCommitSubject, sanitizePrTitle, toJsonSchemaObject } from "./textGenerationUtils.ts";
3030

3131
const CLAUDE_REASONING_EFFORT = "low";
3232
const CLAUDE_TIMEOUT_MS = 180_000;
3333

34-
/** Build a JSON-schema string suitable for the Claude CLI `--json-schema` flag. */
35-
function toClaudeJsonSchemaString(schema: Schema.Top): string {
36-
const document = Schema.toJsonSchemaDocument(schema);
37-
const schemaObj =
38-
document.definitions && Object.keys(document.definitions).length > 0
39-
? { ...document.schema, $defs: document.definitions }
40-
: document.schema;
41-
return JSON.stringify(schemaObj);
42-
}
43-
4434
/**
4535
* Schema for the wrapper JSON returned by `claude -p --output-format json`.
4636
* We only care about `structured_output`.
@@ -88,7 +78,7 @@ const makeClaudeTextGeneration = Effect.gen(function* () {
8878
model?: string;
8979
}): Effect.Effect<S["Type"], TextGenerationError, S["DecodingServices"]> =>
9080
Effect.gen(function* () {
91-
const jsonSchemaStr = toClaudeJsonSchemaString(outputSchemaJson);
81+
const jsonSchemaStr = JSON.stringify(toJsonSchemaObject(outputSchemaJson));
9282

9383
const runClaudeCommand = Effect.gen(function* () {
9484
const command = ChildProcess.make(

apps/server/src/git/Layers/CodexTextGeneration.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,11 @@ import {
2222
buildCommitMessagePrompt,
2323
buildPrContentPrompt,
2424
} from "./textGenerationPrompts.ts";
25-
import { normalizeCliError, sanitizeCommitSubject, sanitizePrTitle } from "./textGenerationUtils.ts";
25+
import { normalizeCliError, sanitizeCommitSubject, sanitizePrTitle, toJsonSchemaObject } from "./textGenerationUtils.ts";
2626

2727
const CODEX_REASONING_EFFORT = "low";
2828
const CODEX_TIMEOUT_MS = 180_000;
2929

30-
function toCodexOutputJsonSchema(schema: Schema.Top): unknown {
31-
const document = Schema.toJsonSchemaDocument(schema);
32-
if (document.definitions && Object.keys(document.definitions).length > 0) {
33-
return {
34-
...document.schema,
35-
$defs: document.definitions,
36-
};
37-
}
38-
return document.schema;
39-
}
40-
4130
const makeCodexTextGeneration = Effect.gen(function* () {
4231
const fileSystem = yield* FileSystem.FileSystem;
4332
const path = yield* Path.Path;
@@ -144,7 +133,7 @@ const makeCodexTextGeneration = Effect.gen(function* () {
144133
const schemaPath = yield* writeTempFile(
145134
operation,
146135
"codex-schema",
147-
JSON.stringify(toCodexOutputJsonSchema(outputSchemaJson)),
136+
JSON.stringify(toJsonSchemaObject(outputSchemaJson)),
148137
);
149138
const outputPath = yield* writeTempFile(operation, "codex-output", "");
150139

apps/server/src/git/Layers/textGenerationUtils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import { Schema } from "effect";
77

88
import { TextGenerationError } from "../Errors.ts";
99

10+
/** Convert an Effect Schema to a flat JSON Schema object, inlining `$defs` when present. */
11+
export function toJsonSchemaObject(schema: Schema.Top): unknown {
12+
const document = Schema.toJsonSchemaDocument(schema);
13+
if (document.definitions && Object.keys(document.definitions).length > 0) {
14+
return { ...document.schema, $defs: document.definitions };
15+
}
16+
return document.schema;
17+
}
18+
1019
/** Truncate a text section to `maxChars`, appending a `[truncated]` marker when needed. */
1120
export function limitSection(value: string, maxChars: number): string {
1221
if (value.length <= maxChars) return value;

0 commit comments

Comments
 (0)