Repository navigation
Conversation
jerelvelarde
left a comment
There was a problem hiding this comment.
This addresses a real Gemini tool-loop incompatibility and fits the existing provider adapter, but hold merge for two signature-preservation failures reproduced through the installed adapter and DotAgent. All 21 focused compatibility/agent/channel tests pass. Synthetic fragmented-stream and repeated-ID fixtures reproduce the findings; no live Google API calls were used. The official contract requires preserving received signatures: https://ai.google.dev/gemini-api/docs/generate-content/thought-signatures
| for (const call of calls) { | ||
| const id = field(call, 'id'); | ||
| const signature = signatureOf(call); | ||
| if (typeof id !== 'string' || !id || !signature) continue; |
There was a problem hiding this comment.
[P2] Assemble streamed tool-call deltas before associating the signature with an ID. This skips a signature when its delta omits the ID, even though an earlier delta for the same choice/tool-call index supplied it. An actual-adapter fixture emitting ID/name first and arguments/signature later sends the placeholder on continuation instead of the received signature. Track the deltas by choice and tool-call index and add a fragmented-SSE regression.
There was a problem hiding this comment.
Both points from the review are fixed in the latest push, with regression tests for each. I also squashed the history to two commits. Could you re-review, and approve the CI run when you get a chance? @jerelvelarde
Gemini 3 models reached through Google's OpenAI-compatible endpoint
return a thought signature on each tool call and reject the follow-up
request with HTTP 400 ("Function call is missing a thought_signature")
when it is not sent back. The chat-completions adapter drops
extra_content, so every turn that used a tool ended without a response.
Wrap fetch for Google endpoints so signatures seen in responses are
restored on the matching tool calls of later requests. Signatures are
cached per provider, model and thread, keyed by tool-call ID and matched
on arguments when an ID is reused. Streamed deltas are assembled per
choice and tool-call index before the signature is attached. Tool calls
that were never seen (for example history reloaded after a restart) get
Google's documented placeholder.
78d6e6c to
14cdf31
Compare
|
Both points from the review are fixed in the latest push, with regression tests for each. I also squashed the history to two commits. Could you re-review, and approve the CI run when you get a chance? @jerelvelarde |
Gemini 3 through Google's OpenAI-compatible endpoint fails on every tool-calling turn. Google returns a thought signature on each tool call (
tool_calls[].extra_content.google.thought_signature) and answers the next request with400 Function call is missing a thought_signatureunless it is sent back. The chat-completions adapter dropsextra_content, so the chat ends with "The current turn returned no response".Direct calls to the endpoint confirm it: replaying the tool call without the signature gives 400; with the returned signature or the documented placeholder
skip_thought_signature_validatorit gives 200.Change
src/server/gemini-compat.ts: afetchwrapper that remembers signatures from responses (by tool call id) and restores them on later requests, using the placeholder for tool calls it has not seen (e.g. history after a restart).src/server/dot-agent.ts: uses it only when the base URL host isgenerativelanguage.googleapis.com; other providers are unchanged.docs/SETUP.md: one paragraph.Tests: wrapper unit tests, plus a full tool-call round trip through
DotAgentagainst a Google base URL (and a check that other providers get no Gemini fields).check-format,lint,typecheck,test(261) andbuildpass on Node 24. Reproduced on a build at c2569bb; the patch is based on main at 565bf78.