Skip to content

fix(desktop): CJK IME Enter blocked — draft never updates during composition - #44208

Closed
questionjie-max wants to merge 1 commit into
NousResearch:mainfrom
questionjie-max:fix/desktop-cjk-ime-composer-submit
Closed

fix(desktop): CJK IME Enter blocked — draft never updates during composition#44208
questionjie-max wants to merge 1 commit into
NousResearch:mainfrom
questionjie-max:fix/desktop-cjk-ime-composer-submit

Conversation

@questionjie-max

Copy link
Copy Markdown

Summary

Fixes #44135 — CJK IME users cannot send messages via Enter in the desktop composer.

Root Cause

Three remaining gaps after #39614 (which added flushEditorToDraft and removed the composingRef guard):

  1. handleEditorInput left as no-op — after the composingRef guard was removed, the function body was empty. Draft state was never synced on input events, so the Send button stayed hidden during IME typing.

  2. No auto-submit after IME EnterimeEnterRef was already tracked in handleEditorKeyDown, but onCompositionEnd didn't check it. Enter is consumed by IME to commit the preedit, so submitDraft() never fires. Users needed a second Enter.

  3. Blur doesn't reset stale composition flag — if compositionend is missed, the wedged composingRef permanently blocks the Send button ([Bug]: Desktop app composer Enter key has no effect — cannot send messages in new or existing sessions #44135 / fix(desktop): recover from a stale IME composition flag that silently blocks all sends #44149).

Fix (3 changes, 1 file: apps/desktop/src/app/chat/composer/index.tsx)

Change Effect
handleEditorInput calls flushEditorToDraft() Draft updates during IME → Send button appears
onCompositionEnd auto-submits on imeEnterRef CJK one-Enter send
onBlur resets composingRef unconditionally Stale flag can't permanently block sends

Testing

  • macOS 15.6.1 with Simplified Chinese Pinyin
  • Plain English: Enter sends normally (no regression)
  • CJK Pinyin: "nihao" → Enter → commits AND sends in one step
  • Send button: appears during IME typing, not only after punctuation

Related

@liuhao1024

Copy link
Copy Markdown
Contributor

⚠️ File encoding issue — is a base64 blob, not source code

The diff shows the entire 1,830-line replaced with a single base64-encoded line. The committed file appears to be binary-encoded rather than valid TypeScript/TSX source.

This will cause:

  • Build failure (the bundler cannot parse base64 as TSX)
  • The diff is unreviewable — the actual code changes are invisible

The file needs to be re-committed as plain text source. This typically happens when:

  • A git filter or setting encodes the file as binary
  • The file was edited in a tool that saved it in a non-UTF-8 encoding
  • Force-pushing a corrupted working tree

Please re-commit the file with the intended source code changes, then the review can proceed.

@alt-glitch alt-glitch added type/bug Something isn't working comp/tui Terminal UI (ui-tui/ + tui_gateway/) P3 Low — cosmetic, nice to have labels Jun 11, 2026
…osition

Two interacting problems prevented CJK IME users from sending messages
via Enter in the desktop composer:

1. handleEditorInput skipped draft updates when composingRef was true, so
   the React draft state stayed empty during IME typing. This meant
   hasComposerPayload was always false — the Send button never appeared,
   and the submit path had nothing to send.

2. (Upstream already fixed) submitDraft() now uses draftRef.current

Fixes:
- Remove the composingRef guard from handleEditorInput. Draft now
  updates during IME composition so the Send button appears as soon as
  text is in the editor. The Enter guard in handleEditorKeyDown still
  blocks premature submission via event.nativeEvent.isComposing.
- Add imeEnterRef to track Enter during IME composition. On
  compositionend, if set, the committed text is synced from the DOM
  into state and submitDraft() is scheduled — CJK users get one-Enter
  send instead of needing a second Enter.
- Self-heal stale composition flag: clear composingRef on keydown when
  nativeEvent.isComposing is false, and reset on blur unconditionally
  (upstream fix from NousResearch#44149 applied locally).

Closes NousResearch#44135
@questionjie-max
questionjie-max force-pushed the fix/desktop-cjk-ime-composer-submit branch from 5422f9c to f8f949b Compare June 11, 2026 11:55
@questionjie-max

Copy link
Copy Markdown
Author

Fixed — the PR branch was rebuilt from upstream/main. The diff now shows only the actual changes (45 additions, 8 deletions, 1 file). Ready for re-review.

@alt-glitch alt-glitch added comp/desktop Electron desktop app (apps/desktop/*) and removed comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels Jun 26, 2026

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

Thanks for the focused CJK IME investigation. The stale composition-ref failure remains on current main, but this branch needs a targeted salvage rather than a direct merge.

Problems

  • Current main already intentionally skips uncommitted preedit input at apps/desktop/src/app/chat/composer/index.tsx:303-312 and flushes committed text at :727-737 (commit 8e629b9f386d12b726bccb32e9d7b48402ea73ea), so the stated no-op input premise is no longer current.
  • The new imeEnterRef is set at the PR's index.tsx:786-788 and cleared only at :1644-1645. A missed compositionend can therefore leave it armed and let a later unrelated composition end submit unexpectedly.
  • No regression tests cover the new auto-submit or latch lifecycle; existing ime-composition-dom-repro.test.tsx:61-106 only covers committed-text visibility.

Suggested changes

  • Resolve the stale-ref recovery into current main's composer structure and add focused tests for one-Enter submit, genuine-composition suppression, missed-composition-end recovery, and blur recovery.
  • Reset the IME-enter latch on abort/new-composition paths as well as normal composition end.

Automated hermes-sweeper review.

// `hasComposerPayload` stays false and the send button stays hidden
// until an unrelated edit forces a sync (#39614).
flushEditorToDraft(event.currentTarget)
if (imeEnterRef.current) {

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.

imeEnterRef is only cleared after a normal compositionend. In the missed-compositionend failure mode this PR also targets, it remains armed; a later unrelated composition end can then call submitDraft() without a new Enter. Reset this latch on abort/new-composition paths and add that regression case.

@teknium1

Copy link
Copy Markdown
Contributor

This fix landed on main via #86760, which consolidated the duplicate PRs for this bug (earliest submission by @satotakumi in #37487; all contributors credited in that PR's body). Closing as the fix is now merged. Thanks for catching it!

@teknium1 teknium1 closed this Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop app composer Enter key has no effect — cannot send messages in new or existing sessions

4 participants