Repository navigation
Replies: 1 comment
|
Checked this against the current TypeScript source rather than the built lib/client.js bundle, and there is a real update to report: one of your two suspected causes has already been independently fixed on upstream master. Commit eff482c (2026-09-09, "fix(web): stabilize composer command editing and scrolling") added almost exactly your suggested fix to packages/client/ui-conversation/src/client/input/editor/keymap.ts's registerRootListener callback: prevRoot?.removeAttribute('data-composer-composing') So a root swap while composing is in flight, which you flagged as one plausible trigger (editor.setRootElement(null) during detach/reattach), now resets the closure flag instead of leaving it stuck forever. This landed after 0.1.5-rc.1, the version you tested, so it is worth re-testing against a later build once one is available, since this half of your diagnosis may already be gone. Your second suspected cause is still open though. The same commit added editor.isComposing() into a new syncComposition() helper, but only to drive a CSS attribute (data-composer-composing, for placeholder suppression per the updated doc comment). recentlyComposing() and isComposingEvent() still only read the local composing and composingUntil closure variables, never editor.isComposing(). So if Lexical's own internal composition state gets stuck without a matching compositionend on the tracked root, for example your cause 2, or any compositionend loss that is not a root swap, composing still has no fallback. There is no blur or focusout listener and no bounded timeout beyond the existing 10ms post-compositionend window. Your suggested fixes 2 and 3, a bounded timeout fallback and not swallowing Enter solely on the sticky flag, are both still fully applicable. Good root causing from an OCR'd screen recording. That is a hard bug to pin down from a report alone. |
Uh oh!
There was an error while loading. Please reload this page.
Web composer can get permanently stuck in IME composition: Enter stops submitting and keystrokes produce duplicate/incorrect text
Summary
In the DSH Web UI, the message composer can enter a state where its IME
composition handling is permanently stuck in the "composing" state. While stuck:
text inserted at the wrong place).
Latin letters are left in the draft (observed:
你好t尼哈奥尼哈尼赫尼).rebuilt — reload the page, or leave the session and come back.
Environment
@deepseek-ai/dsh@0.1.5-rc.1(latest on npm at the time of writing),launched as
npx @deepseek-ai/dsh@latest webbuilt-in kaomoji candidate
\(@^0^@)/http://127.0.0.1:3080@deepseek-ai/dsh-client-ui-conversation@0.1.5-rc.1(line numbers below are from the published
lib/client.jsbundle)Steps to reproduce
the composer enters the stuck state.
So far the failure has been observed several times but is not yet deterministic.
It may be timing-dependent.
Actual behaviour
While stuck, the IME candidate window stays open, pinyin is not converted as a
whole word, and the committed text contains both wrong single characters and raw
Latin letters. Pressing Enter does nothing at all.
Evidence
A 9.7 s screen recording was captured by the reporter. 19 frames (2 fps) were
extracted and OCR'd with the Windows OCR engine (
zh-Hans-CN).The draft content was stable across many consecutive frames, i.e. it is
committed text, not a transient composition rendering:
A bare Latin
tsits between Chinese characters, andhaoappears split into哈(ha) +奥(ao) — the signature of a composition that was abortedmid-word and then committed in fragments.
At the same time the IME candidate window held candidates for
nihao:The reporter's description of the failure:
Suspected cause
There are two independent pieces of "is composing" state. Both are cleared only by
a
compositionendevent, and neither has any fallback.1. DSH's own keymap flag
registerComposerKeymapin@deepseek-ai/dsh-client-ui-conversation/lib/client.js:registered on the editor root:
and the Enter command:
with:
composingis a closure variable cleared only by acompositionenddeliveredon the current root element. If that event is never delivered,
composingstaystrueforever, andisComposingEvent(...)then returnstruefor everykey event (a plain Enter has
isComposing === falseandkeyCode === 13, but therecentlyComposing()term is stuck true). The Enter handler therefore returnstrue— "handled" — without ever callinghandlers.submit(). This matches"Enter cannot send" exactly.
A
compositionendcan plausibly be lost when:ComposerContentEditablecallseditor.setRootElement(null)in its effectcleanup, and the shell calls it in
dispose();in flight;
2. Lexical's internal composition state
The bundled Lexical core under the same file tracks composition itself
(
compositionPhase,isComposing(), theinsertCompositionTextbranch of thebeforeinputhandler). A missedcompositionendleaves that state stuck in thesame way, which routes subsequent
beforeinputevents through the compositionbranch and explains the duplicated / mis-positioned insertions
("other keys produce multiple effects").
Suggested fix
composingonblur/focusoutof the root, and wheneverregisterRootListenerswaps the root element.composingif no composition-related event hasbeen observed for N ms.
recentlyComposing()is true. Prefer theper-event signals (
event.isComposing,event.keyCode === 229) and use thesticky flag only for the documented Safari case it was added for.
flight, and re-establish composition state if it can.
Workaround
Reload the page (F5) or leave the session and re-enter. Rebuilding the composer
clears the stuck state.
All reactions