Gemini 3 models attach a thought signature to every function call and reject the follow-up -- 400, "Function call is missing a thought_signature in functionCall parts" -- when the assistant message echoing that call does not carry it back. The gateway rebuilt the assistant turn from id, name and arguments alone, so every tool-using run on Gemini died on its second model call, after a first call that looked perfectly healthy. Found when production was pointed at Gemini on 2026-09-22; rolled back to Groq within minutes. ToolCall gains an opaque Extra field: the raw JSON of the wire's extra_content, captured on both the streaming and non-streaming paths and emitted verbatim on the next request. The gateway does not read it and must not -- the point of one wire shape is that a vendor's private fields pass through untouched. Absent stays absent; no provider receives a null it never sent. Also: Gemini wraps its error body in a one-element array, which the message parser read as "no detail". The trajectory therefore said only "the model rejected the request" where the body named the missing signature outright. Unwrapped now, so the next provider quirk is legible in the trajectory instead of costing a day of proxy captures. Verified end to end with the real gateway against real Gemini: a three-turn tool-calling run completed and the proxy confirmed the signature on every echoed call. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJvibeSc1JYXjatankqM1g
16 KiB
16 KiB