fix(gemini-translator): sanitize stale required entries in OpenAI tool schemas#3864
Conversation
…l schemas
The OpenAI -> Gemini translator renamed tools[].function.parameters to
parametersJsonSchema but never ran it through CleanJSONSchemaForGemini.
When the OpenAI tool schema declared a 'required' entry that did not
match a key in 'properties' (a common pattern for clients that build
schemas from Pydantic/Zod-style models), the renamed payload reached
Gemini unchanged. Gemini API strictly validates that every name in
required exists in properties, so the request was rejected with:
AI_APICallError: GenerateContentRequest.tools[0]
.function_declarations[N].parameters.required[M]:
property is not defined
Apply util.CleanJSONSchemaForGemini (which already runs
cleanupRequiredFields, removes unsupported keywords, flattens
anyOf/oneOf/allOf, and normalizes enums) to the renamed
parametersJsonSchema in both the chat-completions and responses
OpenAI->Gemini translators. Add regression tests that pin down the
new behaviour for stale, all-stale, and valid required arrays.
|
This pull request targeted The base branch has been automatically changed to |
There was a problem hiding this comment.
Code Review
This pull request introduces JSON schema sanitization for Gemini API compatibility in both the chat-completions and responses translators, resolving API errors caused by stale required fields. Unit tests are also added to verify the sanitization logic. The review feedback suggests optimizing this process by sanitizing only the nested parameters schema directly rather than the entire function declaration, which reduces performance overhead and avoids potential side effects on non-schema fields.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…onses_request.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…ai_request.go Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Summary
Fix
AI_APICallError: GenerateContentRequest.tools[0].function_declarations[N].parameters.required[M]: property is not definedraised by Gemini API when an OpenAI Chat Completions / Responses tool declaresrequiredentries that are missing fromproperties.The OpenAI → Gemini translator renamed
tools[].function.parameterstoparametersJsonSchemabut never ran the renamed payload throughutil.CleanJSONSchemaForGemini. Other translators (claude→gemini, antigravity→gemini) already do so for the same reason. Without that sanitization,cleanupRequiredFieldsis skipped and every stalerequiredname is forwarded to Gemini, which then rejects the request with the API error above.Changes
internal/translator/gemini/openai/chat-completions/gemini_openai_request.goAfter renaming
parameters→parametersJsonSchema, run the renamed value throughutil.CleanJSONSchemaForGemini. This callscleanupRequiredFields(which intersectsrequiredwithproperties, removing any name that does not have a corresponding property) and also flattens anyOf/oneOf/allOf, removes unsupported keywords, normalizes enums, and strips x-* extension fields — all of which Gemini API rejects.internal/translator/gemini/openai/responses/gemini_openai-responses_request.goSame fix for the OpenAI Responses translator.
Tests
New regression tests in:
internal/translator/gemini/openai/chat-completions/gemini_openai_request_sanitize_test.goTestConvertOpenAIRequestToGemini_SanitizesStaleRequiredEntries— pins down the original bug.TestConvertOpenAIRequestToGemini_DropsEmptyRequiredArray— confirms the all-stale case is fully removed.TestConvertOpenAIRequestToGemini_AllRequiredValidPassesThrough— guards against regressions in the happy path.internal/translator/gemini/openai/responses/gemini_openai-responses_request_sanitize_test.goTestConvertOpenAIResponsesRequestToGemini_SanitizesStaleRequiredEntries— same coverage for the responses translator.All tests in the touched packages pass,
gofmtis clean, andgo build -o test-output ./cmd/server && rm test-output(the AGENTS.md compile guard) succeeds.Fixes #3863