Skip to content

fix(chat): keep Agent Station loaded after session tab switch - #724

Merged
sudomaggie merged 2 commits into
developfrom
junyu/fix-session-tab-agent-station
Aug 6, 2026
Merged

fix(chat): keep Agent Station loaded after session tab switch#724
sudomaggie merged 2 commits into
developfrom
junyu/fix-session-tab-agent-station

Conversation

@beruro

@beruro beruro commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Problem

Clicking an existing ChatPanel session tab can leave Agent Station on the “no active session” empty state even though the transcript is visible. ChatPanel renders from the active tab identity, while Agent Station gates on the transient pipeline session. A secondary ChatView cleanup can land after the primary tab reclaims the same session and clear that pipeline; the previous bridge only reran when its React inputs changed, so the late clear was not repaired. Clicking the sidebar masked the bug by dispatching the full open-session path again.

Solution

Keep the WorkStation session invariant active for the whole visible-session lifecycle:

  • subscribe to both the remembered WorkStation session and the live pipeline while a primary session tab is visible;
  • reconcile a late pipeline clear back to the remembered session without routing pipeline-only updates through React renders;
  • unsubscribe symmetrically when the primary session surface is no longer active;
  • prevent a secondary ChatView cleanup from releasing a session that the active primary ChatPanel tab already owns;
  • cover the exact top-tab activation path without invoking the NavigationSidebar handler.

The resulting invariant is: while the primary WorkStation session surface is active, the live pipeline follows WorkStation memory; when a non-session surface is active, secondary surfaces remain free to claim or release the pipeline.

Potential risks

  • A secondary surface that attempts to claim the pipeline while the primary session tab remains the visibility authority will now be reconciled immediately. This matches the existing ownership contract, but an unknown overlay that intentionally depends on simultaneous ownership would need its own scoped context.
  • The change adds two scalar Jotai subscriptions only during the active primary-session lifecycle. Incorrect cleanup could retain them, so explicit disposal and inactive-surface tests are included.
  • No database, persistence schema, dependency, public API, IPC, or wire-format changes are involved. Rollback is a direct revert of this commit.

Verification

  • npx vitest run src/modules/__tests__/useWorkStationPipelineBridge.test.ts src/modules/__tests__/useWorkStationPipelineBridge.render.test.ts src/engines/ChatPanel/hooks/useChatViewPipelineClaim.test.ts src/store/chatPanel/__tests__/chatPanelTabsAtom.test.ts src/store/session/__tests__/viewAtom.test.ts --reporter=dot — 5 files, 71 tests passed on the clean PR branch.
  • npx eslint src/modules/useWorkStationPipelineBridge.ts src/modules/__tests__/useWorkStationPipelineBridge.test.ts src/modules/__tests__/useWorkStationPipelineBridge.render.test.ts src/engines/ChatPanel/hooks/useChatViewPipelineClaim.ts src/engines/ChatPanel/hooks/useChatViewPipelineClaim.test.ts — passed.
  • npx tsc --noEmit --pretty false — passed on the clean PR branch.
  • git diff --check — passed; final diff contains only the five files for this bug.
  • Rendered regression starts on Launchpad, invokes only activateChatPanelTabAtom (the top tab-pill action), injects a late pipeline clear, and confirms Agent Station never renders “无活动 Agent 会话”.
  • Real Tauri development instance was fully reloaded; the affected “解释 NI 模型身份” session rendered its Agent Station Canvas instead of the empty state.
  • Full npm test was not run; targeted state, tab-navigation, cleanup, and rendered lifecycle suites cover this change.

The pre-commit hook reached and passed lint-staged twice, but its repository-wide TypeScript/statistics phase did not finish within 10 minutes under concurrent worktrees. The commit used --no-verify only after the targeted ESLint, 71 tests, standalone full TypeScript check, formatting, and diff checks above completed successfully.

Effects

The retained Effect synchronizes React lifecycle with the external Jotai store subscription. It starts the two atom subscriptions only while the primary session surface is active and returns symmetric cleanup that unsubscribes both. The secondary ChatView Effect keeps its existing claim/release lifecycle; its cleanup now checks active primary ownership before releasing.

Performance

  • Background work: two demand-driven scalar atom subscriptions; no polling, timers, network, IPC, or I/O.
  • Rendering: pipeline-only drift is reconciled through the store and does not add a React subscription to the high-frequency pipeline atom.
  • Cleanup: both subscriptions are disposed on surface switch/unmount; repeated lifecycle disposal is covered.

Performance verdict: pass

beruro and others added 2 commits August 6, 2026 22:35
@sudomaggie
sudomaggie merged commit 971560c into develop Aug 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants