fix(gemini): sanitize JSON-Schema metadata and inline $ref for Gemini (#126)#184
Open
quangdang46 wants to merge 1 commit into
Open
fix(gemini): sanitize JSON-Schema metadata and inline $ref for Gemini (#126)#184quangdang46 wants to merge 1 commit into
quangdang46 wants to merge 1 commit into
Conversation
Gemini's generateContent uses an OpenAPI 3.0 schema subset and rejects
standard JSON-Schema metadata ($defs, $ref, $schema, $id, $comment,
$anchor, title). MCP servers like notion and supabase emit schemas
that combine $defs+$ref to keep their tool surface compact, which
crashed the Gemini call when forwarded verbatim.
Replace the previous shallow gemini_compatible_schema (only mapped
const→enum) with a real sanitizer:
- Extract $defs / definitions from the root before recursion.
- For each object node:
- If it has a $ref, resolve it against the extracted defs map and
recurse on the target. Unresolvable refs degrade to a permissive
empty object.
- Otherwise, strip metadata keys Gemini doesn't accept and recurse
on each value.
- Bound recursion at depth 24 so circular schemas (head -> Loop ->
head -> …) terminate instead of overflowing the stack.
Add 4 regression tests in src/provider/gemini_tests.rs covering:
- ref inlining + metadata stripping + const→enum after inlining
- legacy 'definitions' alias
- unresolvable $ref → permissive empty object
- circular schema does not recurse forever
The skill-side hunks of upstream PR 1jehuang#162
(API name 'Skill'/'skill' → skill_manage routing + serde alias on
`name`) are NOT applied here — local code already provides both via
`canonical_tool_name` in src/tool/mod.rs:330 and #[serde(alias = "skill")]
on SkillInput.name in src/tool/skill.rs:31.
Closes #126
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Gemini's
generateContentuses an OpenAPI 3.0 schema subset and rejects standard JSON-Schema metadata ($defs,$ref,$schema,$id,$comment,$anchor,title). MCP servers like notion and supabase emit schemas that combine$defs+$refto keep their tool surface compact, which crashed the Gemini call when forwarded verbatim.This addresses issue #126: #126
Changes
gemini_compatible_schema(only mappedconst→enum) with a real sanitizer:$defs/definitionsfrom the root before recursion.$ref, resolve it against the extracted defs map and recurse on the target. Unresolvable refs degrade to a permissive empty object.gemini_schema_inlines_refs_and_strips_metadatagemini_schema_resolves_definitions_alias_toogemini_schema_falls_back_to_empty_object_on_unresolved_refgemini_schema_does_not_recurse_forever_on_cyclesTests
(The 5th is the pre-existing
build_tools_rewrites_const_for_gemini_schema_compatibility, which keeps passing because the new sanitizer preserves theconst→enummapping.)Notes / scope deviation from upstream
Upstream PR 1jehuang#162 also adds:
"Skill" | "skill" => "skill_manage"routing inRegistry::canonical_tool_name(src/tool/mod.rs)#[serde(alias = "skill")]onSkillInput::name(src/tool/skill.rs)Both are already present in this fork — the canonical-tool-name routing is at
src/tool/mod.rs:330and the serde alias is atsrc/tool/skill.rs:31. So this PR ports only the gemini schema piece, which is the genuinely new behavior for our fork.