Skip to content

OpenAI-completions tools lose root type object when parameters use oneOf/anyOf (Console Go 400) #710

Description

@wingwogus

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

  1. Use the ast-grep MCP scan tool, whose parameters schema is type: "object" plus a oneOf (ruleFile XOR inlineRules) contract.
  2. Start a chat with any opencode-go model (for example deepseek-v4-flash).
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions