Apply SanitizeFunctionName on request and RestoreSanitizedToolName on
response for: gemini/claude, gemini/openai/chat-completions,
gemini/openai/responses, antigravity/openai/chat-completions,
gemini-cli/openai/chat-completions.
Also update SanitizedToolNameMap to handle OpenAI format
(tools[].function.name) in addition to Claude format (tools[].name).
Claude Code and MCP clients may send tool names containing characters
invalid for Gemini's function_declarations (e.g. '/', '@', spaces).
Sanitize on request via SanitizeFunctionName and restore original names
on response for both antigravity/claude and gemini-cli/claude translators.
When Claude sends redacted thinking with empty text, the translator
was omitting the "text" field from thought parts. Google Antigravity
API requires this field, causing 500 "Unknown Error" responses.
Verified: 129/129 error logs with empty thought → 500, 0/97 success
logs had empty thought. After fix: 0 new "Unknown Error" 500s.
gjson.Parse() marks any string starting with { or [ as gjson.JSON type,
even when the content is not valid JSON (e.g. macOS plist format, truncated
tool results). This caused sjson.SetRaw to embed non-JSON content directly
into the Gemini API request payload, producing 400 errors.
Add json.Valid() check before using SetRaw to ensure only actually valid
JSON is embedded raw. Non-JSON content now falls through to sjson.Set
which properly escapes it as a JSON string.
Fixes#2161
The Claude-to-Gemini translator derived function names by splitting
tool_use_id on "-", which produced empty strings for IDs with exactly
2 segments (e.g. toolu_tool-<uuid>). Replace the string-splitting
heuristic with a lookup map built from tool_use blocks during the
main processing loop, with fallback to the raw ID on miss.
When assistant has tool_calls but no text content, the translator
emitted an empty message into the Responses API input array before
function_call items. The API then couldn't match function_call_output
to its function_call by call_id, returning:
No tool output found for function call ...
Only emit assistant messages that have content parts. Tool-call-only
messages now produce function_call items directly.
Added 9 tests for tool calling translation covering single/parallel
calls, multi-turn conversations, name shortening, empty content
edge cases, and call_id integrity.
1. Claude translator: add CleanJSONSchemaForGemini() to sanitize tool
input schemas (removes $schema, anyOf, const, format, etc.) and
delete eager_input_streaming from tool declarations. Remove fragile
bytes.Replace for format:"uri" now covered by schema cleaner.
2. Gemini native translator: filter out content entries with empty or
missing parts arrays to prevent Gemini API 400 error "required
oneof field 'data' must have one initialized field".
Both fixes align gemini-cli with protections already present in the
antigravity translator.
when Amp or Claude Code sends functionResponse with an empty name in Gemini
conversation history, the Gemini API rejects the request with 400
"Name cannot be empty". this fix backfills empty names from the
corresponding preceding functionCall parts using positional matching.
covers all three Gemini translator paths:
- gemini/gemini (direct API key)
- antigravity/gemini (OAuth)
- gemini-cli/gemini (Gemini CLI)
also switches fixCLIToolResponse pending group matching from LIFO to
FIFO to correctly handle multiple sequential tool call groups.
fixes#1903
The Gemini v1internal (cloudcode-pa) and Antigravity Manager endpoints
require camelCase "systemInstruction" in request JSON. The current
snake_case "system_instruction" causes system prompts to be silently
ignored when routing through these endpoints.
Replace all "system_instruction" JSON keys with "systemInstruction" in
chat-completions and responses request translators.
test(translator): add unit tests for OpenAI to Claude requests and tool result handling
- Introduced tests for converting OpenAI requests to Claude with text, base64 images, and URL images in tool results.
- Refactored `convertClaudeToolResultContent` and related functionality to properly handle raw content with images and text.
- Updated conversion logic to streamline image handling for both base64 and URL formats.
Add util.SanitizeClaudeToolID() to replace non-conforming characters in
tool_use.id fields across all five response translators (gemini, codex,
openai, antigravity, gemini-cli).
Upstream tool names may contain dots or other special characters
(e.g. "fs.readFile") that violate Claude's ID validation regex.
The sanitizer replaces such characters with underscores and provides
a generated fallback for empty IDs.
Fixes#1872, Fixes#1849
Made-with: Cursor