diff --git a/src/lib/cloud-agent-sdk/session-manager.test.ts b/src/lib/cloud-agent-sdk/session-manager.test.ts index 89dc7ec754..e5ddab24a2 100644 --- a/src/lib/cloud-agent-sdk/session-manager.test.ts +++ b/src/lib/cloud-agent-sdk/session-manager.test.ts @@ -608,6 +608,22 @@ describe('createSessionManager', () => { ); }); + it('restores canSend and canInterrupt on interrupt failure', async () => { + const config = createMockConfig(); + const mgr = createSessionManager(config); + + await mgr.switchSession(kiloId('ses-1')); + expect(atomValue(config.store, mgr.atoms.canSend)).toBe(true); + expect(atomValue(config.store, mgr.atoms.canInterrupt)).toBe(true); + + mockSession.interrupt.mockRejectedValueOnce(new Error('transient failure')); + await mgr.interrupt(); + + // After a failed interrupt, atoms should be restored from session state + expect(atomValue(config.store, mgr.atoms.canSend)).toBe(true); + expect(atomValue(config.store, mgr.atoms.canInterrupt)).toBe(true); + }); + it('is a no-op without active session', async () => { const config = createMockConfig(); const mgr = createSessionManager(config); diff --git a/src/lib/cloud-agent-sdk/session-manager.ts b/src/lib/cloud-agent-sdk/session-manager.ts index 7d7ea6ef9f..4c73a770fc 100644 --- a/src/lib/cloud-agent-sdk/session-manager.ts +++ b/src/lib/cloud-agent-sdk/session-manager.ts @@ -601,6 +601,8 @@ function createSessionManager(config: SessionManagerConfig): SessionManager { async function interrupt(): Promise { if (!currentSession) return; + // Snapshot before await — switchSession()/destroy() can swap currentSession while in flight. + const session = currentSession; // Eagerly disable send/interrupt to prevent the user from sending a // message while the async interrupt HTTP call is in flight. We do NOT // call disconnect() — interrupt stops the agent but keeps the transport @@ -608,12 +610,20 @@ function createSessionManager(config: SessionManagerConfig): SessionManager { store.set(canSendAtom, false); store.set(canInterruptAtom, false); try { - if (currentSession.canInterrupt) { - await currentSession.interrupt(); + if (session.canInterrupt) { + await session.interrupt(); + } + if (currentSession === session) { + setIndicator({ type: 'info', message: 'Session stopped', timestamp: Date.now() }); } - setIndicator({ type: 'info', message: 'Session stopped', timestamp: Date.now() }); } catch { - store.set(errorAtom, 'Failed to stop execution'); + if (currentSession === session) { + store.set(canInterruptAtom, session.canInterrupt); + const cs = store.get(cloudStatusAtom); + const cloudReady = cs === null || cs.type === 'ready'; + store.set(canSendAtom, session.canSend && cloudReady); + store.set(errorAtom, 'Failed to stop execution'); + } } }