Skip to content

Stop running threads with Escape - #4298

Closed
jakeleventhal wants to merge 1 commit into
pingdotgg:mainfrom
jakeleventhal:t3code/stop-thread-on-input-escape
Closed

Stop running threads with Escape#4298
jakeleventhal wants to merge 1 commit into
pingdotgg:mainfrom
jakeleventhal:t3code/stop-thread-on-input-escape

Conversation

@jakeleventhal

@jakeleventhal jakeleventhal commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • register Escape as a composer command key
  • interrupt the active turn when Escape is pressed while the chat input is focused and the thread is running
  • preserve existing Escape behavior when the thread is idle
  • cover the running and non-running keyboard rules

Why

The chat composer did not forward Lexical's Escape command to the thread controls, so keyboard users had to move focus to the stop button to interrupt a running turn.

User impact

Users can now stop a running thread by pressing Escape without leaving the chat input.

Validation

  • vp check apps/web/src/composer-logic.ts apps/web/src/composer-logic.test.ts apps/web/src/components/ComposerPromptEditor.tsx apps/web/src/components/chat/ChatComposer.tsx
  • vp test run apps/web/src/composer-logic.test.ts (44 tests passed)
  • pnpm --filter @t3tools/web typecheck
  • integrated browser verification: Escape stopped a running 120-second turn while the composer retained focus

Note

Stop running threads by pressing Escape in the chat composer

  • Adds Escape to the ComposerCommandKey union type and registers a Lexical KEY_ESCAPE_COMMAND handler in ComposerPromptEditor to forward the key to onCommandKeyDown.
  • Adds shouldInterruptRunningThreadFromComposerKey in composer-logic.ts, a predicate that returns true only when the key is Escape and the thread phase is running.
  • ChatComposer checks this predicate on each composer key event and calls onInterrupt() when it returns true, consuming the key before other handlers run.

Macroscope summarized 4fce377.


Note

Low Risk
Small UX change that reuses the existing interrupt callback and only runs when phase === "running".

Overview
Escape in the chat composer now stops an in-progress turn without moving focus to the stop control.

Lexical’s KEY_ESCAPE_COMMAND is wired through the same command-key path as arrows, Enter, and Tab. ChatComposer checks shouldInterruptRunningThreadFromComposerKey first and calls onInterrupt() when the session phase is running; when idle, Escape is not consumed so existing behavior can stay available elsewhere.

Shared typing moves to ComposerCommandKey (including Escape), with unit tests on the interrupt predicate.

Reviewed by Cursor Bugbot for commit 4fce377. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c8500116-36de-4d0d-9627-8c5e194b4298

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 22, 2026
@jakeleventhal
jakeleventhal marked this pull request as ready for review July 22, 2026 19:04

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4fce377. Configure here.

if (shouldInterruptRunningThreadFromComposerKey({ key, isRunning: phase === "running" })) {
onInterrupt();
return true;
}

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.

Escape stops during pending input

Medium Severity

When structured plan or user-input questions are open, the footer shows submit/next controls and hides stop generation, but Escape in the composer still calls onInterrupt() whenever phase === "running". That can abort the turn while someone is typing a custom answer, diverging from the primary-action UI the thread can already be running during pending input.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4fce377. Configure here.

@macroscopeapp

macroscopeapp Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR adds new user-facing keyboard behavior (Escape stops running threads). An unresolved review comment identifies a potential issue where Escape could unintentionally abort threads during pending input scenarios, warranting human review.

You can customize Macroscope's approvability policy. Learn more.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fce377276

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1775 to +1777
if (shouldInterruptRunningThreadFromComposerKey({ key, isRunning: phase === "running" })) {
onInterrupt();
return true;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve IME Escape while composing

When a turn is running and the user is editing with an IME, Escape is commonly used to cancel the current composition/conversion. This new branch runs before any composition check and then consumes the key after onInterrupt(), so an IME user trying to cancel conversion in the composer will instead stop the thread. Please skip the interrupt while event.isComposing so IME editing still works.

Useful? React with 👍 / 👎.

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant