UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

296 lines (295 loc) 12.7 kB
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js"; import { S as isAcpSessionKey, T as isSubagentSessionKey } from "./session-key-BnWWjqNc.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js"; import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js"; import { r as logVerbose } from "./globals-CTaGxEqj.js"; import { r as resolveCommandAuthorization } from "./command-auth-DRYzLgCh.js"; import { bt as resolveSessionAbortTarget, yt as markSessionAbortTarget } from "./session-accessor-YsytfDtG.js"; import { l as loadSessionEntry } from "./session-accessor.sqlite-entry-CWk3jL7s.js"; import { t as getAcpSessionManager } from "./manager-Bbp2Ogkb.js"; import { i as setAbortMemory, n as isAbortRequestText } from "./abort-primitives-pmK4VR6Y.js"; import { h as replyRunRegistry } from "./reply-run-registry.registry-BMo0d96L.js"; import "./reply-run-registry-BlmBKV23.js"; import { n as abortEmbeddedAgentRun } from "./runs-Cb42qain.js"; import { i as resolveActiveEmbeddedRunSessionId } from "./active-run-projections-C4mdt8WG.js"; import "./sessions-9nxpeTwt.js"; import { i as resolveConversationBindingContextFromMessage } from "./conversation-binding-input-BzjT8SWv.js"; import { m as resolveMainSessionAlias, p as resolveInternalSessionKey } from "./sessions-helpers-B2gzzr60.js"; import { h as listSubagentRunsForController } from "./subagent-registry-read-DeFf_9Nz.js"; import { t as killAllControlledSubagentRuns } from "./subagent-control-Cm3eFdYX.js"; import { t as clearSessionQueues } from "./cleanup-DKkilV3a.js"; import "./queue-BpaiO3X2.js"; import { a as stripMentions, o as stripStructuralPrefixes } from "./mentions-BXIDEOtX.js"; import { a as shouldPersistAbortCutoff, i as resolveAbortCutoffFromContext } from "./abort-cutoff-BxM8jmK3.js"; import { t as resolveEffectiveResetTargetSessionKey } from "./acp-reset-target-Cuv8dYQz.js"; //#region src/auto-reply/reply/abort.ts function abortSessionRunTargetWithOutcome(params) { const sessionIds = /* @__PURE__ */ new Set(); const key = normalizeOptionalString(params.key); let active = key ? replyRunRegistry.isActive(key) : false; if (key) { const activeSessionId = resolveActiveEmbeddedRunSessionId(key); if (activeSessionId) { active = true; sessionIds.add(activeSessionId); } } const explicitSessionId = normalizeOptionalString(params.sessionId); if (explicitSessionId) sessionIds.add(explicitSessionId); let aborted = key ? replyRunRegistry.abort(key) : false; for (const sessionId of sessionIds) aborted = abortEmbeddedAgentRun(sessionId) || aborted; return { active, aborted }; } function formatAbortReplyText(stoppedSubagents, rejectionReason, failedSubagents) { const failureSuffix = typeof failedSubagents === "number" && failedSubagents > 0 ? ` Cancellation was incomplete for ${failedSubagents} sub-agent${failedSubagents === 1 ? "" : "s"}. Retry /stop.` : ""; if (rejectionReason === "finalizing") { const base = "Agent reply is already finalizing and can no longer be aborted."; if (typeof stoppedSubagents !== "number" || stoppedSubagents <= 0) return `${base}${failureSuffix}`; return `${base} Stopped ${stoppedSubagents} ${stoppedSubagents === 1 ? "sub-agent" : "sub-agents"}.${failureSuffix}`; } if (typeof stoppedSubagents !== "number" || stoppedSubagents <= 0) return `⚙️ Agent was aborted.${failureSuffix}`; return `⚙️ Agent was aborted. Stopped ${stoppedSubagents} ${stoppedSubagents === 1 ? "sub-agent" : "sub-agents"}.${failureSuffix}`; } function resolveStoredSessionId(params) { const agentId = resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }); const storePath = resolveSessionStorePathCore(params.cfg.session?.store, { agentId }); try { return loadSessionEntry({ agentId, clone: false, sessionKey: params.sessionKey, storePath })?.sessionId; } catch { return; } } function resolveBoundAcpAbortTargetSessionKey(params) { const bindingContext = resolveConversationBindingContextFromMessage({ cfg: params.cfg, ctx: params.ctx }); if (!bindingContext) return; return resolveEffectiveResetTargetSessionKey({ cfg: params.cfg, channel: bindingContext.channel, accountId: bindingContext.accountId, conversationId: bindingContext.conversationId, parentConversationId: bindingContext.parentConversationId, activeSessionKey: params.activeSessionKey, skipConfiguredFallbackWhenActiveSessionNonAcp: false, fallbackToActiveAcpWhenUnbound: false }); } function normalizeRequesterSessionKey(cfg, key) { const cleaned = normalizeOptionalString(key); if (!cleaned) return; const { mainKey, alias } = resolveMainSessionAlias(cfg); return resolveInternalSessionKey({ key: cleaned, alias, mainKey }); } async function stopSubagentsForRequester(params) { const requesterKey = normalizeRequesterSessionKey(params.cfg, params.requesterSessionKey); if (!requesterKey) { await params.beforeKill?.(); return { stopped: 0, failed: 0 }; } const controllerAgentId = resolveSessionAgentId({ config: params.cfg, sessionKey: requesterKey, fallbackAgentId: params.requesterAgentId }); const result = await killAllControlledSubagentRuns({ cfg: params.cfg, controller: { controllerSessionKey: requesterKey, controllerAgentId, callerSessionKey: requesterKey, callerIsSubagent: isSubagentSessionKey(requesterKey), controlScope: "children" }, runs: listSubagentRunsForController(requesterKey), 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 }; } async function tryFastAbortFromMessage(params) { const { ctx, cfg } = params; const commandSessionKey = normalizeOptionalString(ctx.SessionKey) ?? normalizeOptionalString(ctx.ParentSessionKey); const targetKey = normalizeOptionalString(ctx.CommandTargetSessionKey) ?? commandSessionKey; const raw = stripStructuralPrefixes(ctx.commandText); const stripped = normalizeOptionalLowercaseString(ctx.ChatType) === "group" ? stripMentions(raw, ctx, cfg, resolveSessionAgentId({ sessionKey: targetKey ?? ctx.SessionKey ?? "", config: cfg })) : raw; if (!isAbortRequestText(stripped)) return { handled: false, aborted: false }; const commandAuthorized = ctx.CommandAuthorized; const auth = resolveCommandAuthorization({ ctx, cfg, commandAuthorized }); if (!auth.isAuthorizedSender) return { handled: false, aborted: false }; const agentId = resolveSessionAgentId({ sessionKey: targetKey ?? ctx.SessionKey ?? "", config: cfg, fallbackAgentId: ctx.AgentId }); 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 conversationBoundAcpTargetKey = commandSessionKey ? resolveBoundAcpAbortTargetSessionKey({ ctx, cfg, activeSessionKey: commandSessionKey }) : void 0; const boundAcpTargetKey = !isAcpSessionKey(resolvedTargetKey) ? conversationBoundAcpTargetKey : void 0; const abortTargetKeys = [resolvedTargetKey]; if (boundAcpTargetKey && boundAcpTargetKey !== resolvedTargetKey) abortTargetKeys.push(boundAcpTargetKey); let aborted = false; let activeAbortRejected = false; const acpCancellations = []; try { const { stopped, failed } = await stopSubagentsForRequester({ cfg, requesterSessionKey, requesterAgentId: agentId, beforeKill: () => { if (params.isCommandTargetCurrent?.() === false) throw new Error("The selected session changed before it could be stopped."); try { const sourceAbortKey = commandSessionKey && !abortTargetKeys.includes(commandSessionKey) && conversationBoundAcpTargetKey && abortTargetKeys.includes(conversationBoundAcpTargetKey) ? commandSessionKey : void 0; const sessionIdsByKey = new Map(abortTargetKeys.map((abortTargetKey) => [abortTargetKey, replyRunRegistry.resolveSessionId(abortTargetKey) ?? (abortTargetKey === resolvedTargetKey ? resolvedAbortTarget?.sessionId : resolveStoredSessionId({ cfg, sessionKey: abortTargetKey }))])); for (const abortTargetKey of abortTargetKeys) { const outcome = abortSessionRunTargetWithOutcome({ key: abortTargetKey, sessionId: sessionIdsByKey.get(abortTargetKey) }); activeAbortRejected ||= outcome.active && !outcome.aborted; aborted = outcome.aborted || aborted; } const sourceSessionId = sourceAbortKey ? replyRunRegistry.resolveSessionId(sourceAbortKey) ?? resolveStoredSessionId({ cfg, sessionKey: sourceAbortKey }) : void 0; if (sourceAbortKey) { const outcome = abortSessionRunTargetWithOutcome({ key: sourceAbortKey, sessionId: sourceSessionId }); activeAbortRejected ||= outcome.active && !outcome.aborted; aborted = outcome.aborted || aborted; } const cleared = clearSessionQueues(abortTargetKeys.flatMap((abortTargetKey) => [abortTargetKey, sessionIdsByKey.get(abortTargetKey)]).concat(sourceAbortKey, sourceSessionId)); if (cleared.followupCleared > 0 || cleared.laneCleared > 0) logVerbose(`abort: cleared followups=${cleared.followupCleared} lane=${cleared.laneCleared} keys=${cleared.keys.join(",")}`); } 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; } }); const rejectionReason = activeAbortRejected && !aborted ? "finalizing" : void 0; if (!rejectionReason) { let persistedAbortTarget = null; try { persistedAbortTarget = await markSessionAbortTarget({ isCurrent: params.isCommandTargetCurrent, 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"}`); const abortMemoryKey = persistedAbortTarget?.sessionKey ?? resolvedAbortTarget?.sessionKey ?? abortKey; const hasAbortTargetEntry = Boolean(persistedAbortTarget?.entry ?? resolvedAbortTarget?.entry); if (persistedAbortTarget?.persisted !== true && abortMemoryKey && !hasAbortTargetEntry && params.isCommandTargetCurrent?.() !== false) setAbortMemory(abortMemoryKey, true); } return { handled: true, aborted, ...rejectionReason ? { rejectionReason } : {}, stoppedSubagents: stopped, failedSubagents: failed }; } finally { await Promise.all(acpCancellations); } } if (abortKey) setAbortMemory(abortKey, true); const { stopped, failed } = await stopSubagentsForRequester({ cfg, requesterSessionKey }); return { handled: true, aborted: false, stoppedSubagents: stopped, failedSubagents: failed }; } //#endregion export { tryFastAbortFromMessage as i, formatAbortReplyText as n, stopSubagentsForRequester as r, abortSessionRunTargetWithOutcome as t };