From 395b477289da1c1b3257edbd0b8a5bc8551f8846 Mon Sep 17 00:00:00 2001 From: ViNull008 Date: Mon, 6 Jul 2026 16:38:50 +0800 Subject: [PATCH] fix(provider): ensure required array is present in object schemas Strict JSON Schema validators (e.g. ajv in strict mode, used by some OpenAI-compatible API gateways/proxies) reject tool schemas where additionalProperties: false is set but required is missing or null. Several built-in tools (list_mcp_resources, list_mcp_resource_templates, and others) define inputSchema with additionalProperties: false but without a required field. When serialized and sent to the model, the missing required becomes null, which strict validators reject with: Invalid schema for function 'X': null is not of type "array" Fix: normalize all object schemas in ProviderTransform.schema() to include an explicit (possibly empty) required array when properties is present. Also add required: [] directly to the two MCP resource tools as a defensive measure. required: [] means no fields are required, semantically identical to omitting required. Lenient validators (OpenAI, Anthropic, official DeepSeek API) ignore it; strict validators now see a valid array. --- packages/opencode/src/provider/transform.ts | 9 +++++++++ packages/opencode/src/session/tools.ts | 2 ++ 2 files changed, 11 insertions(+) diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index f42e14139f1e..3a5562884d91 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -1432,6 +1432,15 @@ export function schema(model: Provider.Model, schema: JSONSchema7): JSONSchema7 } */ + // Ensure `required` is always an array when `properties` is present. + // Strict JSON Schema validators (e.g. ajv used by some API gateways/proxies) + // reject schemas where `additionalProperties: false` is set but `required` + // is missing or null. This normalizes all object schemas to include an + // explicit (possibly empty) `required` array. + if (schema.type === "object" && schema.properties && !Array.isArray(schema.required)) { + schema.required = [] + } + if (model.api.npm === "@ai-sdk/openai" || model.api.npm === "@ai-sdk/azure") { schema = sanitizeOpenAISchema(schema) as JSONSchema7 // Codex also applies lossy compaction above 4 KB; defer that until OpenCode needs the same schema budget. diff --git a/packages/opencode/src/session/tools.ts b/packages/opencode/src/session/tools.ts index 0f401c7562fa..59c7ad6cd020 100644 --- a/packages/opencode/src/session/tools.ts +++ b/packages/opencode/src/session/tools.ts @@ -150,6 +150,7 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: { }, }, additionalProperties: false, + required: [], }), ), execute(args, opts) { @@ -233,6 +234,7 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: { }, }, additionalProperties: false, + required: [], }), ), execute(args, opts) {