Skip to content

fix(adk-middleware): map oneOf → anyOf so genai keeps discriminated-union tool params#2027

Open
jplikesbikes wants to merge 1 commit into
ag-ui-protocol:mainfrom
jplikesbikes:fix/clean-schema-oneof-to-anyof
Open

fix(adk-middleware): map oneOf → anyOf so genai keeps discriminated-union tool params#2027
jplikesbikes wants to merge 1 commit into
ag-ui-protocol:mainfrom
jplikesbikes:fix/clean-schema-oneof-to-anyof

Conversation

@jplikesbikes

Copy link
Copy Markdown
Contributor

Fix: map oneOf → anyOf in ADK middleware schema cleaner

Problem

google.genai's types.Schema accepts anyOf but not oneOf. The ADK middleware's _clean_schema_for_genai filters tool-parameter schemas through an allowlist derived from types.Schema.model_fields, so any oneOf key was silently dropped.

This erases the structure of discriminated unions. CopilotKit / AG-UI frontend tools serialize a zod discriminatedUnion to oneOf (via zod-to-json-schema), so any frontend tool with such a parameter reached Gemini as a bare {description} object with no fields — and the model would just invent a shape.

Fix

Map oneOfanyOf recursively (cleaning each branch), alongside the existing examplesexample and constenum mappings. For tool-argument schemas the oneOf/anyOf distinction is immaterial: the model emits exactly one branch either way.

This mirrors prior Gemini-compat fixes — #1919 (additionalProperties) and #1664 (nested required).

Changes

  • client_proxy_tool.py: add the oneOfanyOf mapping in _clean_schema_for_genai.
  • test_client_proxy_tool.py: add tests covering a flat oneOf mapping and a nested discriminated-union schema where each branch is recursively cleaned ($-keys / rejected keys stripped, constenum) and the sibling description is preserved.

@jplikesbikes
jplikesbikes requested a review from a team as a code owner June 23, 2026 16:23
@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

@jplikesbikes is attempting to deploy a commit to the CopilotKit Team on Vercel.

A member of the Team first needs to authorize it.

@jplikesbikes

Copy link
Copy Markdown
Contributor Author

@contextablemark Just wanted to bring this to your attention no rush

@jplikesbikes
jplikesbikes force-pushed the fix/clean-schema-oneof-to-anyof branch from 68fb604 to eb1b185 Compare July 6, 2026 17:11
@jplikesbikes

Copy link
Copy Markdown
Contributor Author

@contextablemark friendly reminder

google.genai's Schema accepts `anyOf` but not `oneOf`, so the schema
cleaner's allowlist silently dropped `oneOf` — erasing the structure of
discriminated unions. CopilotKit / AG-UI frontend tools serialize a zod
`discriminatedUnion` to `oneOf` via zod-to-json-schema, so any frontend
tool with such a parameter reached Gemini as a bare `{description}` object
with no fields, and the model would invent a shape.

Map `oneOf` -> `anyOf` (recursively, cleaning each branch) alongside the
existing `examples`/`const` mappings. For tool-argument schemas the
distinction is immaterial — the model emits exactly one branch either way.

Mirrors the prior Gemini-compat fixes (ag-ui-protocol#1919 additionalProperties, ag-ui-protocol#1664
nested required).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jplikesbikes
jplikesbikes force-pushed the fix/clean-schema-oneof-to-anyof branch from eb1b185 to b7e1eec Compare July 16, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant