Skip to content

Commit 58d6417

Browse files
authored
Merge pull request #261 from LeXwDeX/dev
fix(provider): object-root union schemas for all openai-compatible backends
2 parents 56e48e7 + e02f5d3 commit 58d6417

2 files changed

Lines changed: 20 additions & 4 deletions

File tree

packages/opencode/src/provider/transform.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,11 +1537,13 @@ export function schema(model: Provider.Model, schema: JSONSchema7): JSONSchema7
15371537
schema = sanitizeGemini(schema)
15381538
}
15391539

1540-
// DeepSeek rejects function schemas whose root type is implicit. Effect
1541-
// emits object-only discriminated unions as a root `anyOf`; retaining the
1542-
// union while declaring its shared object type preserves every branch.
1540+
// OpenAI-compatible backends (DeepSeek, GLM, and other relays) reject
1541+
// function schemas whose root type is implicit — the model emits empty
1542+
// tool arguments instead of erroring. Effect emits object-only
1543+
// discriminated unions as a root `anyOf`; retaining the union while
1544+
// declaring its shared object type preserves every branch.
15431545
if (
1544-
model.api.id.toLowerCase().includes("deepseek") &&
1546+
model.api.npm === "@ai-sdk/openai-compatible" &&
15451547
schema.type === undefined &&
15461548
Array.isArray(schema.anyOf) &&
15471549
schema.anyOf.length > 0 &&

packages/opencode/test/tool/workflow-provider-schema.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const deepseekModel = {
1515
providerID: "deepseek",
1616
api: { id: "deepseek-v4-pro", npm: "@ai-sdk/openai-compatible" },
1717
} as never
18+
const glmModel = {
19+
providerID: "local-proxy",
20+
api: { id: "glm-5.3", npm: "@ai-sdk/openai-compatible" },
21+
} as never
1822

1923
type JsonSchemaNode = {
2024
anyOf?: JsonSchemaNode[]
@@ -131,6 +135,16 @@ describe("workflow provider-facing schema", () => {
131135
expect(branchByAction(transformed, "start", "spec_path")).toHaveLength(1)
132136
})
133137

138+
test("OpenAI-compatible transports (GLM relay) also get the object-root union", () => {
139+
const transformed = ProviderTransform.schema(
140+
glmModel,
141+
ToolJsonSchema.fromSchema(Parameters as never),
142+
) as JsonSchemaNode
143+
expect(transformed.type).toBe("object")
144+
expect(branches(transformed)).toHaveLength(10)
145+
expect(branchByAction(transformed, "start", "spec_path")).toHaveLength(1)
146+
})
147+
134148
test("post-change byte sizes stay at the recorded evidence", async () => {
135149
const evidence = (await Bun.file(
136150
new URL("./fixtures/workflow-parameters-post-change.json", import.meta.url),

0 commit comments

Comments
 (0)