-
Notifications
You must be signed in to change notification settings - Fork 813
fix(google): carry Gemini thought signatures through the Responses round trip #1781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
devlog/_plan/260815_roadmap_closeout/050_gemini_thought_signature.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # 050 — Gemini thought signature survives the Responses round trip (#1735) | ||
|
|
||
| ## Problem | ||
|
|
||
| Gemini issues a `thoughtSignature` on the exact part that carries a function call, and the next | ||
| request is only valid when that signature returns on the part rebuilt from that same call. | ||
|
|
||
| Today the signature is observed on the response and then lost: the adapter event carries only | ||
| `id`/`name`, the Responses `function_call` item has nowhere to put it, and the parser rebuilds an | ||
| `OcxToolCall` without it. A same-process replay cache hides this for streaming turns, which is why | ||
| the bug reads as intermittent — history replay and `previous_response_id` have no cache to fall | ||
| back on. | ||
|
|
||
| PR #1772 repaired one web-search reconstruction. The roadmap's own instruction is that a | ||
| web-search-only patch is not acceptable, because every other tool loop rebuilds calls the same way. | ||
|
|
||
| ## Approach | ||
|
|
||
| Carry the metadata with the individual tool call, at every hop it already travels: | ||
|
|
||
| 1. `OcxProviderOpaqueToolCallMetadata` on `OcxToolCall` and on `tool_call_start`. | ||
| 2. `src/responses/provider-opaque-metadata.ts` — the single seam that reads and writes the wire | ||
| shape `extra_content.google.thought_signature`. | ||
| 3. Google adapter attaches metadata from the originating part (streaming and buffered), and on | ||
| the outbound side prefers it over the legacy field. | ||
| 4. Responses schema models the bounded nested shape; parser reads it back. | ||
| 5. Bridge emits it on the `function_call` item so a client can round-trip it. | ||
|
|
||
| Values are opaque: never parsed, merged, re-encoded, or synthesized. One upstream part maps to one | ||
| event, one Responses item, one internal call, one rebuilt part. | ||
|
|
||
| ## Deliberately out of scope for this cycle | ||
|
|
||
| The audit also found two adjacent defects that are **not** #1735 and must not ride along: | ||
|
|
||
| - Google-issued `functionCall.id` is discarded and replaced with a synthetic `call_*`. The | ||
| generated call/response ids still match each other, so pairing works; preserving Google's exact | ||
| id is a separate contract change with its own blast radius. | ||
| - `src/web-search/loop.ts` interleaves parallel calls as `FC1, FR1, FC2, FR2` where Google requires | ||
| `FC1, FC2, FR1, FR2`. That is a message-ordering fix in the sidecar loop, independent of whether | ||
| a signature is carried. | ||
|
|
||
| Both are recorded here so the next cycle can pick them up deliberately rather than by accident. | ||
|
|
||
| ## Acceptance | ||
|
|
||
| A signature observed on a Google function-call part is present on the Responses `function_call` | ||
| item, survives parsing back into the tool call, and is re-attached to the rebuilt part — with no | ||
| dependency on the replay cache. Legacy callers that still set `thoughtSignature` keep working. |
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
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When Gemini invokes a declared custom tool such as
apply_patch, or the client-sidetool_searchtool, the bridge selects one of the preceding branches, so this metadata spread never runs; the buffered path has the same omission. These tools are exposed to Gemini as function declarations and their calls can therefore carry a requiredthoughtSignature, but the resultingcustom_tool_call/tool_search_callitem and parser discard it. A direct-Gemini follow-up or cold history replay consequently sends the call back unsigned and can be rejected upstream. Attach the bounded metadata to these item variants as well and restore it when parsing them intoOcxToolCall.AGENTS.md reference: src/AGENTS.md:L19-L19
Useful? React with 👍 / 👎.