docs: document acp turn control plane

This commit is contained in:
Peter Steinberger
2026-06-04 05:26:08 -04:00
parent d88b06cb75
commit 05289f1aa0
16 changed files with 36 additions and 0 deletions
+1
View File
@@ -1,3 +1,4 @@
/** Reads ACP session status from the runtime and reconciles persisted identity metadata. */
import { resolveSessionIdentityFromMeta } from "@openclaw/acp-core/runtime/session-identity";
import type {
AcpRuntime,
@@ -1,3 +1,4 @@
/** Shared ACP manager test harness, mocks, fixtures, and assertion helpers. */
import type { AcpRuntime, AcpRuntimeCapabilities } from "@openclaw/acp-core/runtime/types";
import { afterEach, beforeEach, expect, vi } from "vitest";
import { resetAcpManagerTaskStateForTests } from "../../../test/helpers/acp-manager-task-state.js";
+1
View File
@@ -1,3 +1,4 @@
/** Tests ACP session manager resolution, turn execution, state transitions, and cleanup. */
import { setTimeout as scheduleNativeTimeout } from "node:timers";
import { setTimeout as sleep } from "node:timers/promises";
import { MAX_TIMER_TIMEOUT_MS } from "@openclaw/normalization-core/number-coercion";
+1
View File
@@ -1,3 +1,4 @@
/** Public singleton facade for the ACP session manager control plane. */
import { AcpSessionManager } from "./manager.core.js";
export { AcpSessionManager } from "./manager.core.js";
@@ -1,3 +1,4 @@
/** Tests ACP turn terminal results and detached-task progress outcomes. */
import { describe, expect, it, vi } from "vitest";
import {
requireTaskByRunId,
@@ -1,3 +1,4 @@
/** Runs ACP turns, failover, timeout cleanup, and detached-task progress mirroring. */
import type { AcpRuntime, AcpRuntimeHandle } from "@openclaw/acp-core/runtime/types";
import { logVerbose } from "../../globals.js";
import { AcpRuntimeError, formatAcpErrorChain, toAcpRuntimeError } from "../runtime/errors.js";
@@ -47,6 +48,7 @@ type ApplyRuntimeControls = (params: {
meta: SessionAcpMeta;
}) => Promise<void>;
/** Executes one ACP prompt turn against the selected backend and records terminal state. */
export async function runManagerTurn(params: {
input: AcpRunTurnInput;
sessionKey: string;
@@ -1,3 +1,4 @@
/** Normalizes ACP runtime turn event/result streams into manager-facing outcomes. */
import type {
AcpRuntime,
AcpRuntimeEvent,
@@ -8,6 +9,7 @@ import { AcpRuntimeError } from "../runtime/errors.js";
import { normalizeAcpErrorCode } from "./manager.utils.js";
import { normalizeText } from "./runtime-options.js";
/** Mutable gate used to suppress late events after timeout/cancel races. */
export type AcpTurnEventGate = {
open: boolean;
};
@@ -104,6 +106,7 @@ async function notifyTerminalResult(params: {
});
}
/** Consumes runtime turn APIs and emits normalized events while tracking output/terminal state. */
export async function consumeAcpTurnStream(params: {
runtime: AcpRuntime;
turn: AcpRuntimeTurnInput;
@@ -1,3 +1,4 @@
/** Timeout and cleanup helpers for long-running ACP turns. */
import type { AcpRuntimeSessionMode } from "@openclaw/acp-core/runtime/types";
import { clampTimerTimeoutMs } from "@openclaw/normalization-core/number-coercion";
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
@@ -29,6 +30,7 @@ export function resolveTurnTimeoutMs(params: {
});
}
/** Awaits a turn promise with bounded timeout handling and late-error logging. */
export async function awaitTurnWithTimeout<T>(params: {
sessionKey: string;
turnPromise: Promise<T>;
@@ -107,6 +109,7 @@ export async function awaitTurnWithTimeout<T>(params: {
}
}
/** Cancels a timed-out turn and clears non-persistent cached runtime state. */
export async function cleanupTimedOutTurn(params: {
sessionKey: string;
activeTurn: ActiveTurnState;
+6
View File
@@ -1,3 +1,4 @@
/** Shared types and dependency wiring for the ACP session manager control plane. */
import type {
AcpRuntime,
AcpRuntimeCapabilities,
@@ -39,6 +40,7 @@ export type AcpSessionResolution =
meta: SessionAcpMeta;
};
/** Input required to create or resume an ACP runtime session. */
export type AcpInitializeSessionInput = {
cfg: OpenClawConfig;
sessionKey: string;
@@ -55,6 +57,7 @@ export type AcpTurnAttachment = {
data: string;
};
/** Input for one ACP prompt turn routed through the manager. */
export type AcpRunTurnInput = {
cfg: OpenClawConfig;
sessionKey: string;
@@ -72,6 +75,7 @@ export type AcpTurnLifecycleEvent = {
at: number;
};
/** Input for closing, resetting, or cleaning up an ACP session. */
export type AcpCloseSessionInput = {
cfg: OpenClawConfig;
sessionKey: string;
@@ -88,6 +92,7 @@ export type AcpCloseSessionResult = {
metaCleared: boolean;
};
/** User-facing session status assembled from persisted metadata and runtime status. */
export type AcpSessionStatus = {
sessionKey: string;
backend: string;
@@ -102,6 +107,7 @@ export type AcpSessionStatus = {
lastError?: string;
};
/** Process-local ACP manager counters exposed for diagnostics. */
export type AcpManagerObservabilitySnapshot = {
runtimeCache: {
activeSessions: number;
+7
View File
@@ -1,3 +1,4 @@
/** Shared ACP manager normalization, resolution, and error helpers. */
import { ACP_ERROR_CODES, AcpRuntimeError } from "@openclaw/acp-core/runtime/errors";
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
import {
@@ -19,6 +20,7 @@ export function resolveAcpAgentFromSessionKey(sessionKey: string, fallback = "ma
return normalizeAgentId(parsed?.agentId ?? fallback);
}
/** Builds the stale-session error shown when ACP metadata is missing. */
export function resolveMissingMetaError(sessionKey: string): AcpRuntimeError {
return new AcpRuntimeError(
"ACP_SESSION_INIT_FAILED",
@@ -26,6 +28,7 @@ export function resolveMissingMetaError(sessionKey: string): AcpRuntimeError {
);
}
/** Converts a session resolution union into the runtime error callers should throw. */
export function resolveAcpSessionResolutionError(
resolution: AcpSessionResolution,
): AcpRuntimeError | null {
@@ -41,6 +44,7 @@ export function resolveAcpSessionResolutionError(
);
}
/** Returns ready ACP metadata or throws the matching resolution error. */
export function requireReadySessionMeta(resolution: AcpSessionResolution): SessionAcpMeta {
if (resolution.kind === "ready") {
return resolution.meta;
@@ -52,6 +56,7 @@ function normalizeSessionKey(sessionKey: string): string {
return sessionKey.trim();
}
/** Canonicalizes aliases and main-session keys before ACP metadata lookup. */
export function canonicalizeAcpSessionKey(params: {
cfg: OpenClawConfig;
sessionKey: string;
@@ -79,10 +84,12 @@ export function canonicalizeAcpSessionKey(params: {
return lowered;
}
/** Normalizes session keys for process-local actor maps. */
export function normalizeActorKey(sessionKey: string): string {
return normalizeLowercaseStringOrEmpty(sessionKey);
}
/** Restricts runtime-provided error codes to the ACP error-code enum. */
export function normalizeAcpErrorCode(code: string | undefined): AcpRuntimeError["code"] {
if (!code) {
return "ACP_TURN_FAILED";
@@ -1,3 +1,4 @@
/** Tests runtime cache touch semantics and idle-candidate collection. */
import type { AcpRuntime } from "@openclaw/acp-core/runtime/types";
import type { AcpRuntimeHandle } from "@openclaw/acp-core/runtime/types";
import { describe, expect, it } from "vitest";
+3
View File
@@ -1,3 +1,4 @@
/** Small touch-aware cache for process-local ACP runtime handles. */
import type {
AcpRuntime,
AcpRuntimeHandle,
@@ -21,6 +22,7 @@ type RuntimeCacheEntry = {
lastTouchedAt: number;
};
/** Snapshot entry used for idle eviction and cache diagnostics. */
export type CachedRuntimeSnapshot = {
actorKey: string;
state: CachedRuntimeState;
@@ -28,6 +30,7 @@ export type CachedRuntimeSnapshot = {
idleMs: number;
};
/** Map-backed cache that tracks last-touch time per actor key. */
export class RuntimeCache {
private readonly cache = new Map<string, RuntimeCacheEntry>();
@@ -1,3 +1,4 @@
/** Tests runtime config-option serialization against advertised backend keys. */
import { describe, expect, it } from "vitest";
import { buildRuntimeConfigOptionPairs } from "./runtime-options.js";
+1
View File
@@ -1,3 +1,4 @@
/** Validation and normalization for ACP session runtime options and config controls. */
import { isAbsolute } from "node:path";
import { normalizeText } from "@openclaw/acp-core/normalize-text";
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
@@ -1,3 +1,4 @@
/** Per-session async queue wrapper used by ACP manager operations. */
import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
/** Per-session async queue that serializes ACP runtime operations and exposes queue depth. */
+3
View File
@@ -1,9 +1,11 @@
/** Cleanup helpers for failed ACP spawn flows. */
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { callGateway } from "../../gateway/call.js";
import { logVerbose } from "../../globals.js";
import { getSessionBindingService } from "../../infra/outbound/session-binding-service.js";
import { getAcpSessionManager } from "./manager.js";
/** Minimal runtime handle needed to close a just-created session during failed spawn cleanup. */
export type AcpSpawnRuntimeCloseHandle = {
runtime: {
close: (params: {
@@ -14,6 +16,7 @@ export type AcpSpawnRuntimeCloseHandle = {
handle: { sessionKey: string; backend: string; runtimeSessionName: string };
};
/** Best-effort cleanup for partially created ACP sessions, bindings, and transcripts. */
export async function cleanupFailedAcpSpawn(params: {
cfg: OpenClawConfig;
sessionKey: string;