fix(desktop): keep fuller pending assistant over empty inflight shell - #75967
fix(desktop): keep fuller pending assistant over empty inflight shell#75967arimu1 wants to merge 1 commit into
Conversation
When reconciling a session after mid-turn switch, an empty or lagging inflight projection at the same role-ordinal no longer discards the local pending assistant that still holds streamed content (NousResearch#75825).
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused transcript-reconciliation fix. The reported gap remains present on current main: apps/desktop/src/app/session/hooks/use-session-actions/utils.ts:411-415 drops a local pending assistant whenever a same-ordinal authoritative row exists, while utils.ts:515-524 can construct an empty assistant-stream-${sessionId} projection.
Problems
apps/desktop/src/app/session/hooks/use-session-actions/utils.ts:460chooses the local assistant using only text length. A longer but unrelated local message can replace an authoritative assistant at the same ordinal. This conflicts with the stricter identity guard already used by this PR inreconcileResumeMessagesatutils.ts:265-268.- The new tests at
utils.test.ts:656-699cover empty/prefix projections but not a shorter non-prefix authoritative body.
Suggested changes
- Require the local text to be a strict extension of the authoritative text (or let an empty authoritative shell match) in both replacement branches, including the same-id branch at
utils.ts:431. - Add non-prefix regressions for both same-id and different-id rows, asserting the authoritative row remains intact.
Automated hermes-sweeper review.
| const localText = chatMessageText(message).trim() | ||
| const authoritativeText = chatMessageText(authoritative).trim() | ||
|
|
||
| if (authoritativeText.length >= localText.length) { |
There was a problem hiding this comment.
This length-only comparison can replace a different authoritative assistant that merely happens to be shorter. Please mirror the strict-extension condition used above in reconcileResumeMessages (empty shell or localText.startsWith(authoritativeText)) and add a non-prefix regression.
|
Confirmed the premise and the branch you targeted — thank you, this was the right diagnosis. Superseded by #77644, which keeps your commit as its base. Two things pushed it to a salvage rather than a merge. The length-only comparison teknium1 flagged is still live in both replacement paths, so a longer unrelated local row can take an authoritative reply's ordinal or reuse its stream id. And the reporter's own first symptom — reply streaming, but no inference traces or tool calls — is a local row holding reasoning and tool calls with no text yet, where both bodies are empty text and length can't separate them. Two more cases turned up while I was in there: an |
What does this PR do?
Fixes a Desktop transcript bug where switching sessions while a turn streams (or right as it completes) can leave the assistant reply missing from the UI until restart, even though the streamed content was still held in the local slice.
When resuming, reconciliation merges stored history + the backend
inflightprojection (fixed idassistant-stream-${sessionId}, often empty or lagging) with local pending messages.preserveLocalPendingTurnMessagespreviously dropped the local pending assistant whenever any authoritative assistant existed at the same role-ordinal — including an empty projection shell — so the fuller streamed row was discarded and nothing repopulated it after stream events had stopped.Related Issue
Fixes #75825
Related but not duplicated:
assistant-stream-*resurrection viapendingflagType of Change
Changes Made
reconcileResumeMessages: prefer a richer local pending assistant when the authoritative/projected text is empty or a strict prefix of the local stream textpreserveLocalPendingTurnMessages: when a same-ordinal authoritative assistant is less complete, replace that shell with the local pending row (do not append a second bubble); same-id shells get the same completeness preferenceHow to Test
cd apps/desktop ../../node_modules/.bin/vitest run --project ui \ src/app/session/hooks/use-session-actions/utils.test.tsExpected: 50 passed
Manual:
Checklist
Code
pytest tests/ -q— N/A: Desktop-only TypeScript changeDocumentation & Housekeeping