Repository navigation
fix(mcp): persist and re-attach Gemini thoughtSignature on the direct Claude<->Gemini path - #9448
Merged
diegosouzapw merged 4 commits intoAug 13, 2026
Conversation
… Claude<->Gemini path The direct Claude<->Gemini translator (claude-to-gemini.ts / gemini-to-claude.ts) never persisted the thoughtSignature Gemini returns on functionCall parts, and never re-attached one on the next turn. Gemini 3+/2.5 strictly reject a native functionCall part with no signature (400), which surfaces whenever a combo falls back onto a Gemini model mid-conversation (the fallback tool_use never went through Gemini, so no signature exists for it). - gemini-to-claude.ts: store the signature (keyed by tool_use id + connection namespace) when Gemini's response carries one, mirroring the existing gemini-to-openai.ts hub-path behavior. - claude-to-gemini.ts: resolve a stored signature for historical tool_use blocks; when none exists and the target model requires one, downgrade the tool_use/tool_result pair to inert text instead of sending a signature-less native part, matching the "context" fallback already used by the OpenAI hub path (diegosouzapw#3358) rather than the removed fake-signature injection.
Owner
Review: PR #9448 — fix(mcp): persist Gemini thoughtSignature on direct Claude<->Gemini pathVerdict: merge-ready (5/5 stars) Correctly persists and re-attaches Gemini thoughtSignature. Matches existing hub-path behavior. Tests included. Ready to merge after retarget/rebase to release/v3.8.50 tip. |
The direct Claude<->Gemini thoughtSignature persist/re-attach fix this PR introduced (open-sse/translator/request/claude-to-gemini.ts, open-sse/translator/response/gemini-to-claude.ts) was independently superseded on release/v3.8.50 by a more complete implementation covering the same root cause (diegosouzapw#2504, diegosouzapw#3440) plus related fixes (diegosouzapw#9568 tool-name casing, standalone thoughtSignature parts, first-call-only signature embedding). Conflicts resolved by taking the release implementation and its test coverage, which already delivers this PR's stated goal. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Owner
|
Merged into |
This was referenced Aug 13, 2026
Merged
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
… Claude<->Gemini path (diegosouzapw#9448) The direct Claude<->Gemini translator (claude-to-gemini.ts / gemini-to-claude.ts) never persisted the thoughtSignature Gemini returns on functionCall parts, and never re-attached one on the next turn. Gemini 3+/2.5 strictly reject a native functionCall part with no signature (400), which surfaces whenever a combo falls back onto a Gemini model mid-conversation (the fallback tool_use never went through Gemini, so no signature exists for it). - gemini-to-claude.ts: store the signature (keyed by tool_use id + connection namespace) when Gemini's response carries one, mirroring the existing gemini-to-openai.ts hub-path behavior. - claude-to-gemini.ts: resolve a stored signature for historical tool_use blocks; when none exists and the target model requires one, downgrade the tool_use/tool_result pair to inert text instead of sending a signature-less native part, matching the "context" fallback already used by the OpenAI hub path (diegosouzapw#3358) rather than the removed fake-signature injection. Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
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.
Summary
claude-to-gemini.ts/gemini-to-claude.ts) never persisted thethoughtSignatureGemini returns onfunctionCallparts, and never re-attached one on the next turn.functionCallpart with no signature (400). This surfaces in practice whenever a fallback combo lands on a Gemini model mid-conversation — the priortool_usenever went through Gemini, so no real signature was ever stored for it.gemini-to-claude.tsnow stores the signature (keyed by tool_use id + connection namespace) when Gemini's response carries one, mirroring the existinggemini-to-openai.tshub-path behavior.claude-to-gemini.tsnow resolves a stored signature for historicaltool_useblocks; when none exists and the target model requires one, thetool_use/tool_resultpair is downgraded to inert text instead of being sent as a signature-less native part — matching the"context"fallback the OpenAI hub path already uses for the same situation (fix(gemini): resolve truncation/suppression of false positive textual tool call markers in backticks #3358), rather than the removed fake-signature injection this file's dead code comment referenced.Test plan
node --import tsx/esm --test tests/unit/translator-claude-to-gemini.test.ts— updated the two pre-existing tests that relied on the old (buggy) signature-less passthrough to prime a real stored signature, added a regression test reproducing the exact 400 (signature-lesstool_use/tool_resultpair is downgraded to inert text on a thinking-capable model), and a test locking in that older non-thinking models are unaffected.node --import tsx/esm --test tests/unit/translator-resp-gemini-to-claude.test.ts— added a test asserting the signature from a standalonethoughtSignaturepart is persisted and retrievable viagetGeminiThoughtSignature.node --import tsx/esm --test tests/unit/vertex-functioncall-id-3440.test.ts— updated the one affected pre-existing test (primed a signature; unrelated to what it actually tests).npm run lintclean on all touched files (test-fileanyusage stayed within the frozen per-file budget).npx tsc --noEmitclean on all touched files.