fix(desktop): eliminate perceived delay when sending messages#3441
Merged
esengine merged 1 commit intoJun 7, 2026
Merged
Conversation
When the user sends a message, the UI waits until the backend emits the first text/reasoning token before showing anything in the Transcript. During this gap (0.3-3 s depending on model TTFT) the Composer clears itself but the conversation area stays blank - the message appears to have vanished. Root cause: the reducer holds the user text in pendingUser and only flushes it to items on the first non-turn_started/non-turn_done event. The turn_started handler itself never touched pendingUser. Fix: - Flush pendingUser on turn_started so the user message appears immediately when the backend acknowledges the turn. - Pre-create an empty assistant bubble with a blinking cursor on turn_started, giving instant visual feedback that the model is working (similar to ChatGPT/Claude typing indicator). - The guard that excluded turn_started from flushing is no longer needed; keep only the turn_done exclusion for the cancel-before- reply edge case. Perceived latency drops from backend TTFT to 0 ms.
d0e96c0 to
0b3d53a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When the user sends a message in the desktop app, there is a noticeable delay (0.3–3 s depending on model TTFT) before anything appears in the conversation area. During this gap:
textorreasoningtoken does the user message finally appearThis creates a "dead zone" where the user's message has seemingly vanished into the void.
Root Cause
In
useController.ts, the reducer holds the user's text inpendingUserand only flushes it toitems(the rendered list) on the first non-turn_started/non-turn_doneevent:The
turn_startedhandler never touchedpendingUser:So the user message only becomes visible when the first
text/reasoningevent arrives from the backend — which could be hundreds of milliseconds to several seconds later.Fix
Two changes in
applyEvent:Flush
pendingUseronturn_started— the user message appears the instant the backend acknowledges the turn, not when the first token arrives.Pre-create an empty assistant bubble with a blinking cursor — gives immediate visual feedback that the model is processing (similar to ChatGPT/Claude's typing indicator). The Composer's status bar already shows "thinking… 0s", and now the Transcript also shows the cursor.
The guard condition is simplified from
e.kind !== "turn_started" && e.kind !== "turn_done"to juste.kind !== "turn_done"— theturn_doneexclusion is kept for the cancel-before-reply edge case.Before / After
Verification
pnpm typecheck✅ cleanpnpm build✅built in 10.58s.cursoranimation already exists at styles.css:1172)