diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index b659799c1b6..ef12dfa86fe 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -895,8 +895,13 @@ export namespace ProviderTransform { } */ - // Convert integer enums to string enums for Google/Gemini - if (model.providerID === "google" || model.api.id.includes("gemini")) { + // Convert integer enums to string enums for Google/Gemini. + // Skip for Copilot models — they use OpenAI-compatible format and the + // Copilot API handles Gemini schema requirements internally. + if ( + (model.providerID === "google" || model.api.id.includes("gemini")) && + !model.providerID.includes("github-copilot") + ) { const sanitizeGemini = (obj: any): any => { if (obj === null || typeof obj !== "object") { return obj diff --git a/packages/opencode/test/provider/transform.test.ts b/packages/opencode/test/provider/transform.test.ts index 189bdfd32b4..a247b0fbf8f 100644 --- a/packages/opencode/test/provider/transform.test.ts +++ b/packages/opencode/test/provider/transform.test.ts @@ -618,6 +618,63 @@ describe("ProviderTransform.schema - gemini non-object properties removal", () = expect(result.properties.data.properties).toBeDefined() }) + + test("does not apply to github-copilot provider even when api.id includes gemini", () => { + const copilotGeminiModel = { + providerID: "github-copilot", + api: { + id: "gemini-3-flash-preview", + }, + } as any + + const schema = { + type: "object", + properties: { + status: { + type: "integer", + enum: [1, 2, 3], + }, + data: { + type: "string", + properties: { invalid: { type: "string" } }, + required: ["invalid"], + }, + }, + } as any + + const result = ProviderTransform.schema(copilotGeminiModel, schema) as any + + // enum values should NOT be converted to strings + expect(result.properties.status.type).toBe("integer") + expect(result.properties.status.enum).toEqual([1, 2, 3]) + // properties/required should NOT be stripped from non-object types + expect(result.properties.data.properties).toBeDefined() + expect(result.properties.data.required).toBeDefined() + }) + + test("does not apply to github-copilot-enterprise provider", () => { + const copilotEnterpriseModel = { + providerID: "github-copilot-enterprise", + api: { + id: "gemini-3-flash-preview", + }, + } as any + + const schema = { + type: "object", + properties: { + count: { + type: "integer", + enum: [10, 20], + }, + }, + } as any + + const result = ProviderTransform.schema(copilotEnterpriseModel, schema) as any + + expect(result.properties.count.type).toBe("integer") + expect(result.properties.count.enum).toEqual([10, 20]) + }) }) describe("ProviderTransform.message - DeepSeek reasoning content", () => {