UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

369 lines (368 loc) • 15.2 kB
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs"; import { t as formatErrorMessage } from "./errors-BvOkmQM5.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-DY3MOX4N.mjs"; import { h as parseAgentSessionKey, r as isAcpSessionKey, s as isSubagentSessionKey } from "./session-key-utils-CDyBC9Gn.mjs"; import { c as resolveSessionStorePathCore } from "./paths-Bonddxfk.mjs"; import { h as resolveSessionAgentId } from "./agent-scope-bJOokm5r.mjs"; import { l as getActiveAgentRunDelegatedAuthority } from "./agent-run-registry-Cm8FlLIi.mjs"; import { l as retireSessionMcpRuntime } from "./agent-bundle-mcp-manager-api-B24ukpdI.mjs"; import { r as logVerbose } from "./globals-yEiTitH8.mjs"; import { i as resolveCommandAuthorization } from "./command-auth-BHrKDij6.mjs"; import { o as loadSessionEntry } from "./session-accessor.sqlite-entry-DLa7_9ui.mjs"; import "./session-accessor-C3ljJ974.mjs"; import { c as resolveSessionAbortTarget, i as markSessionAbortTarget } from "./session-accessor.entry-mutation-telsi3Ig.mjs"; import { a as ACTIVE_EMBEDDED_RUNS_BY_RUN_ID, i as ACTIVE_EMBEDDED_RUNS, o as ACTIVE_EMBEDDED_RUN_REGISTRATIONS } from "./run-state-D054QiMr.mjs"; import { n as getAcpSessionManager } from "./manager-sn_kcSXp.mjs"; import { y as resolveReplyOperationsForSession } from "./reply-run-registry.registry-ICalZVvY.mjs"; import "./reply-run-registry-1HN3_KMU.mjs"; import { n as abortEmbeddedAgentRun } from "./runs-Qhulcs4s.mjs"; import { i as resolveActiveEmbeddedRunSessionId } from "./active-run-projections-TAxZeJ_S.mjs"; import "./sessions-CRUJeu5H.mjs"; import { t as resolveEffectiveResetTargetSessionKey } from "./acp-reset-target-j7GMtDbc.mjs"; import { s as resolveSessionConversationBindingContext } from "./session-conversation-binding-Ct7uOkBw.mjs"; import { o as resolveInternalSessionKey, s as resolveMainSessionAlias } from "./sessions-resolution-DvbCWXwD.mjs"; import "./sessions-helpers-CA0CJ1ys.mjs"; import { r as captureExecRequestSubagentSelection } from "./subagent-control-scope-BK6Z23s2.mjs"; import { n as captureExecRequestCancellation } from "./bash-process-control-CcTL6Huf.mjs"; import { t as killAllControlledSubagentRuns } from "./subagent-control-kill-BF4IB_0r.mjs"; import { a as prepareSessionLifecycleQueueCleanup } from "./cleanup-BBmMSpbZ.mjs"; import "./subagent-control-CpvtvvWe.mjs"; import { a as shouldPersistAbortCutoff, i as resolveAbortCutoffFromContext } from "./abort-cutoff-Cy_3zrWp.mjs"; import { r as setAbortMemory } from "./abort-primitives-BWGbzk7d.mjs"; //#region src/agents/embedded-agent-runner/runs.abort-target.ts /** Follow admitted retries while keeping legacy compaction bound to its exact handle. */ function prepareEmbeddedAgentRunAbort(sessionId) { const handle = ACTIVE_EMBEDDED_RUNS.get(sessionId); const registration = handle && ACTIVE_EMBEDDED_RUN_REGISTRATIONS.get(handle); const instance = registration?.operationalRunInstance; const authority = registration?.delegatedAuthority; const agentId = registration?.agentId; const sessionKey = registration?.sessionKey; const resolveCurrent = () => { if (!handle || !registration) return; if (!instance || !authority) return ACTIVE_EMBEDDED_RUNS.get(sessionId) === handle && ACTIVE_EMBEDDED_RUN_REGISTRATIONS.get(handle) === registration ? registration : void 0; if (getActiveAgentRunDelegatedAuthority(instance) !== authority) return; const successor = ACTIVE_EMBEDDED_RUNS_BY_RUN_ID.get(instance.runId); const current = successor && ACTIVE_EMBEDDED_RUN_REGISTRATIONS.get(successor); return current && current.operationalRunInstance?.instanceId === instance.instanceId && current.operationalRunInstance.runId === instance.runId && current.delegatedAuthority === authority && current.agentId === agentId && current.sessionKey === sessionKey && ACTIVE_EMBEDDED_RUNS.get(current.sessionId) === successor ? current : void 0; }; return () => { const current = resolveCurrent(); return current ? { active: true, aborted: abortEmbeddedAgentRun(current.sessionId), sessionId: current.sessionId } : { active: false, aborted: false }; }; } //#endregion //#region src/auto-reply/reply/abort-operation.ts function prepareSessionRunTargetAbort(params) { const key = normalizeOptionalString(params.key); const operations = resolveReplyOperationsForSession({ ...params, sessionKeys: key ? [key] : [] }); const sessionIds = new Set(operations.map((operation) => operation.sessionId)); const explicitSessionId = normalizeOptionalString(params.sessionId); const commands = key || explicitSessionId ? captureExecRequestCancellation({ sessionKey: key, sessionId: explicitSessionId, agentId: params.agentId }) : void 0; if (explicitSessionId) sessionIds.add(explicitSessionId); if (key) { const activeSessionId = resolveActiveEmbeddedRunSessionId(key); if (activeSessionId && (sessionIds.has(activeSessionId) || parseAgentSessionKey(key)?.agentId === normalizeAgentId(params.agentId))) sessionIds.add(activeSessionId); } const runs = [...sessionIds].map(prepareEmbeddedAgentRunAbort); return () => { let active = operations.some((operation) => !operation.result); const failures = []; let aborted = commands?.cancel() === true; for (const operation of operations) { for (const sessionId of operation.captureOwnedSessionIds()) sessionIds.add(sessionId); try { aborted = operation.abortByUser() || aborted; } catch (error) { failures.push(error); } } for (const run of runs) try { const outcome = run(); active ||= outcome.active; aborted ||= outcome.aborted; if (outcome.sessionId) sessionIds.add(outcome.sessionId); } catch (error) { failures.push(error); } const retirement = !active || aborted || failures.length > 0 ? Promise.allSettled([...[...sessionIds].map((sessionId) => retireSessionMcpRuntime({ sessionId, reason: "session-stop", preserveActiveLeases: true })), commands?.settle()]).then((results) => { for (const result of results) if (result.status === "rejected") failures.push(result.reason); if (failures.length === 1) throw failures[0]; if (failures.length > 1) throw new AggregateError(failures, failures.map(formatErrorMessage).join("; ")); }) : void 0; return { active, aborted, retirement }; }; } function resolveStoredSessionId(params) { const storePath = resolveSessionStorePathCore(params.cfg.session?.store, { agentId: params.agentId }); try { return loadSessionEntry({ agentId: params.agentId, clone: false, sessionKey: params.sessionKey, storePath })?.sessionId; } catch { return; } } async function stopSubagentsForRequester(params) { const cleaned = normalizeOptionalString(params.requesterSessionKey); if (!cleaned) { await params.beforeKill?.(() => {}); return { stopped: 0, failed: 0 }; } const { alias } = resolveMainSessionAlias(params.cfg); const requesterKey = resolveInternalSessionKey({ key: cleaned, alias }); const controllerAgentId = resolveSessionAgentId({ config: params.cfg, sessionKey: requesterKey, fallbackAgentId: params.requesterAgentId }); const controller = { controllerSessionKey: requesterKey, controllerAgentId, callerSessionKey: requesterKey, callerIsSubagent: isSubagentSessionKey(requesterKey), controlScope: "children" }; const commands = captureExecRequestCancellation({ sessionKey: requesterKey, agentId: controllerAgentId }); const requestSelection = captureExecRequestSubagentSelection({ cfg: params.cfg, controller, owners: commands.owners, sessionOrigin: params.requesterSession ? { target: { ...params.requesterSession, sessionKey: requesterKey, agentId: controllerAgentId }, acceptsRequest: () => true } : void 0 }); const result = await killAllControlledSubagentRuns({ cfg: params.cfg, controller, runs: requestSelection.runs, requestSelection, assertCurrent: params.assertCurrent, suppressTaskDelivery: true, beforeKill: params.beforeKill }); if (result.status === "error") logVerbose(`abort: failed to stop subagents for ${requesterKey}: ${result.error}`); if (result.killed > 0) logVerbose(`abort: stopped ${result.killed} subagent run(s) for ${requesterKey}`); return { stopped: result.killed, failed: result.status === "error" ? result.failed : 0, ...result.execAborted ? { execAborted: true } : {} }; } async function executeFastAbortRequest(params, request) { const { ctx, cfg } = params; const { commandSessionKey, targetKey, resolveTargetAgentId } = request; const auth = resolveCommandAuthorization({ ctx, cfg, commandAuthorized: ctx.CommandAuthorized }); if (!auth.isAuthorizedSender) return { handled: false, aborted: false }; const agentId = resolveTargetAgentId(); const abortKey = targetKey ?? auth.from ?? auth.to; const requesterSessionKey = targetKey ?? ctx.SessionKey ?? abortKey; if (targetKey) { const storePath = resolveSessionStorePathCore(cfg.session?.store, { agentId }); const abortCutoffForTarget = (target) => shouldPersistAbortCutoff({ commandSessionKey, targetSessionKey: target.sessionKey }) ? resolveAbortCutoffFromContext(ctx) : void 0; let resolvedAbortTarget = null; try { resolvedAbortTarget = resolveSessionAbortTarget({ agentId, sessionKey: targetKey, storePath }); } catch (error) { logVerbose(`abort: failed to resolve abort metadata for ${targetKey}: ${formatErrorMessage(error)}`); } const resolvedTargetKey = resolvedAbortTarget?.sessionKey ?? targetKey; const assertCurrent = () => { if (params.isCommandTargetCurrent?.() === false) throw new Error("The selected session changed before it could be stopped."); }; const prepareTarget = (key) => { const targetAgentId = key === resolvedTargetKey ? agentId : resolveSessionAgentId({ config: cfg, sessionKey: key, fallbackAgentId: ctx.AgentId ?? agentId }); const sessionId = resolveReplyOperationsForSession({ sessionKeys: [key], agentId: targetAgentId })[0]?.sessionId ?? (key === resolvedTargetKey ? resolvedAbortTarget?.sessionId : resolveStoredSessionId({ cfg, sessionKey: key, agentId: targetAgentId })); const target = { key, agentId: targetAgentId, sessionId }; return { abort: prepareSessionRunTargetAbort(target), clearQueues: prepareSessionLifecycleQueueCleanup({ ...target, keys: [key, sessionId], sessionKey: key, assertCurrent }) }; }; const preparedTargets = new Map([resolvedTargetKey, ...commandSessionKey ? [commandSessionKey] : []].map((key) => [key, prepareTarget(key)])); let aborted = false; let activeAbortRejected = false; const acpCancellations = []; try { const { stopped, failed, execAborted } = await stopSubagentsForRequester({ cfg, requesterSessionKey, requesterAgentId: agentId, requesterSession: resolvedAbortTarget?.sessionId ? { storePath, sessionId: resolvedAbortTarget.sessionId, lifecycleRevision: resolvedAbortTarget.entry.lifecycleRevision ?? null } : void 0, assertCurrent, beforeKill: async (sealRootSelection) => { assertCurrent(); const bindingContext = commandSessionKey ? resolveSessionConversationBindingContext(cfg, ctx) : void 0; const conversationBoundAcpTargetKey = commandSessionKey ? await (bindingContext ? resolveEffectiveResetTargetSessionKey({ cfg, ...bindingContext, activeSessionKey: commandSessionKey, skipConfiguredFallbackWhenActiveSessionNonAcp: false, fallbackToActiveAcpWhenUnbound: false }) : void 0) : void 0; const boundAcpTargetKey = !isAcpSessionKey(resolvedTargetKey) ? conversationBoundAcpTargetKey : void 0; const abortTargetKeys = [resolvedTargetKey]; if (boundAcpTargetKey && boundAcpTargetKey !== resolvedTargetKey) abortTargetKeys.push(boundAcpTargetKey); const sourceAbortKey = commandSessionKey && !abortTargetKeys.includes(commandSessionKey) && conversationBoundAcpTargetKey && abortTargetKeys.includes(conversationBoundAcpTargetKey) ? commandSessionKey : void 0; const targets = [...abortTargetKeys, ...sourceAbortKey ? [sourceAbortKey] : []].map((key) => preparedTargets.get(key) ?? prepareTarget(key)); assertCurrent(); sealRootSelection(); try { for (const target of targets) { const cleared = target.clearQueues(); if (cleared.followupCleared > 0 || cleared.laneCleared > 0) logVerbose(`abort: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`); } for (const target of targets) { const outcome = target.abort(); if (outcome.retirement) { outcome.retirement.catch(() => {}); acpCancellations.push(outcome.retirement); } activeAbortRejected ||= outcome.active && !outcome.aborted; aborted = outcome.aborted || aborted; } } finally { const acpManager = getAcpSessionManager(); for (const acpTargetKey of abortTargetKeys) { const resolution = acpManager.resolveSession({ cfg, sessionKey: acpTargetKey, agentId: acpTargetKey === resolvedTargetKey ? agentId : void 0 }); if (resolution.kind === "none") continue; acpCancellations.push(acpManager.cancelSession({ cfg, sessionKey: resolution.sessionKey, agentId: resolution.agentId, reason: "fast-abort" }).catch((error) => { logVerbose(`abort: ACP cancel failed for ${acpTargetKey}: ${formatErrorMessage(error)}`); })); } } return true; } }); aborted ||= execAborted === true; const rejectionReason = activeAbortRejected && !aborted ? "finalizing" : void 0; if (!rejectionReason) { let persistedAbortTarget = null; try { persistedAbortTarget = await markSessionAbortTarget({ isCurrent: params.isCommandTargetCurrent, expectedTarget: resolvedAbortTarget?.entry ?? null, scope: { agentId, sessionKey: targetKey, storePath }, resolveAbortCutoff: abortCutoffForTarget }); } catch (error) { logVerbose(`abort: failed to persist abort metadata for ${targetKey}: ${formatErrorMessage(error)}`); } if (persistedAbortTarget?.persisted === false) logVerbose(`abort: failed to persist abort metadata for ${targetKey}: ${persistedAbortTarget.persistenceError ?? "unknown error"}`); } return { handled: true, aborted, ...rejectionReason ? { rejectionReason } : {}, stoppedSubagents: stopped, failedSubagents: failed }; } finally { await Promise.all(acpCancellations); } } if (abortKey) setAbortMemory(abortKey, true); const { stopped, failed, execAborted } = await stopSubagentsForRequester({ cfg, requesterSessionKey }); return { handled: true, aborted: execAborted === true, stoppedSubagents: stopped, failedSubagents: failed }; } //#endregion export { prepareSessionRunTargetAbort as n, stopSubagentsForRequester as r, executeFastAbortRequest as t };