fix(acp): defer auto-connect until historical session id resolves

When reopening a historical conversation, the ACP auto-connect fired before
the detail fetch resolved external_id, so the backend fell back to
session/new and the agent lost prior context. Gate both the auto-connect
effect and the focus-triggered reconnect on the session id being ready.
This commit is contained in:
xintaofei
2026-04-24 22:11:53 +08:00
parent 8d5ec464d9
commit 9bb3f3b84c
2 changed files with 16 additions and 2 deletions

View File

@@ -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)

View File

@@ -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,