UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

278 lines (277 loc) 12.1 kB
import { c as normalizeOptionalString, s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js"; import { i as formatErrorMessage } from "./errors-BXgSefBE.js"; import { v as resolveSessionAgentId } from "./agent-scope-MrLta7Pq.js"; import { c as parseAgentSessionKey, n as isAcpSessionKey } from "./session-key-utils-Bx3apsJ3.js"; import { r as logVerbose } from "./globals-GTrXU4s9.js"; import { u as resolveStorePath } from "./paths-NEwU8m3X.js"; import { V as resolveSessionStoreEntry, t as loadSessionStore } from "./store-load-C4uq6Lrq.js"; import { d as updateSessionStore } from "./store-Qsgtu-0y.js"; import "./sessions-D6zZvoxX.js"; import { t as getAcpSessionManager } from "./manager-D3LiuKaT.js"; import { i as setAbortMemory, n as isAbortRequestText } from "./abort-primitives-CNNnD8oN.js"; import { m as replyRunRegistry } from "./reply-run-registry-C88rqJxg.js"; import { _ as resolveActiveEmbeddedRunSessionId, n as abortEmbeddedAgentRun } from "./runs-B4dP_Q30.js"; import { c as resolveMainSessionAlias, s as resolveInternalSessionKey } from "./sessions-helpers-hMXef98o.js"; import { a as clearSessionQueues } from "./queue-CTB_l5oT.js"; import { f as listSubagentRunsForController, m as markSubagentRunTerminated, s as getLatestSubagentRunByChildSessionKey } from "./subagent-registry-BeWX0MLH.js"; import { i as resolveConversationBindingContextFromMessage } from "./conversation-binding-input-DT_BtDDW.js"; import { o as stripMentions, s as stripStructuralPrefixes } from "./mentions-Be0DZkGs.js"; import { t as resolveCommandAuthorization } from "./command-auth-CrEtnLva.js"; import { a as shouldPersistAbortCutoff, i as resolveAbortCutoffFromContext, t as applyAbortCutoffToSessionEntry } from "./abort-cutoff-fnVhj49B.js"; import { t as resolveEffectiveResetTargetSessionKey } from "./acp-reset-target-B4jtVDf6.js"; const abortDeps = { getAcpSessionManager, abortEmbeddedAgentRun, resolveActiveEmbeddedRunSessionId, getLatestSubagentRunByChildSessionKey, listSubagentRunsForController, markSubagentRunTerminated }; function abortSessionRunTarget(params) { const sessionIds = /* @__PURE__ */ new Set(); const key = normalizeOptionalString(params.key); if (key) { const activeSessionId = abortDeps.resolveActiveEmbeddedRunSessionId(key); if (activeSessionId) 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 = abortDeps.abortEmbeddedAgentRun(sessionId) || aborted; return aborted; } function formatAbortReplyText(stoppedSubagents) { if (typeof stoppedSubagents !== "number" || stoppedSubagents <= 0) return "⚙️ Agent was aborted."; return `⚙️ Agent was aborted. Stopped ${stoppedSubagents} ${stoppedSubagents === 1 ? "sub-agent" : "sub-agents"}.`; } function resolveSessionEntryForKey(store, sessionKey) { if (!store || !sessionKey) return {}; const resolved = resolveSessionStoreEntry({ store, sessionKey }); if (resolved.existing) return resolved.legacyKeys.length > 0 ? { entry: resolved.existing, key: resolved.normalizedKey, legacyKeys: resolved.legacyKeys } : { entry: resolved.existing, key: resolved.normalizedKey }; return {}; } function resolveStoredSessionId(params) { const agentId = resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }); const storePath = resolveStorePath(params.cfg.session?.store, { agentId }); try { return resolveSessionEntryForKey(loadSessionStore(storePath), params.sessionKey).entry?.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 }); } function stopSubagentsForRequester(params) { const requesterKey = normalizeRequesterSessionKey(params.cfg, params.requesterSessionKey); if (!requesterKey) return { stopped: 0 }; const dedupedRunsByChildKey = /* @__PURE__ */ new Map(); for (const run of abortDeps.listSubagentRunsForController(requesterKey)) { const childKey = normalizeOptionalString(run.childSessionKey); if (!childKey) continue; const latest = abortDeps.getLatestSubagentRunByChildSessionKey(childKey); if (!latest) { const existing = dedupedRunsByChildKey.get(childKey); if (!existing || run.createdAt >= existing.createdAt) dedupedRunsByChildKey.set(childKey, run); continue; } const latestControllerSessionKey = normalizeOptionalString(latest?.controllerSessionKey) ?? normalizeOptionalString(latest?.requesterSessionKey); if (latest.runId !== run.runId || latestControllerSessionKey !== requesterKey) continue; const existing = dedupedRunsByChildKey.get(childKey); if (!existing || run.createdAt >= existing.createdAt) dedupedRunsByChildKey.set(childKey, run); } const runs = Array.from(dedupedRunsByChildKey.values()); if (runs.length === 0) return { stopped: 0 }; const storeCache = /* @__PURE__ */ new Map(); const seenChildKeys = /* @__PURE__ */ new Set(); let stopped = 0; for (const run of runs) { const childKey = normalizeOptionalString(run.childSessionKey); if (!childKey || seenChildKeys.has(childKey)) continue; seenChildKeys.add(childKey); if (!run.endedAt) { const cleared = clearSessionQueues([childKey]); const parsed = parseAgentSessionKey(childKey); const storePath = resolveStorePath(params.cfg.session?.store, { agentId: parsed?.agentId }); let store = storeCache.get(storePath); if (!store) { store = loadSessionStore(storePath); storeCache.set(storePath, store); } const entry = store[childKey]; const aborted = abortSessionRunTarget({ key: childKey, sessionId: replyRunRegistry.resolveSessionId(childKey) ?? entry?.sessionId }); if (abortDeps.markSubagentRunTerminated({ runId: run.runId, childSessionKey: childKey, reason: "killed" }) > 0 || aborted || cleared.followupCleared > 0 || cleared.laneCleared > 0) stopped += 1; } const cascadeResult = stopSubagentsForRequester({ cfg: params.cfg, requesterSessionKey: childKey }); stopped += cascadeResult.stopped; } if (stopped > 0) logVerbose(`abort: stopped ${stopped} subagent run(s) for ${requesterKey}`); return { stopped }; } 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.CommandBody ?? ctx.RawBody ?? ctx.Body ?? ""); if (!isAbortRequestText(normalizeOptionalLowercaseString(ctx.ChatType) === "group" ? stripMentions(raw, ctx, cfg, resolveSessionAgentId({ sessionKey: targetKey ?? ctx.SessionKey ?? "", config: cfg })) : raw)) 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 }); const abortKey = targetKey ?? auth.from ?? auth.to; const requesterSessionKey = targetKey ?? ctx.SessionKey ?? abortKey; if (targetKey) { const storePath = resolveStorePath(cfg.session?.store, { agentId }); const store = loadSessionStore(storePath); const { entry, key, legacyKeys } = resolveSessionEntryForKey(store, targetKey); const resolvedTargetKey = key ?? 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); const acpManager = abortDeps.getAcpSessionManager(); for (const acpTargetKey of abortTargetKeys.filter(isAcpSessionKey)) { if (acpManager.resolveSession({ cfg, sessionKey: acpTargetKey }).kind === "none") continue; try { await acpManager.cancelSession({ cfg, sessionKey: acpTargetKey, reason: "fast-abort" }); } catch (error) { logVerbose(`abort: ACP cancel failed for ${acpTargetKey}: ${formatErrorMessage(error)}`); } } 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 ? entry?.sessionId : resolveStoredSessionId({ cfg, sessionKey: abortTargetKey }))])); let aborted = false; for (const abortTargetKey of abortTargetKeys) aborted = abortSessionRunTarget({ key: abortTargetKey, sessionId: sessionIdsByKey.get(abortTargetKey) }) || aborted; const sourceSessionId = sourceAbortKey ? replyRunRegistry.resolveSessionId(sourceAbortKey) ?? resolveStoredSessionId({ cfg, sessionKey: sourceAbortKey }) : void 0; if (sourceAbortKey) aborted = abortSessionRunTarget({ key: sourceAbortKey, sessionId: sourceSessionId }) || 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(",")}`); const abortCutoff = shouldPersistAbortCutoff({ commandSessionKey, targetSessionKey: resolvedTargetKey }) ? resolveAbortCutoffFromContext(ctx) : void 0; if (entry && key) { entry.abortedLastRun = true; applyAbortCutoffToSessionEntry(entry, abortCutoff); entry.updatedAt = Date.now(); store[key] = entry; for (const legacyKey of legacyKeys ?? []) if (legacyKey !== key) delete store[legacyKey]; await updateSessionStore(storePath, (nextStore) => { const nextEntry = nextStore[key] ?? entry; if (!nextEntry) return; nextEntry.abortedLastRun = true; applyAbortCutoffToSessionEntry(nextEntry, abortCutoff); nextEntry.updatedAt = Date.now(); nextStore[key] = nextEntry; for (const legacyKey of legacyKeys ?? []) if (legacyKey !== key) delete nextStore[legacyKey]; }); } else if (abortKey) setAbortMemory(abortKey, true); const { stopped } = stopSubagentsForRequester({ cfg, requesterSessionKey }); return { handled: true, aborted, stoppedSubagents: stopped }; } if (abortKey) setAbortMemory(abortKey, true); const { stopped } = stopSubagentsForRequester({ cfg, requesterSessionKey }); return { handled: true, aborted: false, stoppedSubagents: stopped }; } //#endregion export { tryFastAbortFromMessage as a, stopSubagentsForRequester as i, formatAbortReplyText as n, resolveSessionEntryForKey as r, abortSessionRunTarget as t };