openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
216 lines (215 loc) • 9.58 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { o as resolveUserPath } from "./home-dir-Dc6nN6HB.mjs";
import { r as isMissingPathError } from "./errno-FR4CRyya.mjs";
import "./utils-CitNzLyF.mjs";
import "./errors-BvOkmQM5.mjs";
import { c as resolveSessionStorePathCore } from "./paths-Bonddxfk.mjs";
import { r as resolveAgentConfig } from "./agent-scope-config-BEk6-ThS.mjs";
import { t as splitTrailingAuthProfile } from "./model-ref-profile-BNjB2hED.mjs";
import "./agent-scope-bJOokm5r.mjs";
import { r as logVerbose } from "./globals-yEiTitH8.mjs";
import { n as formatThinkingLevels } from "./thinking-7OesKvXK.mjs";
import { n as resolveConfiguredSubagentSpawnModelSelection } from "./model-selection-Cpoq0B2R.mjs";
import { r as resolveThinkingDefaultCore } from "./model-thinking-default-Cepu2GOi.mjs";
import { v as runExclusiveSessionLifecycleMutation } from "./session-lifecycle-admission-B5CJ-emz.mjs";
import { o as loadSessionEntry } from "./session-accessor.sqlite-entry-DLa7_9ui.mjs";
import "./session-accessor-C3ljJ974.mjs";
import { i as resolveAcpThreadSessionDetailLines, n as resolveAcpSessionCwd } from "./session-identifiers-2CkhpQUq.mjs";
import { c as isAcpOwnerRepairRequired, n as getAcpSessionManager } from "./manager-sn_kcSXp.mjs";
import { t as getSessionBindingService } from "./session-binding-service-wvWqRl2A.mjs";
import { n as resolveSandboxRuntimeStatus } from "./runtime-status-BBzhhE6k.mjs";
import { a as getInProcessGatewayToolContext, c as runWithGatewayToolCleanupContext, r as callInProcessGatewayTool } from "./in-process-gateway-BYRZzLBf.mjs";
import { a as resolveSubagentThinkingOverride, d as resolveSpawnSandboxError, h as resolveSenderRestrictedSpawnError, i as splitModelRef, t as buildSpawnThreadBinding } from "./spawn-thread-binding-CxKbcyi_.mjs";
import fs from "node:fs/promises";
//#region src/acp/control-plane/spawn.ts
/** Cleanup helpers for failed ACP spawn flows. */
/** Roll back only the provisional session owned by this failed spawn. */
async function cleanupFailedAcpSpawn(params) {
if (!params.sessionEntry) return;
const { sessionId, lifecycleRevision } = params.sessionEntry;
const storePath = resolveSessionStorePathCore(params.cfg.session?.store, { agentId: params.agentId });
const assertCurrent = () => {
const current = loadSessionEntry({
storePath,
sessionKey: params.sessionKey,
agentId: params.agentId,
clone: false
});
if (current?.sessionId !== sessionId || current?.lifecycleRevision !== lifecycleRevision) throw new Error(`ACP provisional session ${params.sessionKey} changed before cleanup.`);
};
let deletionStarted = false;
let deletionExecution;
const cancellation = new AbortController();
try {
await runWithGatewayToolCleanupContext(async () => {
assertCurrent();
const context = getInProcessGatewayToolContext();
if (!context) throw new Error("ACP provisional cleanup Gateway is unavailable.");
await callInProcessGatewayTool("sessions.delete", {
key: params.sessionKey,
agentId: params.agentId,
expectedSessionId: sessionId,
...lifecycleRevision ? { expectedLifecycleRevision: lifecycleRevision } : {},
deleteTranscript: params.deleteTranscript,
emitLifecycleHooks: false
}, {
onExecution: (execution) => {
deletionExecution = execution;
},
sessionMutationCommitGuard: () => {
cancellation.signal.throwIfAborted();
context.requestEntryLifetime?.signal.throwIfAborted();
assertCurrent();
deletionStarted = true;
},
signal: cancellation.signal,
timeoutMs: 1e4
});
});
} catch (error) {
if (!deletionStarted) cancellation.abort(error);
if (!deletionStarted && params.closeRuntimeOnFailure) await runExclusiveSessionLifecycleMutation("acp-spawn-cleanup", {
scope: storePath,
identities: [params.sessionKey, sessionId],
run: async () => {
assertCurrent();
await params.closeRuntimeOnFailure();
}
}).catch((releaseError) => {
if (isAcpOwnerRepairRequired(releaseError)) throw releaseError;
logVerbose(`acp-spawn: provisional runtime cleanup failed: ${String(releaseError)}`);
});
logVerbose(`acp-spawn: provisional session cleanup failed: ${String(error)}`);
} finally {
if (deletionStarted) await deletionExecution;
}
}
//#endregion
//#region src/agents/subagents/spawn/acp-spawn-policy.ts
function resolveAcpSpawnRuntimePolicyError(params) {
const requesterRuntime = resolveSandboxRuntimeStatus({
cfg: params.cfg,
sessionKey: params.requesterSessionKey,
agentId: params.requesterAgentId
});
return resolveSpawnSandboxError({
backend: "acp",
requesterSandboxed: params.requesterSandboxed === true || requesterRuntime.sandboxed,
sandbox: params.sandbox === "require" ? "require" : "inherit"
});
}
function resolveAcpSenderSpawnError(params) {
const targetError = resolveSenderRestrictedSpawnError(params);
if (targetError) return targetError;
if (params.inheritedToolPolicySource !== "sender") return;
const root = params.sessionPermissionPolicy?.root ?? params.workspaceDir;
return params.sessionPermissionPolicy && params.sessionPermissionPolicy.mode !== "full" || !root || params.cwd && resolveUserPath(params.cwd) !== resolveUserPath(root) ? `ACP cannot preserve this sender's session root restrictions. Use runtime="subagent" without a cwd override.` : void 0;
}
//#endregion
//#region src/agents/subagents/spawn/acp-spawn-runtime.ts
const ACP_RUNTIME_TIMEOUT_MAX_SECONDS = 86400;
async function resolveRuntimeCwdForAcpSpawn(params) {
if (!params.resolvedCwd) return;
if (normalizeOptionalString(params.explicitCwd)) return params.resolvedCwd;
try {
await fs.access(params.resolvedCwd);
return params.resolvedCwd;
} catch (error) {
if (isMissingPathError(error)) return;
throw error;
}
}
function resolveAcpSpawnRuntimeOptions(params) {
const policyAgentId = params.configAgentId ?? params.targetAgentId;
const modelExplicit = normalizeOptionalString(params.model) !== void 0;
const thinkingExplicit = normalizeOptionalString(params.thinking) !== void 0;
const rawModel = resolveConfiguredSubagentSpawnModelSelection({
cfg: params.cfg,
agentId: policyAgentId,
modelOverride: params.model,
modelRuntime: "acp"
});
const modelSelection = splitTrailingAuthProfile(rawModel ?? "");
if (modelExplicit && modelSelection.profile) return {
ok: false,
error: "ACP model overrides cannot select OpenClaw auth profiles; configure credentials in the ACP runtime instead."
};
const model = modelSelection.model || void 0;
const targetAgentConfig = resolveAgentConfig(params.cfg, policyAgentId);
const thinkingPlan = resolveSubagentThinkingOverride({
cfg: params.cfg,
targetAgentConfig,
thinkingOverrideRaw: params.thinking
});
if (thinkingPlan.status === "error") {
const { provider, model: modelId } = splitModelRef(model);
return {
ok: false,
error: `Invalid thinking level "${thinkingPlan.thinkingCandidateRaw}". Use one of: ${formatThinkingLevels(provider, modelId)}.`
};
}
let thinking = thinkingPlan.thinkingOverride;
if (!thinking) {
const { provider, model: modelId } = splitModelRef(model);
thinking = provider && modelId ? resolveThinkingDefaultCore({
cfg: params.cfg,
agentId: policyAgentId,
provider,
model: modelId
}) : targetAgentConfig?.thinkingDefault;
}
const timeoutSeconds = params.runTimeoutSeconds ? Math.min(params.runTimeoutSeconds, ACP_RUNTIME_TIMEOUT_MAX_SECONDS) : void 0;
return {
ok: true,
runtimeOptions: model || thinking || timeoutSeconds ? {
...model ? { model } : {},
...thinking ? { thinking } : {},
...timeoutSeconds ? { timeoutSeconds } : {}
} : void 0,
modelExplicit,
thinkingExplicit
};
}
async function initializeAcpSpawnRuntime(params) {
params.assertActive?.();
const initialized = await getAcpSessionManager().initializeSession({
assertActive: params.assertActive,
cfg: params.cfg,
sessionKey: params.sessionKey,
agentId: params.ownerAgentId,
agent: params.runtimeAgentId,
mode: params.runtimeMode,
resumeSessionId: params.resumeSessionId,
revalidateResume: params.revalidateResume,
runtimeOptions: params.runtimeOptions,
modelExplicit: params.modelExplicit,
thinkingExplicit: params.thinkingExplicit,
cwd: params.cwd,
backendId: params.backendId
});
return {
initialized,
sessionId: initialized.sessionEntry.sessionId,
sessionEntry: initialized.sessionEntry
};
}
async function bindPreparedAcpThread(params) {
const binding = await getSessionBindingService().bind(buildSpawnThreadBinding({
cfg: params.cfg,
sessionKey: params.sessionKey,
targetKind: "session",
agentId: params.targetAgentId,
label: params.label,
binding: params.preparedBinding,
sessionCwd: resolveAcpSessionCwd(params.initializedRuntime.initialized.meta),
sessionDetails: resolveAcpThreadSessionDetailLines({
sessionKey: params.sessionKey,
meta: params.initializedRuntime.initialized.meta
})
}));
params.assertActive?.();
if (!binding.conversation.conversationId) throw new Error(params.preparedBinding.placement === "child" ? `Failed to create and bind a ${params.preparedBinding.channel} thread for this ACP session.` : `Failed to bind the current ${params.preparedBinding.channel} conversation for this ACP session.`);
return binding;
}
//#endregion
export { resolveAcpSenderSpawnError as a, resolveRuntimeCwdForAcpSpawn as i, initializeAcpSpawnRuntime as n, resolveAcpSpawnRuntimePolicyError as o, resolveAcpSpawnRuntimeOptions as r, cleanupFailedAcpSpawn as s, bindPreparedAcpThread as t };