Skip to content

AI Gateway chat-completions forwards OpenAI-format tool-schema extras ($schema, exclusiveMinimum, stream_options) into Gemini's native API — 400s ALL Gemini models for OpenCode agents #491

Description

@bradaffleck-75

Summary

The AI Gateway's Gemini translation layer on the standard serving-endpoints chat-completions surface (POST {host}/serving-endpoints/<gemini-model>/invocations, OpenAI wire format) forwards unknown OpenAI-format fields verbatim into Gemini's native API, which rejects them with a hard 400:

Invalid JSON payload received. Unknown name "$schema" at 'tools[0].function_declarations[N].parameters': Cannot find field.
Invalid JSON payload received. Unknown name "exclusiveMinimum" at 'tools[0].function_declarations[N].parameters.properties[1].value': Cannot find field.
Invalid JSON payload received. Unknown name "stream_options" at 'generation_config': Cannot find field.

Any OpenAI-compatible client whose tool JSON-Schemas carry standard JSON-Schema 2020-12 keywords, or that requests usage via stream_options, gets rejected. This makes every Gemini model unusable for tool-carrying agents on this surface. OpenCode (1.18.x) emits all three on every turn, so OpenCode + Gemini is 100% broken.

Verified identical on databricks-gemini-3-7-flash and databricks-gemini-3-8-flash — this is the translation layer, not a model regression.

Environment

  • Workspace: dbc-0927d274-c1a8.cloud.databricks.com (ws 2502993781179439)
  • Models: databricks-gemini-3-7-flash, databricks-gemini-3-8-flash (AI Gateway foundation models)
  • Date: 2026-09-03

Reproduction (3 minimal requests, same token, same model)

1. Clean tools → 200 (the surface itself works fine):

POST /serving-endpoints/databricks-gemini-3-8-flash/invocations
{"messages":[{"role":"user","content":"Say OK"}],
 "tools":[{"type":"function","function":{"name":"read","description":"Read a file",
   "parameters":{"type":"object","properties":{"path":{"type":"string"}},"required":["path"]}}}]}

HTTP 200

2. Same request, parameters gain two bog-standard JSON-Schema fields → 400:

"parameters": {
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {"path": {"type": "string"},
                 "limit": {"type": "number", "exclusiveMinimum": 0}},
  "required": ["path"]
}

HTTP 400Unknown name "$schema" at 'tools[0].function_declarations[0].parameters' (plus the exclusiveMinimum violation)

3. No tools at all, just stream_options → 400:

{"messages":[{"role":"user","content":"Say OK"}], "stream_options": {"include_usage": true}}

HTTP 400Unknown name "stream_options" at 'generation_config'

So each of $schema, exclusiveMinimum, and stream_options independently 400s, while identical payloads without them succeed — including image_url vision content (Gemini vision itself is fine on this surface).

Production evidence

A real OpenCode-native session turn failed with the full 40-tool payload (excerpts above). The response carried:

  • request_id: fbf02b36-8824-49df-848f-07b18751a2e6
  • x-databricks-response-source: CallerError
  • "via": "1.1 google" — the request is translated and forwarded to Google's API, which rejects the unknown keys

Expected behavior

The Gemini translation layer should sanitize OpenAI-compat payloads before mapping to Gemini's native schema, the way mature OpenAI-compatibility layers do:

  • strip $schema (and other meta-keywords) from tool parameter schemas
  • map or strip validation keywords Gemini's Schema proto doesn't model (exclusiveMinimum/exclusiveMaximum, and similar) rather than rejecting the whole request
  • map or drop stream_options (e.g., honor usage reporting natively, or ignore it) instead of failing the request

Workaround status / impact

  • No other gateway surface serves Gemini: the Responses surface (/ai-gateway/openai/v1/responses) returns "Responses API passthrough is not supported for model databricks-gemini-3-8-flash." — OpenAI-family only. The Anthropic surface doesn't serve Gemini either. So there is no harness path to Gemini with tools today (OpenCode → this surface; openai-agents/codex → Responses; pi → same chat-completions surface).
  • We moved our vision-review tier from Gemini Flash to Claude Sonnet 5 to keep it alive; we'd move it back the moment the translation sanitizes these fields.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions