fix(desktop): drain queued prompts for background sessions - #57849
fix(desktop): drain queued prompts for background sessions#57849frizikk wants to merge 1 commit into
Conversation
cca34f4 to
46f7d9b
Compare
|
@alt-glitch For extra context: this problem is very frustrating in day-to-day use. Queued prompts getting stranded in background sessions forces manual switching/checking and noticeably slows down the workflow. |
falkoro
left a comment
There was a problem hiding this comment.
Community review — read the full diff. The core of this is strong: the root-cause diagnosis is correct (the only auto-drain effect lives inside the mounted ChatBar, so a backgrounded session's queue is simply never observed), and lifting the drain to a DesktopController-scope hook with explicit sessionId/storedSessionId threading is the right shape — it also closes the adjacent wrong-session hazard for good. The test coverage is meaningful, especially the offscreen-drain-must-not-flip-foreground-busy assertion.
A few things to tighten, mostly against CONTRIBUTING.md:
-
PR template. The body has good Summary/Root cause/Fix/Tests sections, but skips the repo's template — Type of Change and the checklist (guide read, duplicate search, only-related-changes, platform tested). At the current PR volume that checklist is how maintainers triage; adding it makes this easier to salvage/merge.
-
Unrelated formatting churn. Four hunks look like a different Prettier config rather than the fix: the import reflow in
desktop-controller.tsx, the parenthesization change insessionMessagesSignature, theGatewayRequesttype reflow inutils.ts, and therender(...)reflow inindex.test.tsx. Dropping those keeps the diff review-tight per the "only changes related to this fix" rule. -
Small code nit in
submit.ts: two back-to-back identicalif (targetIsCurrentView)blocks (busy-set, thenclearNotifications()) — can merge into one. -
Re-entrancy across the two drainers:
useBackgroundQueueDrainand the ChatBar'suseComposerQueueguard with separatedrainingSessionIdsRefs, so a session switch mid-drain can briefly have both hooks eligible for the same session (background hook skips the newly selected session; the ChatBar now owns it while the old drain is still in flight). The per-session_submitInFlightlock insubmitTextdoes catch the double-submit — worth a one-line comment saying that lock is what makes the dual-drainer overlap safe, so a future refactor doesn't remove it innocently.
None of these are blockers from where I sit — the fix itself looks correct and well-tested. Fixing #1/#2 would mostly make it merge faster.
1f8a30c to
8b01a91
Compare
|
@falkoro thanks for the review — addressed the feedback in the latest push:
I also rebased onto current |
|
Great work on the background drainer — this covers the offscreen-drain gap that #56444 doesn't address. One thing to watch for in the The fix is to accept const storedIdForResume = options?.targetStoredId || selectedStoredSessionIdRef.currentAlso, after a successful resume, the current code unconditionally sets if (!options?.targetRuntimeId || options.targetRuntimeId === activeSessionIdRef.current) {
activeSessionIdRef.current = recoveredId
}These two changes make the background drain fully safe when the user has switched to a different session. |
falkoro
left a comment
There was a problem hiding this comment.
Re-reviewed the updated push — every point from my earlier review is addressed, verified against the new head:
- ✅ PR template — Type of Change, Checklist, and How to Test all filled in
- ✅ Formatting churn dropped —
desktop-controller.tsxis now just the +8 hook wiring,utils.tsjust theSubmitTextOptionsaddition, thesessionMessagesSignature/GatewayRequest/test-render reflows are gone; the diff is review-tight - ✅ Duplicate
targetIsCurrentViewblocks merged — busy-set +clearNotifications()now live in one block insubmit.ts - ✅ Dual-drainer safety documented — the comment at the
_submitInFlightlock now says exactly why the foreground/background drainer overlap during session switches is safe, so a future refactor won't remove it innocently
The core design was already sound (controller-scope drain + explicit sessionId/storedSessionId threading); with the diff tightened and the invariant documented, this looks ready from a community perspective — LGTM. (GitHub won't let a non-collaborator file a formal approval on this repo, so consider this the approve.) CI on the new push is still pending workflow approval, but the changes themselves check out. Nice turnaround on the feedback.
8b01a91 to
4824104
Compare
|
@yingliang-zhang thanks — agreed this is the important safety case. I re-checked the current implementation while resolving the latest
The retry path now resolves the stored id with: const recoverStoredSessionId = targetStoredSessionId ?? selectedStoredSessionIdRef.currentand only updates the foreground runtime ref when the target is still the current view: if (targetIsCurrentView) {
activeSessionIdRef.current = recoveredId
}I added a regression test for the exact switched-session case you called out: It covers: background queued drain hits Rebased onto latest The PR is now mergeable from GitHub's perspective; only review/policy gates remain. |
|
@falkoro thanks for the second pass and the detailed LGTM. Small follow-up after this review: That test covers the switched-session edge case where a background queued submit hits Re-ran after the rebase: Current PR head is |
4824104 to
ec36940
Compare
|
Rebased this PR onto current Kept the newer foreground session-context drift guard while preserving queued/background routing:
Re-ran: focused Vitest (2 files / 51 tests), Desktop typecheck, changed-file ESLint, production build, and |
ec36940 to
7f2ad88
Compare
|
Rebased onto current Conflict resolution preserved both sides of the current test contract: upstream's React Re-ran after the rebase:
I also ran the full Desktop UI suite. It remains red on unrelated baseline/flaky tests; exact PR/base evidence is documented in the updated PR body. |
|
Thanks for the focused background-queue fix. The premise remains present on current The PR's controller-scoped drain and explicit queued runtime/stored ID threading address that gap without publishing background work into the foreground. This fits the Desktop isolation contract: No blocking issues found. Current Automated hermes-sweeper review. |
7f2ad88 to
9174b86
Compare
|
Added the missing issue linkage after re-checking the current release and upstream reports:
The current regression coverage in this PR exercises both the source-binding invariant ( |
|
@teknium1 could you please reassess the priority/severity of this Desktop session-routing class? I agree that #57850's narrow symptom — a background queue remaining stranded until the session is focused — can be viewed as P3 on its own. But this PR also addresses the materially more serious source-session routing failure reported in #56390 and evidenced in #61573:
#61573 contains concrete v0.18.2 Under the repository's labels ( The separate ordinary-submit A/B/B bug in #64789 / #65328 strengthens the overall Desktop session-isolation concern, but I am not claiming this PR fixes that distinct foreground path. This request is specifically about the queued cross-session persistence behavior covered here. |
|
Reviewed (cc from the Desktop cross-session thread). The fix direction is right — binding queued entries to their originating runtime/stored session IDs + a controller-scoped offscreen drainer is exactly what the "prompt queued for A executes in B" reports (#57850, #56390, #61573) need. The blocker is a rebase collision, not the design. Since this branch's base,
Your version restructured the same routing block around This one needs your intent on how the background-drain path should compose with the routed-resume path — could you rebase onto current (For the thread: #62408 terminal-cwd is merged; the bg-completion routing piece is being worked in the #54785/#63317/#42731 cluster.) |
|
Update: went ahead and did the rebase myself in #66001 rather than bounce it back to you. The typecheck clean; your 57 behavioral tests pass unchanged (source-session routing / no foreground mutation / stale-runtime resume), plus 221 across session-hooks + composer. Will close this once #66001 merges. Thanks @frizikk — solid fix, just needed to catch up to main. |
What does this PR do?
Fixes #57850.
A queued Desktop prompt could remain stranded after its source session became backgrounded: the only auto-drain observer belonged to the mounted
ChatBarfor the selected session. This adds a controller-scoped drainer for non-selected sessions and preserves each queued entry's runtime and stored session IDs through submission.The rebase keeps the newer foreground session-context drift guard. Background drains deliberately bypass that foreground-only guard, resume their own stored session after a stale runtime ID, and never overwrite the foreground runtime ID or foreground busy/notification state.
Related Issues
#56390 describes the same queued-prompt source-session affinity failure once a drain runs. #61573 provides field evidence from Desktop v0.18.2 where a prompt queued for busy Session A was persisted and executed in unrelated idle Session B. This PR covers both mechanisms involved: explicit source runtime/stored IDs through queued submit and a controller-scoped offscreen drain loop.
Type of Change
Changes Made
apps/desktop/src/app/session/hooks/use-background-queue-drain.tsDesktopController-scoped drain for idle queues belonging to non-selected sessions.ChatBar.apps/desktop/src/app/session/hooks/use-prompt-actions/submit.tssession.resumedesktop source payload, and guards foreground-only state mutations._submitInFlightguard that makes transient foreground/background drainer overlap safe.apps/desktop/src/app/chat/composer/hooks/use-composer-queue.tsHow to Test
Checklist
Code
pytest tests/ -qis N/A)Documentation & Housekeeping
cli-config.yaml.exampleupdated — N/A; no config keys changedCONTRIBUTING.md/AGENTS.mdupdated — N/A; no workflow changeFor New Skills
N/A — this PR does not add a skill.
Screenshots / Logs
Rebased onto current
upstream/main(569b912d7d0931c7256e9f5fb326609e9deda377) and verified:upstream/mainbaseline also fails (1,279 passed, 2 failed): both reproduce the existingfallback-model.test.tsthousands-separator mismatch, while the other failure varies between localStorage-sensitive tests. The PR run'sterminals.test.tsfailure passes in isolation (7/7).react-hooks/exhaustive-depsin the upstreamact()wrapper; the same warning exists on untouchedupstream/main).assert-dist-builtconfirmeddist/index.htmland assets.git diff --check upstream/main...HEAD: passed.expected stored-db-xyz789, receivedstored-foreground). The mutation was restored and the regression re-passed before push.