Repository navigation
[Bug]: Hangul/CJK composition is overwritten in the Native Chat composer while a turn streams #16911
Description
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)
- Write a synthetic Claude transcript JSONL to
~/.claude/projects/<encoded-cwd>/<uuid>.jsonlwith one user + one assistant turn. - Repoint the pane:
window.__store.setStateso the pane'sagentStatusByPaneKey[key].providerSession.transcriptPathpoints at that file. - Enable the experimental Chat UI and switch the tab to
chat. - Append an assistant turn to the file every 40ms.
- 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
- Refs [Bug]: Chinese IME input lags/stutters in text fields (not present in Ghostty) #12829 — same class (CJK IME lag in text fields) but broader scope; search fields and the macOS candidate window are not addressed by this report.
- Refs Chinese IME: single character not displayed during composition #16260 — proposes the same composition-guard approach app-wide.
- Not related: [Bug]: Persistent Korean character doubling (duplicate rendering) in Orca terminal #15550 / [Bug]: Issues with duplicate Korean text and content disappearing in the terminal #15192 are terminal output rendering bugs, not input.
Activity
AmethystLiang commentedon Aug 28, 2026
thanks for reporting. looking into it
nwparker commentedon Aug 30, 2026
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.