diff --git a/src/components/conversations/conversation-detail-panel.tsx b/src/components/conversations/conversation-detail-panel.tsx index b3a51b9..da571c1 100644 --- a/src/components/conversations/conversation-detail-panel.tsx +++ b/src/components/conversations/conversation-detail-panel.tsx @@ -202,8 +202,6 @@ const ConversationTabView = memo(function ConversationTabView({ const [hasSentMessage, setHasSentMessage] = useState(false) const hasPersistedConversation = dbConversationId != null - const canAutoConnect = - hasPersistedConversation || (agentsLoaded && usableAgentCount > 0) // Expose the runtime session key to the tab so the aux panel (Diff sidebar) // can look up live turns even before the DB conversation is created. @@ -266,6 +264,17 @@ const ConversationTabView = memo(function ConversationTabView({ }, [effectiveSessionStats, isActive, setSessionStats]) const externalId = detail?.summary.external_id ?? undefined + // For persisted conversations opened from the sidebar, wait until the + // session's external_id has been resolved before auto-connecting. + // Otherwise the auto-connect effect fires with sessionId=undefined and + // the backend falls back to session/new, orphaning the historical + // context. cline doesn't support session resume, so it connects + // immediately regardless. + const awaitingHistoricalSessionId = + hasPersistedConversation && selectedAgent !== "cline" && detailLoading + const canAutoConnect = + (hasPersistedConversation || (agentsLoaded && usableAgentCount > 0)) && + !awaitingHistoricalSessionId const draftStorageKey = useMemo(() => { if (dbConversationId != null) { return buildConversationDraftStorageKey(dbConversationId) diff --git a/src/hooks/use-connection-lifecycle.ts b/src/hooks/use-connection-lifecycle.ts index e2aa1db..a9e93a5 100644 --- a/src/hooks/use-connection-lifecycle.ts +++ b/src/hooks/use-connection-lifecycle.ts @@ -264,6 +264,10 @@ export function useConnectionLifecycle({ }, [removeTask, clearSelectorTask]) const handleFocus = useCallback(() => { + // Respect the caller's readiness gate — e.g. historical conversations + // set isActive=false until the session's external_id resolves, to + // avoid connecting with sessionId=undefined and orphaning context. + if (!isActive) return touchActivity(contextKey) if (!status || status === "disconnected" || status === "error") { setLastAutoConnectError(null) @@ -274,6 +278,7 @@ export function useConnectionLifecycle({ }) } }, [ + isActive, agentType, workingDir, sessionId,