fix(core): ensure all model turns with function calls receive thought signatures by amelidev · Pull Request #29828 · google-gemini/gemini-cli · GitHub
Skip to content

fix(core): ensure all model turns with function calls receive thought signatures - #29828

Merged
DavidAPierce merged 7 commits into
google-gemini:mainfrom
amelidev:b_545909551
Oct 22, 2026
Merged

DavidAPierce merged 7 commits into
google-gemini:mainfrom
amelidev:b_545909551

Conversation

@amelidev

@amelidev amelidev commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes an issue where multi-turn agent conversations fail with HTTP 400 Bad Request (Function call is missing a thought_signature in functionCall parts) when historical model tool calls precede subsequent user prompts.

Details

Root Cause

In GeminiChat.ensureActiveLoopHasThoughtSignatures, thought signature enforcement was only applied to turns beginning at activeLoopStartIndex (the most recent user text prompt). Any historical model turn containing a function call prior to activeLoopStartIndex (such as a tool invoked earlier in a coding session, e.g. at position 58) was forwarded to the Gemini API without a thoughtSignature.

The Gemini API requires that every model turn containing function calls in the contents history payload must have a thought_signature on its first functionCall part. Consequently, once a session progressed past the initial tool turn, the Gemini API rejected the subsequent request with HTTP 400 INVALID_ARGUMENT.

Fix

  • Updated ensureActiveLoopHasThoughtSignatures in packages/core/src/core/geminiChat.ts to iterate across all model turns in requestContents rather than restricting to activeLoopStartIndex.
  • Guaranteed that the first functionCall part of every model turn in history has a thoughtSignature (SYNTHETIC_THOUGHT_SIGNATURE if not already present).
  • Preserved existing valid signatures and left parallel function calls (after the first in a turn) unsigned per Gemini API specifications.
  • Updated and added regression test coverage in packages/core/src/core/geminiChat.test.ts.

How to Validate

  1. Run the targeted unit and regression tests in @google/gemini-cli-core:

    npm test -w @google/gemini-cli-core -- src/core/geminiChat.test.ts

    Expected result: All 134 tests pass.

  2. Run a2a-server test suite:

    npm test -w @google/gemini-cli-a2a-server

    Expected result: All 16 test files pass (177 tests).

  3. Run workspace typecheck and linter:

    npm run typecheck
    npm run lint

    Expected result: 0 errors, 0 warnings.

  4. Manual verification across 8 cases:

    • Case 1: Standard Active Loop Tool Call — Verified first function call is signed.
    • Case 2: Multi-Turn Historical Tool Call — Verified historical Turn 1 and active Turn 5 both signed.
    • Case 3: Parallel Tool Calls — Verified first function call signed, subsequent calls unsigned.
    • Case 4: Existing Real Signature Preservation — Verified real encrypted signatures are preserved.
    • Case 5: History Without User Text — Verified model function call is signed.
    • Case 6: Deep Turn 58 Reproduction — Verified position 58 function call is signed.
    • Case 7: Text-Only and Empty Turns — Verified no spurious fields added.
    • Case 8: User Turns — Verified user parts remain unaffected.

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

@amelidev
amelidev requested a review from a team as a code owner October 19, 2026 15:15
@gemini-code-assist

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot added the size/m A medium sized PR label Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 189
  • Additions: +147
  • Deletions: -42
  • Files changed: 2

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates ensureActiveLoopHasThoughtSignatures in GeminiChat to apply thoughtSignature (using SYNTHETIC_THOUGHT_SIGNATURE) to the first function call of every model turn across the entire conversation history, rather than limiting it to the active loop. This prevents 400 Bad Request errors from the Gemini API, which validates all historical function calls. Corresponding unit tests and reproduction test cases have been updated and added to verify this behavior. I have no further feedback to provide as the changes are clean and well-tested.

@amelidev

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates ensureActiveLoopHasThoughtSignatures in geminiChat.ts to ensure that the first function call in every model turn across the entire conversation history has a thoughtSignature property, resolving potential 400 Bad Request errors from the Gemini API. It also adds comprehensive unit and reproduction tests to verify this behavior. The review feedback recommends defining a local interface for the undocumented thoughtSignature property and adding a detailed comment explaining the rationale for using this internal SDK property to maintain type safety and document the workaround.

Comment thread packages/core/src/core/geminiChat.ts Outdated
@amelidev

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the ensureActiveLoopHasThoughtSignatures method in GeminiChat to apply a synthetic thoughtSignature to the first function call of all model turns across the entire conversation history, rather than restricting it to the active loop, preventing 400 Bad Request errors from the Gemini API. Corresponding unit and reproduction tests have been updated and added. The review feedback correctly identifies a performance optimization opportunity to avoid redundant array and object allocations by lazily copying the history and parts arrays only when modifications are actually required.

Comment thread packages/core/src/core/geminiChat.ts Outdated
@amelidev

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates ensureActiveLoopHasThoughtSignatures in geminiChat.ts to ensure that the first function call in every model turn across the entire conversation history has a thoughtSignature property, preventing 400 Bad Request errors from the Gemini API. It also optimizes the method to lazily clone arrays only when modifications are needed, and adds comprehensive unit tests to verify this behavior. The feedback suggests defensively checking if part is defined before accessing its properties to prevent potential runtime TypeError crashes.

Comment thread packages/core/src/core/geminiChat.ts Outdated
@amelidev

Copy link
Copy Markdown
Contributor Author

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the ensureActiveLoopHasThoughtSignatures method in GeminiChat to apply synthetic thought signatures to the first function call of every model turn across the entire conversation history, rather than limiting it to the active loop. This change prevents HTTP 400 Bad Request errors from the Gemini API, which validates all historical function calls. Additionally, the implementation has been optimized to lazily clone the history array only when modifications are necessary, returning the original reference otherwise. Comprehensive unit tests and reproduction cases have been added to verify this behavior. There are no review comments to address, and the changes look solid.

@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Oct 20, 2026
auto-merge was automatically disabled October 22, 2026 17:22

Head branch was pushed to by a user without write access

@DavidAPierce
DavidAPierce added this pull request to the merge queue Oct 22, 2026
Merged via the queue into google-gemini:main with commit c690b9d Oct 22, 2026
42 of 51 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m A medium sized PR status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants