Skip to content

fix(desktop/composer): don't cancel in-flight turn on ESC while IME is composing - #7919

Open
chengoak wants to merge 1 commit into
esengine:main-v2from
chengoak:fix/composer-escape-ime-guard-v2
Open

fix(desktop/composer): don't cancel in-flight turn on ESC while IME is composing#7919
chengoak wants to merge 1 commit into
esengine:main-v2from
chengoak:fix/composer-escape-ime-guard-v2

Conversation

@chengoak

@chengoak chengoak commented Aug 8, 2026

Copy link
Copy Markdown

Problem

The composer's ESC handler unconditionally calls handleCancel() whenever a turn is running, even when the ESC keydown was fired to dismiss a Chinese/Japanese IME candidate window. On macOS this is easy to hit while replying is streaming:

  1. Send a prompt and let the agent start replying.
  2. Start typing a new message with a Chinese IME while the reply streams.
  3. With the candidate list still open, press ESC to dismiss the candidate.
  4. Expected: candidate closes, agent keeps replying.
  5. Actual: the agent turn is cancelled mid-reply.

Root cause

desktop/frontend/src/components/Composer.tsx — the same onKeyDown handler that gates the send-Enter chord, the mention/past-chats menu, Shift+Tab plan toggle, and paste shortcuts with !composing was missing that guard on the running-turn ESC branch:

if (e.key === "Escape" && running) {
  e.preventDefault();
  handleCancel();
}

So an IME dismiss ESC on a running turn falls straight into handleCancel().

Fix

Add !composing to the ESC guard. The existing isImeKeyEvent() helper already folds together composingRef, nativeEvent.isComposing, keyCode === 229, and a short post-compositionend grace window (IME_CONFIRM_GRACE_MS), so composing is already the right signal — no new state or listeners.

if (e.key === "Escape" && running && !composing) {
  e.preventDefault();
  handleCancel();
}

Diff: +4 / -1 (three lines are a comment explaining why, sized to stay within the project's ≤3 lines per non-declaration comment rule in REASONIX.md).

Verification

Local Wails build (main-v2 HEAD + this patch, macOS arm64):

  1. Send a prompt; agent starts streaming a reply.
  2. In the composer, start typing with a Chinese IME (macOS 拼音 / 双拼).
  3. Press ESC while the candidate window is open.
  4. Result: candidate window closes; agent continues streaming without interruption. ✅

Non-IME ESC behavior is unchanged:

  • ESC with no composition and running still cancels the turn as before (matches the Stop button's hint).
  • Menu/past-chats ESC branch above is untouched.
  • Send-Enter, Shift+Tab, prompt-history nav paths are untouched.

Notes

  • Fix is scoped to desktop/frontend/src/components/Composer.tsx; no changes to the Go side or bindings.
  • Same class of bug (IME composition ESC being interpreted as an abort) has bitten other Electron/Tauri/Wails chat frontends on macOS WKWebView; this is the minimal per-component fix.

Documentation impact

Documentation-impact: none - Composer.tsx is the user-facing chat composer, but this change is purely a behavior guard (don't treat ESC as an interrupt while the IME composition is active). No public API, no documented keybinding surface, no user-visible setting changes. The existing docs for the ESC interrupt / Stop button remain accurate as-is.

Supersedes

This PR supersedes #6749, which I closed to restart the review queue. The previous PR was technically correct but got stuck for two reasons I want to be transparent about:

  1. CI docs-impact was failing — the original PR body didn't declare a Documentation-impact field, so the Documentation impact guard check blocked it. Fixed in this PR's body.
  2. mergeable: UNKNOWN kept recurringmain-v2 ships 20+ PRs per day, so the base moved forward between my force-pushes. The PR was repeatedly in a state where GitHub couldn't compute the merge.

The patch itself is functionally identical to #6749 (same one-condition addition to the same guard). The only delta is the comment was tightened from 4 lines to 3 to stay within the project's ≤3 lines per non-declaration comment rule.

@SivanCola @esengine — would appreciate a review when you have a moment. Happy to split into two commits (comment-only + one-line condition) if that's preferred.

@github-actions github-actions Bot added desktop Wails desktop app (desktop/**) v2 Go rewrite (1.x) — main-v2 branch, active development labels Aug 8, 2026
@chengoak
chengoak force-pushed the fix/composer-escape-ime-guard-v2 branch 2 times, most recently from 0d20ae2 to b6dafa2 Compare August 8, 2026 05:07
@chengoak

chengoak commented Aug 8, 2026

Copy link
Copy Markdown
Author

@SivanCola @esengine ping — when you have a moment, would appreciate a review on this small IME/ESC guard fix. Supersedes #6749 (which got stuck on docs-impact CI + recurring mergeable: UNKNOWN); the patch is functionally identical but the PR body now declares Documentation-impact: none up front and the comment was tightened to 3 lines per REASONIX.md. CI is clean, mergeable is stable. Happy to split or rebase if helpful.

@chengoak
chengoak force-pushed the fix/composer-escape-ime-guard-v2 branch 3 times, most recently from 8c4be1c to 06d61de Compare August 8, 2026 10:14
@chengoak
chengoak force-pushed the fix/composer-escape-ime-guard-v2 branch from 06d61de to 153b6d2 Compare August 8, 2026 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop Wails desktop app (desktop/**) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant