-
Notifications
You must be signed in to change notification settings - Fork 9.5k
feat(cli): support single Ctrl+C to cancel streaming, preserving double Ctrl+C to exit #5838
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
feat(cli): support single Ctrl+C to cancel streaming, preserving double Ctrl+C to exit #5838
Conversation
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.
Summary of Changes
Hello @JayadityaGit, 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!
I've improved the Gemini CLI's user experience by implementing a more intuitive way to cancel in-progress streaming responses. Previously, users had to press the Esc key, which is not a standard CLI pattern. Now, a single Ctrl+C press will cancel the stream, bringing the CLI in line with common command-line tool expectations. This change also centralizes the cancellation logic into a reusable function and provides clearer user feedback, while maintaining the existing double Ctrl+C behavior for exiting the application.
Highlights
- Single Ctrl+C for Stream Cancellation: Users can now press
Ctrl+Conce to stop an active streaming response, aligning the CLI's behavior with common command-line expectations. - Centralized Cancellation Logic: The logic for canceling a stream has been refactored into a reusable
cancelRequestfunction, reducing code duplication and improving maintainability. - Improved User Feedback: Clear messages are now displayed to the user for stream cancellation (
Request cancelled.) and when prompting for a secondCtrl+Cto exit (Press Ctrl+C again to exit.). - Preservation of Double Ctrl+C Exit: The existing behavior of pressing
Ctrl+Ctwice to exit the application remains unchanged, ensuring familiar functionality is preserved.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| 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 issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize 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 counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
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. ↩
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.
Code Review
This pull request introduces a welcome improvement by allowing stream cancellation with a single Ctrl+C, aligning the CLI with standard user expectations. The refactoring of the cancellation logic into a reusable cancelRequest function in useGeminiStream.ts is a good architectural choice that improves maintainability.
My review identifies one high-severity issue where the UI state for tool calls is not correctly updated upon cancellation, which could lead to user confusion. I've provided a detailed comment and a code suggestion to address this.
b2cbe02 to
099bb91
Compare
|
/gemini review |
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.
Code Review
This pull request introduces a great usability improvement by allowing stream cancellation with a single Ctrl+C, which is a standard convention in command-line tools. The refactoring of the cancellation logic into a reusable cancelRequest function is a good architectural choice.
My review identifies one high-severity issue in the new cancelRequest function where pending tool calls are not correctly handled upon cancellation, which could lead to an inconsistent UI state. I've provided a detailed comment with a code suggestion to address this.
Other than that, the changes look good and the feature is a welcome addition to the CLI.
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.
The current cancellation logic for tool calls appears to be flawed. It checks pendingHistoryItemRef.current.type === 'tool_group', but pendingHistoryItemRef is used for text-based pending items (like Gemini's streaming response), not for tool calls. The actual state for tool calls is managed in the toolCalls variable.
This means that when a user cancels (Ctrl+C or Esc) while tools are executing, the pending tool call display will disappear from the UI without being correctly saved to the history with a 'Canceled' status. This leads to an inconsistent UI and loss of session history.
To fix this, the logic should check toolCalls.length and use mapTrackedToolCallsToDisplay to build the history item for the tool group. Additionally, toolCalls should be added to the useCallback dependency array to ensure the function has access to the latest state.
const cancelRequest = useCallback(() => {
if (turnCancelledRef.current) {
return;
}
turnCancelledRef.current = true;
abortControllerRef.current?.abort();
// Persist any pending tool calls to history with a Canceled status.
if (toolCalls.length > 0) {
const toolGroupDisplay = mapTrackedToolCallsToDisplay(toolCalls);
const updatedTools = toolGroupDisplay.tools.map((tool) =>
tool.status === ToolCallStatus.Pending ||
tool.status === ToolCallStatus.Confirming ||
tool.status === ToolCallStatus.Executing
? { ...tool, status: ToolCallStatus.Canceled }
: tool,
);
const updatedToolGroup: HistoryItemToolGroup = {
...toolGroupDisplay,
tools: updatedTools,
};
addItem(updatedToolGroup, Date.now());
}
// Persist any other pending history item (e.g., streaming text).
if (pendingHistoryItemRef.current) {
addItem(pendingHistoryItemRef.current, Date.now());
}
addItem(
{
type: MessageType.INFO,
text: 'Request cancelled.',
},
Date.now(),
);
setPendingHistoryItem(null);
onCancelSubmit();
setIsResponding(false);
setThought(null); // Also reset any active "thought" display.
}, [
addItem,
onCancelSubmit,
pendingHistoryItemRef,
setPendingHistoryItem,
setIsResponding,
setThought,
toolCalls,
]);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.
Thanks !
|
I’d appreciate it if a human reviewer could take a look at this when possible. Thank you! |
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.
Code Review
This pull request introduces a great improvement to the CLI's user experience by allowing stream cancellation with a single Ctrl+C. The implementation is well-structured, centralizing the cancellation logic in a reusable cancelRequest function. I've found one potential issue with how pending items are persisted to history on cancellation, which could lead to duplicate entries. My feedback includes a suggestion to fix this.
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.
There's a potential for duplicating history items when a request with active tool calls is cancelled. The code first persists a new tool group with a 'Canceled' status based on the toolCalls state (lines 194-208). Immediately after, it unconditionally persists pendingHistoryItemRef.current.
If pendingHistoryItemRef.current also contains a tool_group item (which is possible if useReactToolScheduler sets it), this will result in a duplicate tool group being added to the history. This could corrupt the conversation history and affect subsequent model responses.
To fix this, we should avoid persisting pendingHistoryItemRef.current if it's a tool group and we've already handled persisting the tool calls.
// Persist any other pending history item (e.g., streaming text).
if (
pendingHistoryItemRef.current &&
!(toolCalls.length > 0 && pendingHistoryItemRef.current.type === 'tool_group')
) {
addItem(pendingHistoryItemRef.current, Date.now());
}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.
sure !
bfc2684 to
4f81f38
Compare
|
/gemini review |
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.
Code Review
This pull request introduces a standard CLI user experience by allowing a single Ctrl+C to cancel an in-progress stream, while preserving the double Ctrl+C to exit. The core logic is refactored into a reusable cancelRequest function in useGeminiStream.ts. My review focuses on the correctness of this new cancellation logic. I've found one potential issue where partial tool output might be displayed for a canceled tool, which could be confusing. I've provided a suggestion to clear this partial output upon cancellation.
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 a tool call is cancelled, especially while it's in the Executing state, it might have produced partial output that is stored in resultDisplay. Simply changing the status to Canceled while preserving this partial output could be misleading in the UI. It's better to also clear the resultDisplay to avoid showing incomplete data for a canceled operation.
| const updatedTools = toolGroupDisplay.tools.map((tool) => | |
| tool.status === ToolCallStatus.Pending || | |
| tool.status === ToolCallStatus.Confirming || | |
| tool.status === ToolCallStatus.Executing | |
| ? { ...tool, status: ToolCallStatus.Canceled } | |
| : tool, | |
| ); | |
| const updatedTools = toolGroupDisplay.tools.map((tool) => | |
| tool.status === ToolCallStatus.Pending || | |
| tool.status === ToolCallStatus.Confirming || | |
| tool.status === ToolCallStatus.Executing | |
| ? { ...tool, status: ToolCallStatus.Canceled, resultDisplay: undefined } | |
| : tool, | |
| ); |
jacob314
left a comment
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.
Thanks for the pull request. Please add tests and then I will approve. Would be particularly useful to test the new logic added cancelling tool calls.
One other note that if you have a pending tool call awaiting confirmation then Ctrl-C does not cancel it while Esc does. That would be good to fix as with this change users should expect to be able to use ctrl-C to cancel everywhere. Example of what I mean:
Pressing Ctrl-C does nothing here other than to threaten to exit the app.
|
@jacob314 I’ve added the tests and updated the implementation so that a single Ctrl+C works the same as Esc. Thank you for your review. |
|
@jacob314 , The preflight check failed during the test:ci phase for the @google/gemini-cli package due to a JavaScript heap out of memory error. This occurred while running tests with coverage using Vitest. All 1388 tests in The failure seems related to resource constraints during the coverage reporting step rather than an actual test failure. Increasing the Node.js memory limit for the test process might resolve the issue. Consider |
jacob314
left a comment
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.
approved after these comments are addressed. please be sure to revert the files that shouldn't have been changed. there was one file I commented on last round and another file added this round.
d82a025 to
1fcf053
Compare
|
Hi @jacob314, I’ve implemented the requested changes. Let me know if you have any further suggestions or improvements. |
jacob314
left a comment
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.
|
@jacob314, I tried running vitest run --coverage but the job failed with a "JavaScript heap out of memory" error. Interestingly, the tests pass when run in isolation, so this might be related to memory usage during the full coverage run. Is there anything we can do to address this, such as optimizing the tests or increasing Node.js’s memory limit? |
|
Unfortunately there is a merge conflict. Please resolve and then I will merge. |
Head branch was pushed to by a user without write access
|
@jacob314 I’ve tried resolving the conflicts. Could you please review and confirm if everything looks correct? I’m still getting the hang of Git, so I’m a bit unsure. |
7fd491f to
4988fda
Compare
4988fda to
8cb9465
Compare
|
Hi @jacob314, Just wanted to provide an update on this PR. To resolve the merge conflicts with the main branch, I've rebased this feature branch (feat/ctrl-c-stream-stop) on top of the latest upstream/main. A conflict arose in packages/cli/src/ui/App.tsx during the rebase. We resolved it by integrating the cancelOngoingRequest() functionality from main into the newer, refactored key-handling logic in this branch. As of now, this PR adds the intended functionality for Ctrl+C to cancel both ongoing streams and pending tool calls. I am still in the process of figuring out how to write the tests for this behavior. Thanks |
…reaming, preserving double Ctrl+C to exit (google-gemini#5838)
…le Ctrl+C to exit (#5838)
…le Ctrl+C to exit (#5838)

TL;DR
This PR improves the Gemini CLI experience by allowing a single
Ctrl+Cpress to cancel an in-progress stream, matching common CLI expectations. The existing behavior of doubleCtrl+Cto exit the app is preserved.Summary of Changes
The main logic updates are in:
packages/cli/src/ui/App.tsx– to detect a singleCtrl+Cpress during streaming.packages/cli/src/ui/hooks/useGeminiStream.ts– where the cancellation logic was extracted into a reusablecancelRequestfunction.Why This Matters
Previously, users needed to press the
Esckey to cancel a long response — not a familiar pattern in most CLI tools. With this update, the CLI aligns with standard UX expectations:Intuitive Interruption: Pressing
Ctrl+Conce during streaming now cancels the stream immediately.Unified Cancellation Logic: Both
EscandCtrl+Ccall a centralizedcancelRequestfunction, reducing code duplication.User Feedback:
Request cancelled.is shown.Press Ctrl+C again to exit.is shown, just like before.How to Test It
Start Gemini CLI.
Trigger a long streaming response (e.g., ask it to write a novel about space-faring cats).
Single
Ctrl+CCancellation:Ctrl+Conce.Request cancelled., and return to the input prompt.EscKey Cancellation:Esc.Ctrl+C.Double
Ctrl+CExit:Ctrl+Ctwice quickly.Idle
Ctrl+CHandling:Ctrl+Conce.Press Ctrl+C again to exit.and waits. Press again within the window to exit.Testing Matrix
(✅ = Tested; ❓ = Untested; – = Unsupported)
Linked Issue
#5837