[PR #12911] fix(provider): handle anyOf/oneOf/const/$ref in Gemini schema sanitization #14433

Open
opened 2026-02-16 18:19:13 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/12911

State: open
Merged: No


Problem

Gemini's generateContent API rejects JSON schemas containing anyOf, oneOf, const, $ref, and $defs — all valid JSON Schema but unsupported by Gemini's function calling format. This causes MCP tools from servers like Notion, Memory, and Obsidian mcp-tools to fail when used with any Gemini model.

Error example:

GenerateContentRequest.tools[0].function_declarations[32].parameters.properties[format].any_of[0].enum: only allowed for STRING type

Root Cause

The sanitizeGemini function in transform.ts handles integer→string enum conversion and a few other edge cases, but does not transform these unsupported JSON Schema patterns:

Pattern Source Example
$ref / $defs Notion MCP { "$ref": "#/$defs/richTextRequest" }
anyOf with const Obsidian mcp-tools { "anyOf": [{ "const": "markdown" }, { "const": "json" }] }
oneOf mixed types Memory MCP { "oneOf": [{ "type": "array" }, { "type": "string" }] }
oneOf multiple objects Notion MCP { "oneOf": [{ "type": "object", "properties": { "page_id": ... } }, ...] }

Solution

Two-phase transformation before existing sanitization:

  1. $ref resolution: Inline all $ref references from $defs/definitions, with circular reference detection
  2. anyOf/oneOf flattening:
    • All constenum array
    • Multiple objects → merge properties
    • Mixed types → pick first (most specific)
    • Single-item → unwrap

Testing

Tested against real MCP server schemas:

  • Notion MCP: 22/22 tools with issues fully fixed (66 anyOf/oneOf patterns resolved)
  • Memory MCP: 4 tools with oneOf tags patterns fixed
  • Obsidian mcp-tools: anyOf+const patterns fixed
  • All existing behavior preserved (enum→string, required filtering, array items)

Changes

  • packages/opencode/src/provider/transform.ts: Added resolveRefs helper and anyOf/oneOf flattening to sanitizeGemini
**Original Pull Request:** https://github.com/anomalyco/opencode/pull/12911 **State:** open **Merged:** No --- ## Problem Gemini's `generateContent` API rejects JSON schemas containing `anyOf`, `oneOf`, `const`, `$ref`, and `$defs` — all valid JSON Schema but unsupported by Gemini's function calling format. This causes MCP tools from servers like **Notion**, **Memory**, and **Obsidian mcp-tools** to fail when used with any Gemini model. Error example: ``` GenerateContentRequest.tools[0].function_declarations[32].parameters.properties[format].any_of[0].enum: only allowed for STRING type ``` ## Root Cause The `sanitizeGemini` function in `transform.ts` handles integer→string enum conversion and a few other edge cases, but does not transform these unsupported JSON Schema patterns: | Pattern | Source | Example | |---------|--------|---------| | `$ref` / `$defs` | Notion MCP | `{ "$ref": "#/$defs/richTextRequest" }` | | `anyOf` with `const` | Obsidian mcp-tools | `{ "anyOf": [{ "const": "markdown" }, { "const": "json" }] }` | | `oneOf` mixed types | Memory MCP | `{ "oneOf": [{ "type": "array" }, { "type": "string" }] }` | | `oneOf` multiple objects | Notion MCP | `{ "oneOf": [{ "type": "object", "properties": { "page_id": ... } }, ...] }` | ## Solution Two-phase transformation before existing sanitization: 1. **`$ref` resolution**: Inline all `$ref` references from `$defs`/`definitions`, with circular reference detection 2. **`anyOf`/`oneOf` flattening**: - All `const` → `enum` array - Multiple objects → merge properties - Mixed types → pick first (most specific) - Single-item → unwrap ## Testing Tested against real MCP server schemas: - **Notion MCP**: 22/22 tools with issues fully fixed (66 `anyOf`/`oneOf` patterns resolved) - **Memory MCP**: 4 tools with `oneOf` tags patterns fixed - **Obsidian mcp-tools**: `anyOf`+`const` patterns fixed - All existing behavior preserved (enum→string, required filtering, array items) ## Changes - `packages/opencode/src/provider/transform.ts`: Added `resolveRefs` helper and `anyOf`/`oneOf` flattening to `sanitizeGemini`
yindo added the pull-request label 2026-02-16 18:19:13 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#14433