fix(desktop): first message of a new chat is silently aborted by the session-context drift guard - #63486
Closed
ccowan93 wants to merge 1 commit into
Closed
fix(desktop): first message of a new chat is silently aborted by the session-context drift guard#63486ccowan93 wants to merge 1 commit into
ccowan93 wants to merge 1 commit into
Conversation
The sessionContextDrifted() guard added in 7b5ba20 ("resync fallback editor after config reload") aborts a submit when the session context changes mid-async-window. But on a brand-new chat, createBackendSessionForSend itself mutates activeSessionIdRef / selectedStoredSessionIdRef / the route token to point at the freshly-created session — so the guard always trips on the very first message of a new chat, aborts the submit, and leaves the user's text unsent. The session is already created with their text as the title and the URL already navigated, so the second Enter appears to "work" because session creation is skipped on the existing session. Re-anchor the drift baseline to the freshly-created session right after createBackendSessionForSend returns, so the guard only catches a *real* concurrent session switch — not the session creation we just performed ourselves.
Contributor
Related: this is one of several open PRs fixing the same regression of merged #54527 (new-chat first message silently aborted by the |
Contributor
1 task
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.
Summary
Starting a brand-new chat and pressing Enter on the first message creates the session and sets its title to the typed text, but never actually sends the message to the model. The user has to press Enter a second time to send. Every subsequent message in the chat works normally — only the very first one is dropped.
Root cause
Commit 7b5ba20 ("resync fallback editor after config reload") added a
sessionContextDrifted()guard to the submit pipeline inapps/desktop/src/app/session/hooks/use-prompt-actions/submit.ts, meant to abort a submit if the user switches sessions mid-async-window (protects against #54527).On a brand-new chat the flow is:
submitPromptTextcapturesstartingActiveSessionId = null,startingStoredSessionId = null,startingRouteToken = <old>.createBackendSessionForSend(visibleText)— which creates the session, sets its title, navigates the URL to the new session, and mutatesactiveSessionIdRef/selectedStoredSessionIdRef/ the route token to point at the new session (lines 240–259 ofuse-session-actions/index.ts).sessionContextDrifted()checksselectedStoredSessionIdRef.current !== startingStoredSessionId→"<new-id>" !== null→ true. AndgetRouteToken() !== startingRouteToken→ also true (URL changed).abortForSessionSwitch(sessionId)→ drops the optimistic message, releases busy, returnsfalse. The message never reachesprompt.submit.sessionIdis now truthy,createBackendSessionForSendis skipped, and the guard passes.The guard cannot distinguish "I created a session myself" from "the user switched to a different session mid-submit." On a fresh chat, the creator is the one who moved the refs.
Fix
Re-anchor the drift baseline to the freshly-created session right after
createBackendSessionForSendreturns, so the post-creation guard only catches a real concurrent session switch — not the session creation we just performed ourselves.if (!sessionId) { try { sessionId = await createBackendSessionForSend(visibleText) } catch (err) { dropOptimistic(null) releaseBusy() notifyError(err, copy.sessionUnavailable) return false } + // createBackendSessionForSend establishes a new session and updates + // activeSessionIdRef / selectedStoredSessionIdRef / the route token to + // point at it. Re-anchor the drift baseline to the freshly-created + // session so the post-creation guard only catches a *real* concurrent + // session switch, not the creation we just performed ourselves. Without + // this, the very first message of a new chat always trips the drift + // guard (the refs were null before creation, non-null after), aborts + // the submit, and leaves the user's message unsent — though the session + // is already created with their text as the title, so Enter "works" on + // the second press because creation is skipped on the existing session. + startingActiveSessionId = activeSessionIdRef.current + startingStoredSessionId = selectedStoredSessionIdRef.current + startingRouteToken = getRouteToken() + if (sessionContextDrifted()) { return abortForSessionSwitch(sessionId) }starting*becomeletinstead ofconst. The three othersessionContextDrifted()call sites (aftersession.resumeand aftersyncAttachmentsForSubmit) are unaffected — they still catch genuine concurrent session switches.Repro
main): a new session appears in the sidebar with your text as the title, the URL navigates to/chat/<new-id>, but no message is sent — the composer is empty and idle. Press Enter again (after re-typing) and it goes through.Test plan
npx tsc -p . --noEmitpasses (desktop renderer)npm run buildsucceeds (vite + electron-main bundle)scripts/test-desktop.mjs)Notes
const→letchanges.sessionContextDrifted()call sites still compare against the pre-submit baseline.