UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

216 lines (215 loc) • 9.58 kB
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 };