Skip to content

[Bug]: Hangul/CJK composition is overwritten in the Native Chat composer while a turn streams #16911

Closed

Description

@norinus

What happens

Typing Hangul in the Native Chat composer while an agent turn is streaming loses and mangles syllables. A composed character is written into the textarea and then overwritten by the next streaming render before it can paint.

Plain (non-CJK) typing is unaffected because there is no composition window to overwrite.

Why

The transcript watcher emits one frame per 40ms debounce (src/main/native-chat/transcript-watch-scheduler.ts). Each frame lands as an urgent setAppended(...) in src/renderer/src/components/native-chat/use-native-chat-live-session.ts, so React cannot interrupt it. That render redraws NativeChatView, whose pass contains both the (non-virtualized) message list and the composer. The composer's textarea is controlled (value={draft}), so every one of those renders rewrites the DOM value — including while an IME composition is in flight.

Measured

14s window, 16 composed syllables, 105 transcript frames appended, ~1200 DOM nodes in the chat:

before
React rewrote the textarea value 111 times (≈7 per syllable)
Main thread blocked by long tasks 49% (p50 task 62ms)
commit → paint p50 / p95 74.9ms / 140.4ms
syllables that never settled 2 of 16

What this is not

Terminal panes are not affected. Flooding a visible terminal pane with high-volume output measures 0 long tasks / 0% blocked, and the per-syllable cost there is the agent TUI's own redraw — 58 bytes/syllable in a Claude Code pane vs 6 bytes in a plain PowerShell pane (paint p50 35.5ms vs 18.5ms). That is not Orca's render path.

Reproduction (no agent, no tokens)

  1. Write a synthetic Claude transcript JSONL to ~/.claude/projects/<encoded-cwd>/<uuid>.jsonl with one user + one assistant turn.
  2. Repoint the pane: window.__store.setState so the pane's agentStatusByPaneKey[key].providerSession.transcriptPath points at that file.
  3. Enable the experimental Chat UI and switch the tab to chat.
  4. Append an assistant turn to the file every 40ms.
  5. Type with a CJK IME in the composer and watch the committed characters get rewritten.

window.__orcaTypingDiagnostic.start() / report() / stop() in the renderer console reports mainThreadBlocking and per-source echo latencies for the terminal side.

Environment

  • Orca dev build from main, Windows 11
  • Root cause is platform-independent React render scheduling, so macOS/Linux should reproduce identically.

Related

Activity

  1. AmethystLiang commented on Aug 28, 2026

    @AmethystLiang
    Contributor

    thanks for reporting. looking into it

  2. nwparker commented on Aug 30, 2026

    @nwparker
    Contributor

    Status update: the composition ownership race is fixed in #17169. During streaming and asynchronous attachment resolution, the browser retains provisional Hangul/CJK text; React reconciles only settled drafts, then applies queued attachment paths exactly once. Focused Native Chat tests, typechecks, Electron proof, and the m4air/awin/openclaw host runs passed. The remaining GitHub matrix is rerunning after the shared happy-dom test baseline repair (#17336, now merged). The durable acceptance contract is documented in #17172.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions