Summary
Function tools whose parameters schema uses a combiner (anyOf / oneOf / allOf) are sent to OpenAI-compatible backends without the root type: "object" marker. normalizeToolParametersForOpenAICompat moves the root type into combiner branches and then deletes it (moveTypeIntoCombinerBranches in packages/ai/src/utils/tool-schema-compat.ts).
Gateways backed by Gemini-style validation (e.g. OpenCode Go / Zen proxying to Console) reject the first request:
Error: 400: {"param":null,"type":"invalid_request_error","code":"invalid_request_error","message":"Error from provider (Console Go): Upstream request failed: [invalid_request_error] Invalid schema for function 'mcp__ast_grep_scan': schema must be a JSON Schema of 'type: \"object\"', got 'type: null'."}
Reproduction
- Use the ast-grep MCP
scan tool, whose parameters schema is type: "object" plus a oneOf (ruleFile XOR inlineRules) contract.
- Start a chat with any
opencode-go model (for example deepseek-v4-flash).
- The first request fails with the 400 above.
Verified locally: normalizeToolParametersForOpenAICompat(scanSchema) drops the top-level type, while search / rewrite (no combiner) keep it.
Root cause
moveTypeIntoCombinerBranches deletes the parent type for every combiner schema. That behavior exists for Moonshot-flavored backends (Apitopia → Kimi / Moonshot), but OpenAI Chat Completions requires every function's parameters root to be a JSON Schema of type: "object", and the Gemini-backed Console gateways enforce the same.
Suggested fix
Restore the root type: "object" marker at the OpenAI-completions wire boundary (convertTools and normalizeRequestToolSchemas) instead of changing the Moonshot-flavored normalizer behavior. A PR with tests for both conversion paths is attached.
Summary
Function tools whose
parametersschema uses a combiner (anyOf/oneOf/allOf) are sent to OpenAI-compatible backends without the roottype: "object"marker.normalizeToolParametersForOpenAICompatmoves the roottypeinto combiner branches and then deletes it (moveTypeIntoCombinerBranchesinpackages/ai/src/utils/tool-schema-compat.ts).Gateways backed by Gemini-style validation (e.g. OpenCode Go / Zen proxying to Console) reject the first request:
Reproduction
scantool, whose parameters schema istype: "object"plus aoneOf(ruleFile XOR inlineRules) contract.opencode-gomodel (for exampledeepseek-v4-flash).Verified locally:
normalizeToolParametersForOpenAICompat(scanSchema)drops the top-leveltype, whilesearch/rewrite(no combiner) keep it.Root cause
moveTypeIntoCombinerBranchesdeletes the parenttypefor every combiner schema. That behavior exists for Moonshot-flavored backends (Apitopia → Kimi / Moonshot), but OpenAI Chat Completions requires every function'sparametersroot to be a JSON Schema oftype: "object", and the Gemini-backed Console gateways enforce the same.Suggested fix
Restore the root
type: "object"marker at the OpenAI-completions wire boundary (convertToolsandnormalizeRequestToolSchemas) instead of changing the Moonshot-flavored normalizer behavior. A PR with tests for both conversion paths is attached.