diff --git a/src/acp/control-plane/manager.core.ts b/src/acp/control-plane/manager.core.ts index 4d45a7693a9..8c4822d46a6 100644 --- a/src/acp/control-plane/manager.core.ts +++ b/src/acp/control-plane/manager.core.ts @@ -49,7 +49,9 @@ import { normalizeAcpErrorCode, normalizeActorKey, normalizeSessionKey, + requireReadySessionMeta, resolveAcpAgentFromSessionKey, + resolveAcpSessionResolutionError, resolveMissingMetaError, resolveRuntimeIdleTtlMs, } from "./manager.utils.js"; @@ -332,15 +334,7 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, handle: ensuredHandle, @@ -348,7 +342,7 @@ export class AcpSessionManager { } = await this.ensureRuntimeHandle({ cfg: params.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); let handle = ensuredHandle; let meta = ensuredMeta; @@ -414,19 +408,11 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, handle, meta } = await this.ensureRuntimeHandle({ cfg: params.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); const capabilities = await this.resolveRuntimeCapabilities({ runtime, handle }); if (!capabilities.controls.includes("session/set_mode") || !runtime.setMode) { @@ -479,19 +465,11 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, handle, meta } = await this.ensureRuntimeHandle({ cfg: params.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); const inferredPatch = inferRuntimeOptionPatchFromConfigOption(key, value); const capabilities = await this.resolveRuntimeCapabilities({ runtime, handle }); @@ -558,17 +536,9 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const nextOptions = mergeRuntimeOptions({ - current: resolveRuntimeOptionsFromMeta(resolution.meta), + current: resolveRuntimeOptionsFromMeta(resolvedMeta), patch: validatedPatch, }); await this.persistRuntimeOptions({ @@ -594,19 +564,11 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, handle } = await this.ensureRuntimeHandle({ cfg: params.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); await withAcpRuntimeErrorBoundary({ run: async () => @@ -638,15 +600,7 @@ export class AcpSessionManager { cfg: input.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, @@ -655,7 +609,7 @@ export class AcpSessionManager { } = await this.ensureRuntimeHandle({ cfg: input.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); let handle = ensuredHandle; const meta = ensuredMeta; @@ -810,19 +764,11 @@ export class AcpSessionManager { cfg: params.cfg, sessionKey, }); - if (resolution.kind === "none") { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - if (resolution.kind === "stale") { - throw resolution.error; - } + const resolvedMeta = requireReadySessionMeta(resolution); const { runtime, handle } = await this.ensureRuntimeHandle({ cfg: params.cfg, sessionKey, - meta: resolution.meta, + meta: resolvedMeta, }); try { await withAcpRuntimeErrorBoundary({ @@ -868,27 +814,17 @@ export class AcpSessionManager { cfg: input.cfg, sessionKey, }); - if (resolution.kind === "none") { + const resolutionError = resolveAcpSessionResolutionError(resolution); + if (resolutionError) { if (input.requireAcpSession ?? true) { - throw new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${sessionKey}`, - ); - } - return { - runtimeClosed: false, - metaCleared: false, - }; - } - if (resolution.kind === "stale") { - if (input.requireAcpSession ?? true) { - throw resolution.error; + throw resolutionError; } return { runtimeClosed: false, metaCleared: false, }; } + const meta = resolution.meta; let runtimeClosed = false; let runtimeNotice: string | undefined; @@ -896,7 +832,7 @@ export class AcpSessionManager { const { runtime, handle } = await this.ensureRuntimeHandle({ cfg: input.cfg, sessionKey, - meta: resolution.meta, + meta, }); await withAcpRuntimeErrorBoundary({ run: async () => diff --git a/src/acp/control-plane/manager.utils.ts b/src/acp/control-plane/manager.utils.ts index 3b6b2dacc45..8360f9bfb8a 100644 --- a/src/acp/control-plane/manager.utils.ts +++ b/src/acp/control-plane/manager.utils.ts @@ -2,6 +2,7 @@ import type { OpenClawConfig } from "../../config/config.js"; import type { SessionAcpMeta } from "../../config/sessions/types.js"; import { normalizeAgentId, parseAgentSessionKey } from "../../routing/session-key.js"; import { ACP_ERROR_CODES, AcpRuntimeError } from "../runtime/errors.js"; +import type { AcpSessionResolution } from "./manager.types.js"; export function resolveAcpAgentFromSessionKey(sessionKey: string, fallback = "main"): string { const parsed = parseAgentSessionKey(sessionKey); @@ -15,6 +16,29 @@ export function resolveMissingMetaError(sessionKey: string): AcpRuntimeError { ); } +export function resolveAcpSessionResolutionError( + resolution: AcpSessionResolution, +): AcpRuntimeError | null { + if (resolution.kind === "ready") { + return null; + } + if (resolution.kind === "stale") { + return resolution.error; + } + return new AcpRuntimeError( + "ACP_SESSION_INIT_FAILED", + `Session is not ACP-enabled: ${resolution.sessionKey}`, + ); +} + +export function requireReadySessionMeta(resolution: AcpSessionResolution): SessionAcpMeta { + const error = resolveAcpSessionResolutionError(resolution); + if (error) { + throw error; + } + return resolution.meta; +} + export function normalizeSessionKey(sessionKey: string): string { return sessionKey.trim(); } diff --git a/src/auto-reply/reply/commands-acp/lifecycle.ts b/src/auto-reply/reply/commands-acp/lifecycle.ts index 43896f3ada3..564788f78d7 100644 --- a/src/auto-reply/reply/commands-acp/lifecycle.ts +++ b/src/auto-reply/reply/commands-acp/lifecycle.ts @@ -1,5 +1,6 @@ import { randomUUID } from "node:crypto"; import { getAcpSessionManager } from "../../../acp/control-plane/manager.js"; +import { resolveAcpSessionResolutionError } from "../../../acp/control-plane/manager.utils.js"; import { cleanupFailedAcpSpawn, type AcpSpawnRuntimeCloseHandle, @@ -10,7 +11,6 @@ import { resolveAcpDispatchPolicyError, resolveAcpDispatchPolicyMessage, } from "../../../acp/policy.js"; -import { AcpRuntimeError } from "../../../acp/runtime/errors.js"; import { resolveAcpSessionCwd, resolveAcpThreadSessionDetailLines, @@ -390,24 +390,13 @@ function resolveAcpSessionForCommandOrStop(params: { cfg: params.cfg, sessionKey: params.sessionKey, }); - if (resolved.kind === "none") { + const error = resolveAcpSessionResolutionError(resolved); + if (error) { return stopWithText( collectAcpErrorText({ - error: new AcpRuntimeError( - "ACP_SESSION_INIT_FAILED", - `Session is not ACP-enabled: ${params.sessionKey}`, - ), + error, fallbackCode: "ACP_SESSION_INIT_FAILED", - fallbackMessage: "Session is not ACP-enabled.", - }), - ); - } - if (resolved.kind === "stale") { - return stopWithText( - collectAcpErrorText({ - error: resolved.error, - fallbackCode: "ACP_SESSION_INIT_FAILED", - fallbackMessage: resolved.error.message, + fallbackMessage: error.message, }), ); }