Skip to content

feat(core): allow user feedback when cancelling a tool call#25681

Open
luckyrandom wants to merge 1 commit intogoogle-gemini:mainfrom
luckyrandom:upstream-pr/cancel-with-feedback
Open

feat(core): allow user feedback when cancelling a tool call#25681
luckyrandom wants to merge 1 commit intogoogle-gemini:mainfrom
luckyrandom:upstream-pr/cancel-with-feedback

Conversation

@luckyrandom
Copy link
Copy Markdown

Summary

Extends ToolConfirmationPayload with a ToolCancelWithFeedbackPayload variant ({ feedback: string }). When a TOOL_CONFIRMATION_RESPONSE carries this payload with outcome=Cancel, the scheduler interpolates the user's reason into the cancellation message delivered back to the model.

Before:

functionResponse.response.error
  = "[Operation Cancelled] Reason: User denied execution."

After (with feedback):

functionResponse.response.error
  = "[Operation Cancelled] Reason: User denied execution. Feedback: <text>"

Behavior without a feedback payload is unchanged. The existing [Operation Cancelled] Reason: prefix is preserved for backward compatibility.

Motivation

When the SDK asks the user to confirm a destructive tool call, the user can Allow or Cancel. On Cancel, the model receives only a generic "User denied execution." — not enough signal to correct the call. In practice the user often knows exactly what's wrong ("do a smoke run first, not the real run", "write to notes.md instead of overwriting README.md") and wants the model to retry with that fix applied.

What's possible today: the user cancels, then types the reason as a chat message. The problem is ordering — the model sees the cancellation result before the user's follow-up message arrives, so it can freely decide to retry (often with a slightly different command that the user would still deny) without ever seeing the feedback. The user's reason ends up scolding the model after it's already wasted a step.

This change lets hosts optionally thread a short user-authored reason through the same payload channel already used by ToolExitPlanModeConfirmationPayload.feedback, so the feedback is embedded in the cancelled call's functionResponse — the model cannot retry without first reading it. The result: a revised tool call in the next step of the same turn, no follow-up user message, no blind retry.

The addition is backward-compatible (absent payload → existing behavior unchanged) and opt-in per host.

Changes

  • tools/tools.ts: add ToolCancelWithFeedbackPayload to the ToolConfirmationPayload union
  • scheduler/confirmation.ts: propagate the final payload through ResolutionResult so the scheduler can inspect it
  • scheduler/scheduler.ts: on Cancel, use payload.feedback to build the cancel reason
  • scheduler/scheduler.test.ts: cover feedback-present and empty-string-fallback cases

Test plan

  • npm test -- src/scheduler — all 146 scheduler tests pass (144 existing + 2 new)
  • npm run typecheck — clean
  • Reviewer: confirm no prompt/eval pipeline pattern-matches specifically on the pre-existing cancellation string without the feedback suffix

Extends ToolConfirmationPayload with a ToolCancelWithFeedbackPayload
variant ({ feedback: string }). When a confirmation response carries
this payload with outcome=Cancel, the scheduler interpolates the user's
reason into the cancellation message delivered to the model, so the
model sees *why* the call was denied without waiting for the next user
turn.

Before:
  functionResponse.response.error
    = "[Operation Cancelled] Reason: User denied execution."

After (with feedback):
  functionResponse.response.error
    = "[Operation Cancelled] Reason: User denied execution. Feedback: <text>"

Behavior without a feedback payload is unchanged. The existing
"[Operation Cancelled] Reason:" prefix is preserved for backward
compatibility with any consumer pattern-matching on it.

This mirrors the precedent already set by ToolExitPlanModeConfirmation
Payload.feedback, extending the same channel to generic tool denials
so non-TUI hosts (IDE, web UI) can surface per-call denial feedback.

- tools/tools.ts: add ToolCancelWithFeedbackPayload to the payload union
- scheduler/confirmation.ts: propagate the final payload through
  ResolutionResult so the scheduler can inspect it
- scheduler/scheduler.ts: on Cancel, use payload.feedback to build the
  cancel reason
- scheduler/scheduler.test.ts: cover feedback present + empty-string
  fallback
@luckyrandom luckyrandom requested review from a team as code owners April 20, 2026 06:13
@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 introduces a mechanism to pass user-authored feedback when cancelling a tool call. By embedding this feedback directly into the function response, the model can immediately understand the reason for the cancellation and potentially adjust its next action without requiring a separate follow-up message from the user. This change is backward-compatible and opt-in for hosts.

Highlights

  • New Payload Variant: Added ToolCancelWithFeedbackPayload to the ToolConfirmationPayload union to allow users to provide feedback when cancelling tool calls.
  • Scheduler Propagation: Updated the confirmation resolution process to propagate the payload, allowing the scheduler to access and utilize the user's feedback.
  • Feedback Integration: Modified the scheduler to append user feedback to the cancellation reason, ensuring the model receives immediate context for the cancellation.
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 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. 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.

@github-actions
Copy link
Copy Markdown

🛑 Action Required: Evaluation Approval

Steering changes have been detected in this PR. To prevent regressions, a maintainer must approve the evaluation run before this PR can be merged.

Maintainers:

  1. Go to the Workflow Run Summary.
  2. Click the yellow 'Review deployments' button.
  3. Select the 'eval-gate' environment and click 'Approve'.

Once approved, the evaluation results will be posted here automatically.

@gemini-cli gemini-cli bot added the status/need-issue Pull requests that need to have an associated issue. label Apr 20, 2026
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a 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 the ability to capture and return user feedback when a tool call is cancelled. It updates the ResolutionResult and ToolConfirmationPayload types, modifies the scheduler to extract feedback from the confirmation response, and updates the cancellation status message to include this feedback. Unit tests were added to verify the correct formatting of the cancellation reason. A security concern was raised regarding the potential for prompt injection when interpolating untrusted user feedback into the message sent back to the LLM, suggesting that the input should be sanitized by removing newlines and context-breaking characters.

Comment on lines +692 to +694
const reason = cancelFeedback
? `User denied execution. Feedback: ${cancelFeedback}`
: 'User denied execution.';
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.

security-high high

The cancelFeedback variable contains untrusted user input interpolated into the reason string sent to the LLM, posing a prompt injection risk. To mitigate this, avoid including user-provided input in content passed to the LLM (llmContent); use returnDisplay if the input is for display purposes. If the input must be passed to the LLM, ensure it is sanitized at the tool or subagent level (not in the executor) by trimming and removing newlines and context-breaking characters like ].

References
  1. To prevent prompt injection, avoid including user-provided input in content passed to the LLM (llmContent). If the input is needed for display purposes, use returnDisplay instead.
  2. Prompt injection sanitization should be handled at the tool or subagent level, not on a per-tool basis within the agent executor.
  3. Sanitize data from LLM-driven tools before injecting it into a system prompt to prevent prompt injection. At a minimum, remove newlines and context-breaking characters (e.g., ']').
  4. When validating string parameters from tools, trim the string first and then check for emptiness to prevent whitespace-only values from being accepted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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.

1 participant