fix(acp): reconnect agent when folder selector switches working directory

This commit is contained in:
xintaofei
2026-04-22 12:38:31 +08:00
parent d3d3a66263
commit 10922dd71a
2 changed files with 29 additions and 23 deletions

View File

@@ -110,6 +110,7 @@ export interface ConnectionState {
connectionId: string connectionId: string
contextKey: string contextKey: string
agentType: AgentType agentType: AgentType
workingDir: string | null
status: ConnectionStatus status: ConnectionStatus
promptCapabilities: PromptCapabilitiesInfo promptCapabilities: PromptCapabilitiesInfo
supportsFork: boolean supportsFork: boolean
@@ -134,6 +135,7 @@ type Action =
contextKey: string contextKey: string
connectionId: string connectionId: string
agentType: AgentType agentType: AgentType
workingDir: string | null
} }
| { type: "CONNECTION_REMOVED"; contextKey: string } | { type: "CONNECTION_REMOVED"; contextKey: string }
| { type: "REMOVE_ALL" } | { type: "REMOVE_ALL" }
@@ -601,6 +603,7 @@ function connectionsReducer(
connectionId: action.connectionId, connectionId: action.connectionId,
contextKey: action.contextKey, contextKey: action.contextKey,
agentType: action.agentType, agentType: action.agentType,
workingDir: action.workingDir,
status: "connecting", status: "connecting",
promptCapabilities: { promptCapabilities: {
image: false, image: false,
@@ -2167,10 +2170,12 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
throw createAlertedError(blocked.reason) throw createAlertedError(blocked.reason)
} }
const nextWorkingDir = workingDir ?? null
const existing = storeRef.current.connections.get(contextKey) const existing = storeRef.current.connections.get(contextKey)
if (existing) { if (existing) {
if ( if (
existing.agentType === agentType && existing.agentType === agentType &&
existing.workingDir === nextWorkingDir &&
existing.status !== "disconnected" && existing.status !== "disconnected" &&
existing.status !== "error" existing.status !== "error"
) { ) {
@@ -2204,6 +2209,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
contextKey, contextKey,
connectionId, connectionId,
agentType, agentType,
workingDir: nextWorkingDir,
}) })
const buffered = consumeBufferedEvents(connectionId) const buffered = consumeBufferedEvents(connectionId)

View File

@@ -129,35 +129,35 @@ export function useConnectionLifecycle({
// Auto-connect when tab becomes active and workingDir is available. // Auto-connect when tab becomes active and workingDir is available.
// Depends on isActive + workingDir so that connections wait for folder // Depends on isActive + workingDir so that connections wait for folder
// info to load (workingDir transitions from undefined → folder.path). // info to load (workingDir transitions from undefined → folder.path),
// and so that changing folders on an already-connected tab triggers a
// reconnect with the new cwd. The context's connect() dedups same-param
// calls and disconnects+reconnects when workingDir differs.
// Status changes must NOT re-trigger this to avoid infinite reconnect // Status changes must NOT re-trigger this to avoid infinite reconnect
// loops on transient errors. // loops on transient errors.
useEffect(() => { useEffect(() => {
if (!isActive) return if (!isActive) return
if (!workingDir) return if (!workingDir) return
let cancelled = false let cancelled = false
const s = statusRef.current connConnectRef
if (!s || s === "disconnected" || s === "error") { .current(agentTypeRef.current, workingDir, sessionIdRef.current)
connConnectRef .then(() => {
.current(agentTypeRef.current, workingDir, sessionIdRef.current) if (!cancelled) {
.then(() => { setLastAutoConnectError(null)
if (!cancelled) { }
setLastAutoConnectError(null) })
} .catch((e: unknown) => {
}) if (!cancelled) {
.catch((e: unknown) => { setLastAutoConnectError({
if (!cancelled) { contextKey: contextKeyRef.current,
setLastAutoConnectError({ agentType: agentTypeRef.current,
contextKey: contextKeyRef.current, message: normalizeErrorMessage(e),
agentType: agentTypeRef.current, })
message: normalizeErrorMessage(e), }
}) if (!isExpectedConnectError(e)) {
} console.error("[ConnLifecycle] auto-connect:", e)
if (!isExpectedConnectError(e)) { }
console.error("[ConnLifecycle] auto-connect:", e) })
}
})
}
return () => { return () => {
cancelled = true cancelled = true
} }