Skip to content

fix(cli): only auto-nudge genuinely empty continuations and await the nudge - #29771

Closed
1sakshm wants to merge 1 commit into
google-gemini:mainfrom
1sakshm:fix/29071-auto-nudge-race
Closed

1sakshm wants to merge 1 commit into
google-gemini:mainfrom
1sakshm:fix/29071-auto-nudge-race

Conversation

@1sakshm

@1sakshm 1sakshm commented Oct 15, 2026

Copy link
Copy Markdown

Summary

When a tool-loop continuation came back with no visible text, useGeminiStream automatically sent a nudge ([System: You successfully executed a tool but returned an empty response...]). It did this as a fire-and-forget promise from inside the stream loop, and it only checked that the text buffer was empty. As a result the nudge also fired when the stream ended for reasons that are not an empty model response, including after the user pressed Esc. In that case it silently undid the cancellation and started a new request. This PR only nudges genuinely empty continuations and sequences the nudge properly.

Details

Before (processGeminiStreamEvents):

  • The nudge condition was just isContinuation && buffer is empty && attempts < 2. That is also true when the stream ended with:
    • UserCancelled, or a signal aborted by Esc. submitQuery then resets turnCancelledRef and creates a new AbortController, so the cancel is undone and the model is called again.
    • Error: the error is shown, then another request is sent anyway.
    • AgentExecutionStopped / AgentExecutionBlocked: a hook asked the agent to stop and the nudge overrode it.
    • MaxSessionTurns, ContextWindowWillOverflow, LoopDetected.
    • InvalidStream, e.g. NO_RESPONSE_TEXT. Since (FIX) history rollback and retry nudge optimizations #28934 the core already retries empty responses with its own nudge (NO_RESPONSE_TEXT_NUDGE_MESSAGE) before reporting this, so the CLI nudge was a second, stacked retry.
  • The nudge was a floating submitQueryRef.current?.(...) call, started before the outer submitQuery had flushed its pending history item.

After:

  • processGeminiStreamEvents records when the stream ended abnormally (the events above). It returns a new StreamProcessingStatus.EmptyContinuation only for a continuation that ended normally, was not aborted, and produced no text or tool calls.
  • submitQuery handles that status after flushing the pending history item. It sends the nudge only if:
    • the turn was not cancelled (turnCancelledRef),
    • no newer query has started (activeQueryIdRef),
    • and the attempt limit is not reached.
  • The nudge is awaited, so the request stays Responding until the nudge has finished.
  • The nudge text is unchanged, moved to a module constant. The now-unused prompt_id parameter of processGeminiStreamEvents is removed.

Not changed: the issue also suggests skipping geminiClient.addHistory for completed tools in the cancelled path of handleCompletedTools. I left that alone. Those responses pair the model's functionCall turn that is already in history, and dropping them would leave an unanswered functionCall, which is the corruption the surrounding code works to avoid (see the comment in the modelSwitchedFromQuotaError branch). Happy to look at it separately if maintainers see a concrete repro.

Related Issues

Fixes #29071

How to Validate

npm run build --workspace @google/gemini-cli-core
cd packages/cli && npx vitest run src/ui/hooks/useGeminiStream.test.tsx -t "nudge"

New auto-nudge on empty continuation responses tests:

  • an always-empty continuation is nudged exactly twice, all sends share the prompt id, and everything has finished by the time the continuation's own promise resolves
  • no nudge when the stream ended with: an error, an invalid stream, a hook stopping the agent, a hook blocking the agent, a user cancellation, or the session turn limit
  • no nudge when the user cancels (cancelOngoingRequest) while the continuation is still streaming

7 of these fail on main and pass with this change. The existing auto-nudge test (via handleCompletedTools) still passes. All CLI hook and AppContainer tests pass (68 files, 1278 tests), and typecheck and lint are clean.

Pre-Merge Checklist

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

… nudge

The empty-response auto-nudge fired from inside the stream loop as a
floating promise whenever a continuation produced no visible text. That
also happened when the stream ended because the user cancelled, an API
error occurred, a hook stopped or blocked the agent, a limit was reached,
or the core reported an invalid stream (after already retrying with its
own nudge). Because submitQuery resets turnCancelledRef and creates a new
AbortController, a nudge after Esc silently undid the cancellation.

The stream loop now only reports an empty continuation when the stream
ended normally and was not aborted. submitQuery then sends the nudge
after flushing the pending history item, only if the turn was not
cancelled and no newer query has started, and awaits it so the request
stays responding until the nudge completes.

Fixes google-gemini#29071
@github-actions github-actions Bot added the size/m A medium sized PR label Oct 15, 2026
@github-actions

Copy link
Copy Markdown

📊 PR Size: size/M

  • Lines changed: 189
  • Additions: +168
  • Deletions: -21
  • Files changed: 2

@1sakshm
1sakshm marked this pull request as ready for review October 15, 2026 19:35
@1sakshm
1sakshm requested a review from a team as a code owner October 15, 2026 19:35
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 improves the reliability of the auto-nudge feature in the Gemini CLI. Previously, the nudge was triggered incorrectly when streams ended for reasons other than an empty model response, such as user cancellation or errors. By introducing a status-based tracking system and properly awaiting the nudge operation, this change ensures that nudges only occur when appropriate and do not interfere with active request lifecycles.

Highlights

  • Refined Auto-Nudge Logic: The auto-nudge mechanism now correctly identifies genuinely empty continuations by tracking abnormal stream terminations (e.g., user cancellation, errors, or execution limits), preventing unwanted nudges in those scenarios.
  • Proper Sequencing: The nudge is now awaited rather than fired-and-forgotten, ensuring the request state remains 'Responding' until the nudge completes and properly respects intermediate cancellations.
  • Improved Test Coverage: Added comprehensive test cases in useGeminiStream.test.tsx to validate nudge behavior across various stream end conditions and cancellation scenarios.
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@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 refactors the auto-nudge behavior on empty continuation responses in useGeminiStream. Instead of triggering the nudge as a fire-and-forget promise, the stream processing now returns an EmptyContinuation status, allowing the nudge query to be properly awaited. It also introduces an endedAbnormally flag to prevent nudging when the stream terminates due to errors, cancellations, or other limits. Comprehensive unit tests have been added to verify these scenarios. I have no feedback to provide as there are no review comments.

@gemini-cli gemini-cli Bot added the area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality label Oct 15, 2026
@gemini-cli

gemini-cli Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Hi there! Thank you for your interest in contributing to Gemini CLI.

To ensure we maintain high code quality and focus on our prioritized roadmap, we only guarantee review and consideration of pull requests for issues that are explicitly labeled as 'help wanted'.

This PR will be closed in 7 days if it remains without that designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.

@gemini-cli

gemini-cli Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

This pull request is being closed as it has been open for 14 days without a 'help wanted' designation. We encourage you to find and contribute to existing 'help wanted' issues in our backlog! Thank you for your understanding.

@gemini-cli gemini-cli Bot closed this Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/agent Issues related to Core Agent, Tools, Memory, Sub-Agents, Hooks, Agent Quality size/m A medium sized PR status/pr-nudge-sent

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(cli): auto-nudge race in useGeminiStream creates duplicate streams and corrupts history on empty responses

1 participant