Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,12 @@ export namespace ProviderTransform {
}
}

// Infer type "object" when properties/required exist but type is missing
// (common in MCP tool schemas like Notion MCP)
if (!result.type && (result.properties || result.required)) {
result.type = "object"
}

// Remove properties/required from non-object types (Gemini rejects these)
if (result.type && result.type !== "object") {
delete result.properties
Expand Down
43 changes: 43 additions & 0 deletions packages/opencode/test/provider/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,49 @@ describe("ProviderTransform.schema - gemini non-object properties removal", () =
expect(result.properties.data.required).toEqual(["name"])
})

test("infers type 'object' when properties exist but type is missing", () => {
const schema = {
type: "object",
properties: {
data: {
description: "The data",
properties: { page_id: { type: "string" } },
required: ["page_id"],
},
},
} 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(["page_id"])
})

test("infers type 'object' for array items with properties but no type", () => {
const schema = {
type: "object",
properties: {
title: {
type: "array",
items: {
properties: {
annotations: {
type: "object",
properties: { bold: { type: "boolean" } },
},
},
},
},
},
} as any

const result = ProviderTransform.schema(geminiModel, schema) as any

expect(result.properties.title.items.type).toBe("object")
expect(result.properties.title.items.properties).toBeDefined()
})

test("does not affect non-gemini providers", () => {
const openaiModel = {
providerID: "openai",
Expand Down
Loading