summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorKiyoung Chang <[email protected]>2026-02-03 14:13:24 +0900
committerGitHub <[email protected]>2026-02-02 23:13:24 -0600
commit3adeed8f97d612171dfdecf8cc33eee193811172 (patch)
tree36c401b3cc49327bea9fbff5f6f6c3a1dbe49fb8 /packages
parent1275c71a63c2ef34f46734b0802dd34435fcb5f6 (diff)
downloadopencode-3adeed8f97d612171dfdecf8cc33eee193811172.tar.gz
opencode-3adeed8f97d612171dfdecf8cc33eee193811172.zip
fix(provider): strip properties/required from non-object types in Gemini schema (#11888)
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/provider/transform.ts6
-rw-r--r--packages/opencode/test/provider/transform.test.ts110
2 files changed, 116 insertions, 0 deletions
diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts
index c05bf75c4..b4f1aaca4 100644
--- a/packages/opencode/src/provider/transform.ts
+++ b/packages/opencode/src/provider/transform.ts
@@ -772,6 +772,12 @@ export namespace ProviderTransform {
result.items = {}
}
+ // Remove properties/required from non-object types (Gemini rejects these)
+ if (result.type && result.type !== "object") {
+ delete result.properties
+ delete result.required
+ }
+
return result
}
diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts
index 8e28f1209..0743049fe 100644
--- a/packages/opencode/test/provider/transform.test.ts
+++ b/packages/opencode/test/provider/transform.test.ts
@@ -293,6 +293,116 @@ describe("ProviderTransform.schema - gemini array items", () => {
})
})
+describe("ProviderTransform.schema - gemini non-object properties removal", () => {
+ const geminiModel = {
+ providerID: "google",
+ api: {
+ id: "gemini-3-pro",
+ },
+ } as any
+
+ test("removes properties from non-object types", () => {
+ const schema = {
+ type: "object",
+ properties: {
+ data: {
+ type: "string",
+ properties: { invalid: { type: "string" } },
+ },
+ },
+ } as any
+
+ const result = ProviderTransform.schema(geminiModel, schema) as any
+
+ expect(result.properties.data.type).toBe("string")
+ expect(result.properties.data.properties).toBeUndefined()
+ })
+
+ test("removes required from non-object types", () => {
+ const schema = {
+ type: "object",
+ properties: {
+ data: {
+ type: "array",
+ items: { type: "string" },
+ required: ["invalid"],
+ },
+ },
+ } as any
+
+ const result = ProviderTransform.schema(geminiModel, schema) as any
+
+ expect(result.properties.data.type).toBe("array")
+ expect(result.properties.data.required).toBeUndefined()
+ })
+
+ test("removes properties and required from nested non-object types", () => {
+ const schema = {
+ type: "object",
+ properties: {
+ outer: {
+ type: "object",
+ properties: {
+ inner: {
+ type: "number",
+ properties: { bad: { type: "string" } },
+ required: ["bad"],
+ },
+ },
+ },
+ },
+ } as any
+
+ const result = ProviderTransform.schema(geminiModel, schema) as any
+
+ expect(result.properties.outer.properties.inner.type).toBe("number")
+ expect(result.properties.outer.properties.inner.properties).toBeUndefined()
+ expect(result.properties.outer.properties.inner.required).toBeUndefined()
+ })
+
+ test("keeps properties and required on object types", () => {
+ const schema = {
+ type: "object",
+ properties: {
+ data: {
+ type: "object",
+ properties: { name: { type: "string" } },
+ required: ["name"],
+ },
+ },
+ } as any
+
+ const result = ProviderTransform.schema(geminiModel, schema) as any
+
+ expect(result.properties.data.type).toBe("object")
+ expect(result.properties.data.properties).toBeDefined()
+ expect(result.properties.data.required).toEqual(["name"])
+ })
+
+ test("does not affect non-gemini providers", () => {
+ const openaiModel = {
+ providerID: "openai",
+ api: {
+ id: "gpt-4",
+ },
+ } as any
+
+ const schema = {
+ type: "object",
+ properties: {
+ data: {
+ type: "string",
+ properties: { invalid: { type: "string" } },
+ },
+ },
+ } as any
+
+ const result = ProviderTransform.schema(openaiModel, schema) as any
+
+ expect(result.properties.data.properties).toBeDefined()
+ })
+})
+
describe("ProviderTransform.message - DeepSeek reasoning content", () => {
test("DeepSeek with tool calls includes reasoning_content in providerOptions", () => {
const msgs = [