diff --git a/src/renderer/src/runtime/local-structured-session-tabs-sync.test.ts b/src/renderer/src/runtime/local-structured-session-tabs-sync.test.ts index 7a6c713f37f..702c5570c0d 100644 --- a/src/renderer/src/runtime/local-structured-session-tabs-sync.test.ts +++ b/src/renderer/src/runtime/local-structured-session-tabs-sync.test.ts @@ -307,6 +307,43 @@ describe('local structured session tab projection', () => { } }) + it('starts the session-tabs inventory without waiting for the capability refresh', async () => { + const priorApi = window.api + let releaseStatus = (): void => undefined + const statusGate = new Promise((resolve) => { + releaseStatus = resolve + }) + const getStatus = vi.fn(async () => { + await statusGate + return { capabilities: [STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY] } + }) + const call = vi.fn().mockResolvedValue({ ok: true, result: { snapshots: [] } }) + Object.defineProperty(window, 'api', { + configurable: true, + value: { runtime: { getStatus, call } } + }) + try { + vi.resetModules() + const { restoreLocalStructuredSessionTabsOnce } = + await import('./local-structured-session-tabs-sync') + let settled = false + const restored = restoreLocalStructuredSessionTabsOnce().finally(() => { + settled = true + }) + expect(getStatus).toHaveBeenCalledOnce() + // The inventory RPC must already be in flight while the capability refresh is pending. + expect(call).toHaveBeenCalledWith({ method: 'session.tabs.listAll', params: {} }) + // ...and overlapping must not let the restore open the gate before capabilities land. + await new Promise((resolve) => setTimeout(resolve, 0)) + expect(settled).toBe(false) + releaseStatus() + await restored + expect(call).toHaveBeenCalledOnce() + } finally { + Object.defineProperty(window, 'api', { configurable: true, value: priorApi }) + } + }) + it('accepts a newer session after merged content returns to the base epoch', () => { const state = createSnapshot() const base = { diff --git a/src/renderer/src/runtime/local-structured-session-tabs-sync/inventory-refresh.ts b/src/renderer/src/runtime/local-structured-session-tabs-sync/inventory-refresh.ts index d0f29ec0cf8..af756458707 100644 --- a/src/renderer/src/runtime/local-structured-session-tabs-sync/inventory-refresh.ts +++ b/src/renderer/src/runtime/local-structured-session-tabs-sync/inventory-refresh.ts @@ -10,10 +10,14 @@ import { applyStructuredSessionTabSnapshots } from './snapshot-apply' export function restoreLocalStructuredSessionTabsOnce( expectedGeneration = localStructuredSessionGeneration() ): Promise { + // Why concurrent: the capability refresh only seeds the module cache that later launch + // flows read; the inventory fetch never reads it, so chaining them only paid a second + // serial IPC round-trip on the startup gate. return latchLocalStructuredSessionRestore(() => - refreshLocalRuntimeCapabilities() - .then(() => refreshLocalStructuredSessionTabs(expectedGeneration)) - .then(() => undefined) + Promise.all([ + refreshLocalRuntimeCapabilities(), + refreshLocalStructuredSessionTabs(expectedGeneration) + ]).then(() => undefined) ) }