fix(desktop): thread foreground spawn priority through requestGatewayForAgent/retainGatewayForAgent - #105390
fix(desktop): thread foreground spawn priority through requestGatewayForAgent/retainGatewayForAgent#105390nftpoetrist wants to merge 1 commit into
Conversation
…ForAgent/retainGatewayForAgent The NousResearch#102281/NousResearch#104139 chain tagged every activation-door dial (openGatewayForAgent/openGatewayForProfile/ensureGatewayForAgent/ sharedPrimaryRoute) as 'foreground' so a user-initiated open takes a reserved pool slot instead of queuing behind background roster hydration. requestGatewayForAgent and retainGatewayForAgent never got a spawnPriority parameter, so they always dialed 'background' — and they are the only dial path createBackendSessionForSend (send on a fresh chat) and openNewSessionTile ("New session" / tab-strip "+") use. On a saturated pool (max 3 local backends), a user's first message or new-tab click could queue behind background hydration for up to the pool slot wait timeout. Add an optional spawnPriority parameter (defaulting to 'background', matching every other dial function in this file) to both functions and thread it into their isAttachedSharedRemote/openSecondary calls. Pass 'foreground' from the two confirmed user-initiated call sites.
SummaryThreads the #102281 Findings
VerdictLooks good. Narrow, well-tested fix for a real UX hang. Safe to merge. |
|
Related / complementary work: #104871 (ours) reclaims the oldest idle pool resident for later foreground dials when the pool is already full (#102281 follow-up after #104139). This PR threads foreground You noted no line-level overlap with #104871 — agreed these look complementary. Happy for maintainers to review both together; they can coexist, or we can follow guidance on how to split/merge. |
|
Superseded by #113269. Kept your fix as-is in spirit: |
… foreground priority (#113269) * fix(desktop): foreground spawn priority through requestGatewayForAgent/retainGatewayForAgent and the session-create dials The #102281/#104139 chain tagged every activation-door dial (openGatewayForAgent/openGatewayForProfile/ensureGatewayForAgent/ sharedPrimaryRoute) as 'foreground' so a user-initiated open takes the pool's reserved slot instead of queuing behind background roster hydration. requestGatewayForAgent and retainGatewayForAgent never got a spawnPriority, so they always dialed 'background', and they are the only dial path createBackendSessionForSend (first send on a fresh chat) and openNewSessionTile ("New session" / tab-strip "+") use. On a saturated 3-slot local pool the user's first message or new-tab click could wait out the background slot timeout. Add `{ spawnPriority }` options (main's requestGatewayForProfile shape, 5eb0ed4) to both functions and forward it into every dial they make: requestGatewayForProfile on the scope===key and primary-registry branches, isAttachedSharedRemote, openSecondary, and the plain-profile retain branch's gatewayForProfile(key, true, ...) which neither #105390 nor #110354 covered. The four session-create call sites pass 'foreground'. Tests: gateway-spawn-priority.test.ts gains both polarities for request/retain plus the plain-profile retain branch; the use-session-actions and default-new-session matchers pin the tagged dial. SpawnPriority is now exported for the SDK. * fix(desktop): canonical Bot Chat lookup dials foreground through host.requestProfile options Clicking a bot in the roster runs findExistingCanonicalChat -> requestForBot(bot, 'session.list') -> host.requestProfile(route, ...) -> requestGatewayForAgent with no intent, so the first RPC of the gesture, the one that cold-spawns the bot's backend on a local pool, dialed 'background'. With three roster backends already hydrating the click produced no backend activity and the fail-closed lookup surfaced as a "try again" toast (#105104). The later host.openSession is already foreground, but it never runs until this lookup returns. host.requestProfile gains a fifth `options?: { spawnPriority }` argument; `timeoutMs` stays the fourth positional so no existing caller changes shape, and the SDK keeps its exact call arity when no options are given. requestForBot takes the same options and forwards them only when set, so passive roster warming (profiles.list, ui_meta) still dials background. The canonical `session.list` and the `session.create` that follows on a first-ever open both pass 'foreground'. Tests: profile-routing.test.ts (options form with and without a timeout), routing.test.ts (tag forwarded, untagged call keeps three args), canonical-chat-registry.test.ts (session.list and session.create carry foreground; session.title does not). --------- Co-authored-by: nftpoetrist <264138787+nftpoetrist@users.noreply.github.com> Co-authored-by: jxfjosh <282433633+jxfjosh@users.noreply.github.com>
Summary
requestGatewayForAgent/retainGatewayForAgentare the session-scoped RPC lease paircreateBackendSessionForSend(send on a fresh chat) andopenNewSessionTile("New session" row / tab-strip "+") dial through when the target registry route isn't already open. Neither function ever forwards aspawnPriority, so every dial through them defaults to'background'— even though both call sites are a direct user click.The
#102281/#104139chain (merged) tagged every activation-door dial (openGatewayForAgent,openGatewayForProfile,ensureGatewayForAgent,sharedPrimaryRoute) as'foreground'specifically so a user-initiated open takes a reserved pool slot instead of queuing behind background roster-hydration spawns.requestGatewayForAgent/retainGatewayForAgentwere not part of that chain's diff (verified against PR #104139's actual patch — neither function name appears in it), so they still hit the same class of bug the chain fixed: on a saturated pool (maxBackends = 3), a user's first message to a not-yet-dialed bot, or a "New session" click, can queue behind background hydration for up to the pool slot wait timeout.Change
gateway.ts: add an optionalspawnPriorityparameter torequestGatewayForAgent(7th positional arg) andretainGatewayForAgent(3rd positional arg), both defaulting to'background'(matching every other dial function in this file, e.g.openGatewayForAgent/openGatewayForProfile). Thread it into their internalisAttachedSharedRemote/openSecondarycalls — the same two chokepoints the activation-door functions already use.use-session-actions/index.ts: pass'foreground'from the two confirmed user-initiated call sites —createBackendSessionForSend'sretainGatewayForAgent/requestGatewayForAgent('session.create', ...)pair, andopenNewSessionTile's identical pair.Deliberately left unchanged:
session.closecleanup calls in both functions (failure-path cleanup, not a user-facing dial).createSessionBranch'srequestGatewayForAgentcall (line ~2082) — it runs afterensureGatewayAgent, which already dials at foreground priority internally (ensureGatewayForAgenthardcodes'foreground', it doesn't take a priority param), so by the time this call runs the socket is already open and the priority argument would be a no-op.requestGatewayForAgent/retainGatewayForAgentcaller (session-import/api.ts,sdk/index.ts,api/mcp.ts,session-request-router.ts) — these are import/plugin/OAuth/generic-routed paths, not direct user-open clicks.Verification
gateway-spawn-priority.test.ts(mirroring the existing#102281test file's pattern): both functions now tag the registry dial'foreground'when asked, and leave it untagged by default.gateway.tschange only, confirmed the two new positive tests fail (expected false to be true), reapplied, confirmed all pass again.apps/desktop/src/store/gateway*.test.tssuite: 14 files, 107 tests, all passing.apps/desktop/src/app/session/hooks/use-session-actions.test.tsx: 105 tests passing (one pre-existing exact-arg assertion on thecreateBackendSessionForSend→requestGatewayForAgentcall updated to include the new trailing args).tsc --noEmit: clean.Competing PRs
Checked
#101554,#100467,#101482,#103275,#104871(all open, adjacent territory — bot-mode routing, floating pets, session-tile pinning, cross-profile bridge timeouts, LRU pool eviction) and the closed/merged#102281chain PRs (#104139merged,#102496closed-salvaged-into-104139). None touchrequestGatewayForAgent/retainGatewayForAgent— confirmed by grepping the actual diffs, not just titles.#104871'sgateway.tshunks (retainGatewayForSessionTurn,openSecondaryCount) don't overlap the lines this PR touches.Test plan
npx vitest run src/store/gateway-spawn-priority.test.ts— 8/8 passingnpx vitest run src/store/gateway*.test.ts— 14 files / 107 tests passingnpx vitest run src/app/session/hooks/use-session-actions.test.tsx— 105/105 passingnpx tsc -p tsconfig.json --noEmit— clean