From 72f522d46464365f12cc632d145ad1a515ceb755 Mon Sep 17 00:00:00 2001 From: Brian Pasquini Date: Sat, 6 Jun 2026 16:45:36 -0400 Subject: [PATCH] fix(desktop): recover session after sleep/wake gateway restart When the laptop sleeps and wakes, the WebSocket reconnects but the gateway's in-memory session table is cleared. The desktop app still holds the old activeSessionId, so the next prompt.submit call returns error 4001 ('session not found'), surfaced to the user as: 'Prompt failed: session not found' Fix: wrap prompt.submit in a try/catch. On 'session not found', call session.resume with the durable SQLite session ID (selectedStoredSessionIdRef) to re-register the session in the gateway, update activeSessionIdRef to the fresh live session_id, then retry prompt.submit once. If recovery fails or the error is unrelated, the original error is re-thrown and surfaces normally. --- .../app/session/hooks/use-prompt-actions.ts | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/app/session/hooks/use-prompt-actions.ts b/apps/desktop/src/app/session/hooks/use-prompt-actions.ts index 1f6457d38..0fe2c379b 100644 --- a/apps/desktop/src/app/session/hooks/use-prompt-actions.ts +++ b/apps/desktop/src/app/session/hooks/use-prompt-actions.ts @@ -486,7 +486,38 @@ export function usePromptActions({ attachmentRefs = syncedAttachments.map(attachmentDisplayText).filter((r): r is string => Boolean(r)) rewriteOptimistic(sessionId) const text = buildContextText(syncedAttachments) - await requestGateway('prompt.submit', { session_id: sessionId, text }) + + // On sleep/wake the gateway's in-memory session may have been cleared + // while the desktop app still holds the old session ID. Detect this, + // resume the stored session to re-register it, and retry once. + let submitErr: unknown = null + + try { + await requestGateway('prompt.submit', { session_id: sessionId, text }) + } catch (firstErr) { + const firstMsg = firstErr instanceof Error ? firstErr.message : String(firstErr) + + if (/session not found/i.test(firstMsg) && selectedStoredSessionIdRef.current) { + // Re-register the session in the gateway and get a fresh live ID. + const resumed = await requestGateway<{ session_id: string }>('session.resume', { + session_id: selectedStoredSessionIdRef.current + }) + const recoveredId = resumed?.session_id + + if (recoveredId) { + activeSessionIdRef.current = recoveredId + await requestGateway('prompt.submit', { session_id: recoveredId, text }) + } else { + submitErr = firstErr + } + } else { + submitErr = firstErr + } + } + + if (submitErr !== null) { + throw submitErr + } if (usingComposerAttachments) { clearComposerAttachments()