fix(cli/acp): prevent infinite thought loop in ACP mode by disablig nextSpeakerCheck#26874
Conversation
…nextSpeakerCheck Summary: Forces `skipNextSpeakerCheck` to `true` when the CLI is running in ACP mode. This prevents the core GeminiClient from recursively initiating synthetic continuation turns, which previously resulted in unbounded `agent_thought_chunk` loops during ACP sessions. Details: Why this happened: The `nextSpeakerCheck` mechanism in `GeminiClient` was designed for the interactive terminal TUI. When a model returns a turn without explicit content or tools (e.g., thought-only responses), this mechanism makes a separate LLM call to evaluate if the model was cut off or expects to continue. If it decides the model should continue, it automatically injects a "Please continue." prompt and recurses the turn inside the generator. However, in ACP mode, turn boundaries are explicit and strictly managed by the IDE client via the `session/prompt` protocol. The core client's internal recursive continuation bypasses the ACP session's `while(true)` outer loop. Because the ACP protocol expects the stream to end so it can evaluate tools or wait for the next user input, the internal continuation traps the agent in a loop where it perpetually emits thoughts without returning control to the client. How we are fixing it: Modified `loadCliConfig` in `packages/cli/src/config/config.ts` to apply an explicit override: `skipNextSpeakerCheck: isAcpMode || settings.model?.skipNextSpeakerCheck` This ensures that regardless of the user's local `settings.json`, ACP sessions will always bypass the `checkNextSpeaker` flow. As a result, when an invalid or thought-only stream ends, the `GeminiClient` correctly yields control back to `acpSession.ts`, which emits an `end_turn` stop reason and allows the IDE protocol to gracefully handle the next step.
|
Size Change: +283 B (0%) Total Size: 34.1 MB
ℹ️ View Unchanged
|
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 an issue where the CLI would enter an infinite loop of thought chunks when operating in ACP mode. By forcing the 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
|
There was a problem hiding this comment.
Code Review
This pull request ensures that skipNextSpeakerCheck is always enabled when the CLI is in ACP mode to prevent infinite loops during turn management. It includes updates to the loadCliConfig function and new unit tests in config.test.ts to validate this logic. I have no feedback to provide.
…extSpeakerCheck (#26874)
Summary
Forces
skipNextSpeakerChecktotruewhen the CLI is running in ACP mode. This prevents the core GeminiClient from recursively initiating synthetic continuation turns, which previously resulted in unboundedagent_thought_chunkloops during ACP sessions.Details
Why this happened:
The
nextSpeakerCheckmechanism inGeminiClientwas designed for the interactive terminal TUI. When a model returns a turn without explicit content or tools (e.g., thought-only responses), this mechanism makes a separate LLM call to evaluate if the model was cut off or expects to continue. If it decides the model should continue, it automatically injects a "Please continue." prompt and recurses the turn inside the generator.However, in ACP mode, turn boundaries are explicit and strictly managed by the IDE client via the
session/promptprotocol. The core client's internal recursive continuation bypasses the ACP session'swhile(true)outer loop. Because the ACP protocol expects the stream to end so it can evaluate tools or wait for the next user input, the internal continuation traps the agent in a loop where it perpetually emits thoughts without returning control to the client.How we are fixing it:
Modified
loadCliConfiginpackages/cli/src/config/config.tsto apply an explicit override:skipNextSpeakerCheck: isAcpMode || settings.model?.skipNextSpeakerCheckThis ensures that regardless of the user's local
settings.json, ACP sessions will always bypass thecheckNextSpeakerflow. As a result, when an invalid or thought-only stream ends, theGeminiClientcorrectly yields control back toacpSession.ts, which emits anend_turnstop reason and allows the IDE protocol to gracefully handle the next step.Related Issues
Fixes google-gemini/maintainers-gemini-cli#1662
How to Validate
There is no loop anymore. This is hard to repro so harder to validate.
Pre-Merge Checklist