From 1954d480cef30024dfa97b74220786e9d1f92ef7 Mon Sep 17 00:00:00 2001 From: openasocket Date: Mon, 9 Mar 2026 00:29:47 -0400 Subject: [PATCH] fix: clear stale agentSessionId on session_not_found to prevent infinite loop When a Claude session expires or is deleted, subsequent prompts would try --resume with the stale session ID, receive session_not_found, and repeat endlessly. Now clears agentSessionId at both the tab and session level so the next prompt starts a fresh session. Co-Authored-By: Claude Opus 4.6 --- .../renderer/hooks/useAgentListeners.test.ts | 33 +++++++++++++++++++ src/renderer/hooks/agent/useAgentListeners.ts | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/src/__tests__/renderer/hooks/useAgentListeners.test.ts b/src/__tests__/renderer/hooks/useAgentListeners.test.ts index 532e537fb..941e75cde 100644 --- a/src/__tests__/renderer/hooks/useAgentListeners.test.ts +++ b/src/__tests__/renderer/hooks/useAgentListeners.test.ts @@ -691,6 +691,39 @@ describe('useAgentListeners', () => { expect(agentErrorOpen).toBe(false); }); + it('clears agentSessionId on session_not_found so next prompt starts fresh', () => { + const deps = createMockDeps(); + const tab = createMockTab({ + id: 'tab-1', + agentSessionId: 'stale-session-abc123', + }); + const session = createMockSession({ + id: 'sess-1', + state: 'busy', + aiTabs: [tab], + activeTabId: 'tab-1', + agentSessionId: 'stale-session-abc123', + }); + useSessionStore.setState({ + sessions: [session], + activeSessionId: 'sess-1', + }); + + renderHook(() => useAgentListeners(deps)); + + onAgentErrorHandler?.('sess-1-ai-tab-1', { + ...baseError, + type: 'session_not_found', + }); + + const updated = useSessionStore.getState().sessions.find((s) => s.id === 'sess-1'); + const updatedTab = updated?.aiTabs.find((t) => t.id === 'tab-1'); + // Tab-level agentSessionId must be cleared + expect(updatedTab?.agentSessionId).toBeUndefined(); + // Session-level agentSessionId must also be cleared + expect(updated?.agentSessionId).toBeUndefined(); + }); + it('appends error log entry to the target tab', () => { const deps = createMockDeps(); const tab = createMockTab({ id: 'tab-1', logs: [] }); diff --git a/src/renderer/hooks/agent/useAgentListeners.ts b/src/renderer/hooks/agent/useAgentListeners.ts index cd9d00254..2b968c760 100644 --- a/src/renderer/hooks/agent/useAgentListeners.ts +++ b/src/renderer/hooks/agent/useAgentListeners.ts @@ -1211,6 +1211,10 @@ export function useAgentListeners(deps: UseAgentListenersDeps): void { ...tab, logs: [...tab.logs, errorLogEntry], agentError: isSessionNotFound ? undefined : agentError, + // Clear stale agentSessionId so the next prompt + // starts a fresh session instead of trying to + // --resume the deleted one (infinite loop). + ...(isSessionNotFound ? { agentSessionId: undefined } : {}), } : tab ) @@ -1220,6 +1224,8 @@ export function useAgentListeners(deps: UseAgentListenersDeps): void { return { ...s, aiTabs: updatedAiTabs, + // Also clear session-level agentSessionId + agentSessionId: undefined, }; }