fix(core): skip merged function-response turns when finding the active loop - #28565
Conversation
…e loop
`ensureActiveLoopHasThoughtSignatures` located the start of the active
loop by looking for the last user turn containing text. Its comment
already described the correct rule ("i.e. that is not a function
response"), but the code never checked for one, which was equivalent
only while a user turn was either pure text or pure function response.
`coalesceConsecutiveRoles` merges adjacent same-role turns, so a function
response turn can now be merged with the prompt that follows it. Starting
the loop at such a turn starts it later than the API starts the turn, so
model turns in between are validated by the API but never get a synthetic
signature, and the request is rejected.
Tool calls made just before the merged turn are the ones affected; skill
activation hits this on every use because its call is client-generated
and carries no signature of its own.
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a regression where the active loop detection logic was incorrectly identifying the start of a loop when user turns were merged with function responses. By explicitly filtering out turns containing function responses, the fix ensures that synthetic thought signatures are correctly applied to all necessary model turns, preventing API validation errors. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
📊 PR Size: size/S
|
There was a problem hiding this comment.
Code Review
This pull request updates the active loop detection logic in GeminiChat to skip user turns that contain both text and a functionResponse (which can occur when consecutive roles are coalesced). This prevents earlier model turns from being left unsigned while still validated by the API. A corresponding unit test has been added to verify this behavior. I have no feedback to provide as the changes are correct and well-tested.
|
Size Change: +53 B (0%) Total Size: 35.2 MB
ℹ️ View Unchanged
|
Summary
Tool calls can be sent to the API without a thought signature, which the API
rejects with
400 INVALID_ARGUMENT. The bad turn stays in history, so once ithappens the session cannot recover. Skill activation triggers it on every use,
because that call is generated client-side and carries no signature of its own.
Regression from #28407, first shipped in
v0.52.0-nightly.20260716. Not inv0.51.0.Details
ensureActiveLoopHasThoughtSignaturesfinds the start of the active loop bylooking for the last
userturn containing text. Its comment already describesthe correct rule:
The code never checked for a function response. That was equivalent only while a
user turn was either pure text or pure function response.
#28407 added
coalesceConsecutiveRoles, which merges adjacent same-role turns —so a function response turn can now be merged with the prompt that follows it.
Starting the loop at such a turn starts it later than the API starts the turn,
so model turns in between are validated by the API but never receive a synthetic
signature.
The fix adds the missing condition, making the code match its comment and the
API's own turn boundary. One condition, one regression test.
Related Issues
Regression from #28407.
How to Validate
npm test -w @google/gemini-cli-core -- src/core/geminiChat.test.tsThe new test builds the merged
functionResponse+ text turn and asserts thepreceding call is signed. It fails on
main(
expected undefined to be 'skip_thought_signature_validator') and passes withthis change.
Manually: send a prompt, let the model reply, then activate a skill with
/<skill-name>and send a follow-up. Before this change the follow-up returns400; after it, it succeeds.Pre-Merge Checklist