openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
626 lines (625 loc) • 26.9 kB
JavaScript
import { y as uniqueStrings } from "./string-normalization-DsCfAx8q.js";
import { t as ADMIN_SCOPE } from "./operator-scopes-Dw7Gu2cA.js";
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { l as isAgentEventLifecycleGenerationCurrent } from "./agent-events-CoxiItUi.js";
import "./method-scopes-K6J_UQGL.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import { i as resolveSessionStoreKey } from "./session-store-key-8xEjWSNi.js";
import "./task-registry.store.sqlite-BK18rNh0.js";
import { f as isSubagentRunQueued, h as listSubagentRunsForController, o as getLatestLiveSubagentRunByChildSessionKey } from "./subagent-registry-read-DeFf_9Nz.js";
import { i as ensureSubagentControllerOwnsRun, l as resolveSubagentController } from "./subagent-control-scope-Y_gLOuLl.js";
import "./session-utils-Cai0_C6U.js";
import { n as killSubagentRunAdmin, t as killAllControlledSubagentRuns } from "./subagent-control-Cm3eFdYX.js";
import { i as isChatAbortControllerEntryAbortable, t as abortChatRunById } from "./chat-abort-qLn3eFOg.js";
import { r as resolveChatRunOwnerAgentId, t as chatRunBelongsToAgent } from "./chat-run-owner-DPtcuc7L.js";
import { n as createChatAbortMarker } from "./server-chat-state-CwKZZaYd.js";
import { i as listQueuedChatTurnsForSession, n as abortQueuedChatTurns } from "./chat-queued-turns-hwiIcr_T.js";
import { n as setGatewayDedupeEntry, t as createChatAbortOps } from "./chat-abort-ops-zvMvu0-3.js";
import { n as pendingChatSendDedupeKey, t as PENDING_CHAT_SEND_DEDUPE_PREFIX } from "./server-shared-C-7Ahu3n.js";
import { n as emitSessionsChanged } from "./session-change-event-DzmH4zlz.js";
import { i as persistAbortedPartials, r as captureAbortedPartial } from "./chat-transcript-persistence-Bo3WmQ0i.js";
import { t as errorShapeFromError } from "./error-shape-Dkw4Brp8.js";
import { t as asWorkerInferenceControl } from "./inference-control-CDvM08Nt.js";
//#region src/gateway/server-methods/chat-text-normalization.ts
function normalizeOptionalChatText(value) {
return value?.trim() || void 0;
}
function normalizeUnknownChatText(value) {
return typeof value === "string" ? normalizeOptionalChatText(value) : void 0;
}
//#endregion
//#region src/gateway/server-methods/chat-abort-authorization.ts
function buildAbortedChatSendPayload(params) {
return {
runId: params.runId,
status: "timeout",
summary: "aborted",
...params.stopReason ? { stopReason: params.stopReason } : {},
endedAt: params.endedAt
};
}
function resolveChatAbortRequester(client) {
const scopes = Array.isArray(client?.connect?.scopes) ? client.connect.scopes : [];
return {
connId: normalizeOptionalChatText(client?.connId),
deviceId: normalizeOptionalChatText(client?.connect?.device?.id),
isAdmin: scopes.includes(ADMIN_SCOPE)
};
}
function canRequesterAbortChatRun(entry, requester, options = {}) {
if (requester.isAdmin) return true;
const ownerDeviceId = normalizeOptionalChatText(entry.ownerDeviceId);
const ownerConnId = normalizeOptionalChatText(entry.ownerConnId);
return Boolean(!options.requireOwnerMatch && !ownerDeviceId && !ownerConnId || ownerDeviceId && requester.deviceId && ownerDeviceId === requester.deviceId || ownerConnId && requester.connId && ownerConnId === requester.connId);
}
function readPreRegisteredAgentDedupePayloadForSession(params) {
if (!params.entry?.ok) return;
const payload = params.entry.payload;
if (payload?.status !== "accepted") return;
if (!params.includeHidden && payload.controlUiVisible === false) return;
const payloadRunId = normalizeUnknownChatText(payload.runId);
if (payloadRunId && payloadRunId !== params.runId) return;
const payloadSessionKeys = /* @__PURE__ */ new Set([normalizeUnknownChatText(payload.sessionKey), ...Array.isArray(payload.sessionKeyAliases) ? payload.sessionKeyAliases.map(normalizeUnknownChatText) : []]);
const hasPayloadSessionKey = [...payloadSessionKeys].some(Boolean);
if (hasPayloadSessionKey && !payloadSessionKeys.has(params.sessionKey) || !hasPayloadSessionKey && payloadRunId !== params.runId) return;
const agentId = normalizeOptionalChatText(params.agentId)?.toLowerCase();
if (agentId) {
if (resolveChatRunOwnerAgentId({
agentId: normalizeUnknownChatText(payload.agentId),
sessionKey: params.sessionKey,
defaultAgentId: params.defaultAgentId
}) !== agentId) return;
}
return payload;
}
function readPreRegisteredRun(params) {
if (!params.key.startsWith(params.keyPrefix) || !params.entry?.ok) return;
const payload = params.entry.payload;
if (payload?.status !== "accepted") return;
if (!params.includeHidden && payload.controlUiVisible === false) return;
const runId = normalizeUnknownChatText(payload.runId) ?? normalizeOptionalChatText(params.key.slice(params.keyPrefix.length));
const sessionKey = normalizeUnknownChatText(payload.sessionKey);
if (!runId || !sessionKey) return;
return {
runId,
sessionKey,
payload
};
}
function canRequesterAbortPreRegisteredRun(payload, requester) {
return canRequesterAbortChatRun({
ownerConnId: normalizeUnknownChatText(payload.ownerConnId),
ownerDeviceId: normalizeUnknownChatText(payload.ownerDeviceId)
}, requester);
}
function resolvePreRegisteredAgentDedupeKeys(payload, runId) {
const keys = [`agent:${runId}`];
const payloadKeys = Array.isArray(payload.dedupeKeys) ? payload.dedupeKeys : [];
for (const key of payloadKeys) {
const normalized = normalizeUnknownChatText(key);
if (normalized?.startsWith("agent:")) keys.push(normalized);
}
return uniqueStrings(keys);
}
function writePreRegisteredAgentAbort(params) {
const endedAt = params.endedAt ?? Date.now();
const payloadAgentId = normalizeUnknownChatText(params.payload.agentId);
for (const key of resolvePreRegisteredAgentDedupeKeys(params.payload, params.runId)) setGatewayDedupeEntry({
dedupe: params.context.dedupe,
key,
entry: {
ts: endedAt,
ok: true,
payload: {
runId: params.runId,
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
...payloadAgentId ? { agentId: payloadAgentId } : {},
...params.payload.controlUiVisible === false ? { controlUiVisible: false } : {},
status: "timeout",
summary: "aborted",
stopReason: params.stopReason,
endedAt
}
}
});
}
function writePreRegisteredChatAbort(params) {
const endedAt = params.endedAt ?? Date.now();
const payload = buildAbortedChatSendPayload({
runId: params.runId,
stopReason: params.stopReason,
endedAt
});
params.context.chatRunState.getOrCreate(params.runId).abortMarker = createChatAbortMarker(endedAt);
const pendingKey = pendingChatSendDedupeKey(params.runId);
const pendingEntry = params.context.dedupe.get(pendingKey);
const pendingAttemptId = normalizeUnknownChatText((pendingEntry?.payload)?.attemptId);
const ownsPendingAttempt = !params.attemptId || pendingAttemptId === params.attemptId;
if (ownsPendingAttempt) params.context.dedupe.delete(pendingKey);
setGatewayDedupeEntry({
dedupe: params.context.dedupe,
key: `chat:${params.runId}`,
entry: {
ts: endedAt,
ok: true,
payload,
...ownsPendingAttempt && pendingEntry?.requestIdentity ? { requestIdentity: pendingEntry.requestIdentity } : {}
}
});
}
function resolveAuthorizedPreRegisteredRunsForSessionKeys(params) {
const sessionKeys = new Set(Array.from(params.sessionKeys, (sessionKey) => normalizeOptionalChatText(sessionKey)).filter((sessionKey) => Boolean(sessionKey)));
const authorizedByRunId = /* @__PURE__ */ new Map();
const matchedRunIds = /* @__PURE__ */ new Set();
let hasUnauthorizedRuns = false;
let hasUnauthorizedProtectedRuns = false;
let hasProtectedRuns = false;
for (const [key, entry] of params.context.dedupe) {
const run = readPreRegisteredRun({
key,
entry,
keyPrefix: params.keyPrefix,
includeHidden: true
});
if (!run) continue;
if (params.excludeRunIds?.has(run.runId)) continue;
if (![run.sessionKey, ...Array.isArray(run.payload.sessionKeyAliases) ? run.payload.sessionKeyAliases.map(normalizeUnknownChatText) : []].some((sessionKey) => Boolean(sessionKey && sessionKeys.has(sessionKey)))) continue;
if (params.context.chatAbortControllers.has(run.runId)) continue;
const agentId = normalizeOptionalChatText(params.agentId)?.toLowerCase();
if (agentId && !chatRunBelongsToAgent({
agentId: normalizeUnknownChatText(run.payload.agentId),
sessionKey: run.sessionKey,
defaultAgentId: params.defaultAgentId
}, agentId)) continue;
matchedRunIds.add(run.runId);
const requesterCanAbort = canRequesterAbortPreRegisteredRun(run.payload, params.requester);
if (params.includeProtectedRuns !== true && (run.payload.controlUiVisible === false || params.preserveSideRuns && normalizeUnknownChatText(run.payload.turnKind) === "btw")) {
hasProtectedRuns = true;
if (!requesterCanAbort) hasUnauthorizedProtectedRuns = true;
continue;
}
if (requesterCanAbort) authorizedByRunId.set(run.runId, run);
else hasUnauthorizedRuns = true;
}
return {
authorizedRuns: [...authorizedByRunId.values()],
matchedRunIds: [...matchedRunIds],
hasUnauthorizedRuns,
hasUnauthorizedProtectedRuns,
hasProtectedRuns
};
}
function resolveAuthorizedRunsForSessionKeys(params) {
const sessionKeys = new Set(Array.from(params.sessionKeys, (sessionKey) => normalizeOptionalChatText(sessionKey)).filter((sessionKey) => Boolean(sessionKey)));
const sessionIds = new Set(Array.from(params.sessionIds ?? [], (sessionId) => normalizeOptionalChatText(sessionId)).filter((sessionId) => Boolean(sessionId)));
const agentId = normalizeOptionalChatText(params.agentId)?.toLowerCase();
const authorizedRuns = [];
const matchedRunIds = [];
let hasUnauthorizedRuns = false;
let hasUnauthorizedProtectedRuns = false;
let hasProtectedRuns = false;
for (const [runId, active] of params.chatAbortControllers) {
if (params.excludeRunIds?.has(runId)) continue;
if (!sessionKeys.has(active.sessionKey) && !sessionIds.has(active.sessionId)) continue;
if (agentId && !chatRunBelongsToAgent({
agentId: active.agentId,
sessionKey: active.sessionKey,
defaultAgentId: params.defaultAgentId
}, agentId)) continue;
matchedRunIds.push(runId);
const requesterCanAbort = canRequesterAbortChatRun(active, params.requester);
if (params.includeProtectedRuns !== true && (active.controlUiVisible === false || params.preserveSideRuns && active.turnKind === "btw")) {
hasProtectedRuns = true;
if (!requesterCanAbort) hasUnauthorizedProtectedRuns = true;
continue;
}
if (requesterCanAbort) authorizedRuns.push({
runId,
sessionKey: active.sessionKey,
entry: active
});
else hasUnauthorizedRuns = true;
}
return {
authorizedRuns,
matchedRunIds,
hasUnauthorizedRuns,
hasUnauthorizedProtectedRuns,
hasProtectedRuns
};
}
//#endregion
//#region src/gateway/server-methods/chat-abort-runtime.ts
async function abortControlledSubagents(params) {
const controller = resolveSubagentController({
cfg: params.cfg,
agentSessionKey: params.sessionKey,
agentId: params.agentId
});
const runs = listSubagentRunsForController(controller.controllerSessionKey, controller.controllerAgentId).filter((entry) => params.requesterTurnRunId === void 0 || entry.requesterTurnRunId === params.requesterTurnRunId);
if (runs.length === 0) {
await params.beforeKill?.();
return;
}
return killAllControlledSubagentRuns({
cfg: params.cfg,
controller,
runs,
suppressTaskDelivery: true,
beforeKill: params.beforeKill
});
}
function descendantAbortError(result, subject) {
return result && result.status !== "ok" ? errorShape(ErrorCodes.UNAVAILABLE, `${subject} stopped, but descendant cancellation was incomplete: ${result.error}`) : void 0;
}
/** Queued collectors retain scheduler ownership while Gateway admission is still pending. */
function abortQueuedCollectorSession(params) {
const entry = getLatestLiveSubagentRunByChildSessionKey(params.sessionKey);
if (!entry || !isSubagentRunQueued(entry) || params.excludeRunIds?.has(entry.runId) || params.runId && entry.runId !== params.runId) return;
const cfg = params.context.getRuntimeConfig();
const parentRunId = entry.requesterTurnRunId;
const parentRun = parentRunId ? params.context.chatAbortControllers.get(parentRunId) : void 0;
const parentKey = entry.controllerSessionKey?.trim() || entry.requesterSessionKey;
const controller = {
controllerSessionKey: parentKey,
controllerAgentId: resolveChatRunOwnerAgentId({
sessionKey: parentKey,
defaultAgentId: entry.requesterAgentId
})
};
const assertCurrent = () => {
params.assertCurrent?.();
if (entry.execution.status === "queued" && !isSubagentRunQueued(entry)) throw new Error("Queued collector reservation changed; retry Stop.");
const ownershipError = ensureSubagentControllerOwnsRun({
cfg,
controller,
entry
});
if (ownershipError) throw new Error(ownershipError);
if (params.requester.isAdmin) return;
if (!parentRunId || !parentRun || params.context.chatAbortControllers.get(parentRunId) !== parentRun || !isChatAbortControllerEntryAbortable(parentRun) || !parentRun.lifecycleGeneration || !isAgentEventLifecycleGenerationCurrent(parentRun.lifecycleGeneration) || parentRun.projectSessionActive === false || resolveSessionStoreKey({
cfg,
sessionKey: parentRun.sessionKey,
storeAgentId: controller.controllerAgentId
}) !== parentKey || resolveChatRunOwnerAgentId({
agentId: parentRun.agentId,
sessionKey: parentRun.sessionKey
}) !== controller.controllerAgentId || !canRequesterAbortChatRun(parentRun, params.requester, { requireOwnerMatch: true })) throw new Error("Unauthorized queued collector Stop; use its active parent requester connection or an administrator.");
};
return (async () => {
let sessionAbort;
let outcome = {
ok: false,
error: errorShape(ErrorCodes.UNAVAILABLE, "Queued collector cancellation was not published; retry Stop.")
};
try {
assertCurrent();
await killSubagentRunAdmin({
cfg,
sessionKey: params.sessionKey,
agentId: params.agentId,
expectedRunId: entry.runId,
expectedGeneration: entry.generation,
expectedOwnerKey: entry.requesterSessionKey,
onResult: (result) => {
if (sessionAbort && !sessionAbort.ok) {
outcome = sessionAbort;
return;
}
const selected = sessionAbort?.value;
if (selected?.result.unauthorized) {
outcome = {
ok: false,
error: errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized")
};
return;
}
if (result.found && result.error) {
outcome = {
ok: false,
error: errorShape(ErrorCodes.UNAVAILABLE, result.error)
};
return;
}
if (selected && !selected.plan.canCascade) {
outcome = {
ok: false,
error: errorShape(ErrorCodes.UNAVAILABLE, "Queued collector was not stopped; other session work was preserved. Wait for it to finish or cancel it through its owner, then retry.")
};
return;
}
const aborted = result.found && result.killed && result.targetState?.state === "terminal" && result.targetState.task.status === "cancelled" && result.targetState.task.error === "Subagent run killed.";
if (aborted) emitSessionsChanged(params.context, {
sessionKey: params.sessionKey,
agentId: params.agentId,
reason: "abort"
});
outcome = {
ok: true,
value: {
aborted: aborted || selected?.result.aborted === true,
runIds: [.../* @__PURE__ */ new Set([...aborted ? [result.runId] : [], ...selected?.result.runIds ?? []])]
}
};
}
}, {
assertCurrent,
beforeSessionKill: () => {
const plan = prepareChatSessionAbort({
...params,
ops: createChatAbortOps(params.context),
cascadeDescendants: true,
includeProtectedRuns: params.runId ? true : params.includeProtectedRuns
}, entry.runId);
if (params.runId && plan.hasOtherWork) {
sessionAbort = {
ok: false,
error: errorShape(ErrorCodes.UNAVAILABLE, "Other work is active in this child session; use a full-session Stop without runId.")
};
return false;
}
sessionAbort = {
ok: true,
value: {
plan,
result: plan.abort()
}
};
return plan.canCascade;
}
});
} catch (error) {
outcome = {
ok: false,
error: errorShapeFromError(ErrorCodes.INVALID_REQUEST, error)
};
} finally {
if (sessionAbort?.ok) try {
await sessionAbort.value.plan.finish(sessionAbort.value.result);
} catch (error) {
if (outcome.ok) outcome = {
ok: false,
error: errorShapeFromError(ErrorCodes.INVALID_REQUEST, error)
};
else params.context.logGateway.warn("chat.abort could not persist captured output after cancellation was rejected");
}
}
return outcome;
})();
}
const SESSION_LIFECYCLE_ABORT_REQUESTER = { isAdmin: true };
function resolveAuthorizedQueuedTurnsForSession(params) {
const matches = listQueuedChatTurnsForSession({
chatQueuedTurns: params.context.chatQueuedTurns,
sessionKeys: params.sessionKeys,
sessionIds: [params.sessionId],
agentId: params.agentId,
defaultAgentId: params.defaultAgentId
}).filter((match) => !params.excludeRunIds?.has(match.runId));
const authorized = matches.filter((match) => canRequesterAbortChatRun(match.entry, params.requester));
return {
authorized,
matchedRunIds: matches.map((match) => match.runId),
hasUnauthorizedRuns: authorized.length < matches.length
};
}
/** Authoritative active, pending, or queued Gateway owner for an exact session. */
function hasGatewaySessionAbortOwner(params) {
const ownerScope = {
sessionKeys: params.sessionKeys,
agentId: params.agentId,
defaultAgentId: params.defaultAgentId,
requester: SESSION_LIFECYCLE_ABORT_REQUESTER
};
return resolveAuthorizedRunsForSessionKeys({
chatAbortControllers: params.context.chatAbortControllers,
sessionIds: [params.sessionId],
...ownerScope,
includeProtectedRuns: true
}).authorizedRuns.length > 0 || resolveAuthorizedQueuedTurnsForSession({
context: params.context,
sessionId: params.sessionId,
...ownerScope
}).authorized.length > 0 || ["agent:", "pending-chat:"].some((keyPrefix) => resolveAuthorizedPreRegisteredRunsForSessionKeys({
context: params.context,
...ownerScope,
keyPrefix,
includeProtectedRuns: true
}).authorizedRuns.length > 0);
}
function cancelWorkerInferenceForSession(params) {
const sessionId = normalizeOptionalChatText(params.sessionId);
if (!sessionId) return [];
return asWorkerInferenceControl(params.context.workerEnvironmentService)?.cancelInferenceForSession({
sessionId,
...params.runId ? { runId: params.runId } : {}
}) ?? [];
}
/** Resolve once at the cancellation boundary; persist captured partials only after Stop. */
function prepareChatSessionAbort(params, selectedRunId) {
const sessionKeys = [params.sessionKey, ...params.sessionKeyAliases ?? []];
const queuedPlan = resolveAuthorizedQueuedTurnsForSession({
context: params.context,
sessionKeys,
sessionId: params.sessionId,
agentId: params.agentId,
defaultAgentId: params.defaultAgentId,
requester: params.requester,
excludeRunIds: params.excludeRunIds
});
const { authorizedRuns, matchedRunIds: matchedActiveRunIds, hasUnauthorizedRuns: hasUnauthorizedActiveRuns, hasUnauthorizedProtectedRuns: hasUnauthorizedProtectedActiveRuns, hasProtectedRuns: hasProtectedActiveRuns } = resolveAuthorizedRunsForSessionKeys({
chatAbortControllers: params.context.chatAbortControllers,
sessionKeys,
sessionIds: [params.sessionId],
agentId: params.agentId,
defaultAgentId: params.defaultAgentId,
requester: params.requester,
preserveSideRuns: params.preserveSideRuns,
includeProtectedRuns: params.includeProtectedRuns,
excludeRunIds: params.excludeRunIds
});
const resolvePendingRuns = (keyPrefix) => resolveAuthorizedPreRegisteredRunsForSessionKeys({
context: params.context,
sessionKeys,
agentId: params.agentId,
defaultAgentId: params.defaultAgentId,
requester: params.requester,
keyPrefix,
preserveSideRuns: params.preserveSideRuns,
includeProtectedRuns: params.includeProtectedRuns,
excludeRunIds: params.excludeRunIds
});
const pendingAgent = resolvePendingRuns("agent:");
const pendingChat = resolvePendingRuns(PENDING_CHAT_SEND_DEDUPE_PREFIX);
const pendingPlans = [pendingAgent, pendingChat];
const hasAuthorizedGatewayRuns = authorizedRuns.length > 0 || queuedPlan.authorized.length > 0 || pendingPlans.some((plan) => plan.authorizedRuns.length > 0);
const workerService = asWorkerInferenceControl(params.context.workerEnvironmentService);
const workerSessionId = params.sessionId;
const isLifecycleAbort = Boolean(params.cascadeDescendants || params.onAuthorizedAfterQueuedAbort);
const hasWorkerRun = Boolean(workerSessionId && (!hasAuthorizedGatewayRuns || isLifecycleAbort) && workerService?.hasInferenceForSession(workerSessionId));
const hasControllerRepresentedWorkerRun = Boolean(hasWorkerRun && workerSessionId && workerService && matchedActiveRunIds.some((runId) => workerService.hasInferenceForSession(workerSessionId, runId)));
const hasUnauthorizedOwner = hasUnauthorizedActiveRuns || queuedPlan.hasUnauthorizedRuns || pendingPlans.some((plan) => plan.hasUnauthorizedRuns) || hasWorkerRun && !hasControllerRepresentedWorkerRun && !params.requester.isAdmin;
const hasProtectedLifecycleRuns = hasProtectedActiveRuns || pendingPlans.some((plan) => plan.hasProtectedRuns);
const hasUnauthorizedProtectedOwner = hasUnauthorizedProtectedActiveRuns || pendingPlans.some((plan) => plan.hasUnauthorizedProtectedRuns);
const hasUnauthorizedLifecycleOwner = isLifecycleAbort && hasUnauthorizedProtectedOwner;
const canRunLifecycleCleanup = !hasUnauthorizedOwner && !hasProtectedLifecycleRuns;
const canCancelWorkerSession = !isLifecycleAbort || !hasProtectedLifecycleRuns;
let snapshots = [];
const abortAuthorizedRuns = () => {
params.onControllerTargets?.(authorizedRuns);
if (!hasAuthorizedGatewayRuns) {
if (hasUnauthorizedOwner || hasUnauthorizedLifecycleOwner) return {
aborted: false,
runIds: [],
unauthorized: true
};
const additionalAborted = canRunLifecycleCleanup ? params.onAuthorizedAfterQueuedAbort?.() ?? false : false;
if (!hasWorkerRun || !workerSessionId || !params.requester.isAdmin || !canCancelWorkerSession) return {
aborted: additionalAborted,
runIds: [],
unauthorized: false
};
const workerRunIds = cancelWorkerInferenceForSession({
context: params.context,
sessionId: workerSessionId
});
return {
aborted: additionalAborted || workerRunIds.length > 0,
runIds: workerRunIds,
unauthorized: false
};
}
snapshots = authorizedRuns.flatMap(({ runId, entry }) => {
const text = params.context.chatRunState.resolveBuffer(runId, { final: true }).text;
return text?.trim() ? [captureAbortedPartial({
runId,
sessionKey: params.sessionKey,
sessionId: entry.sessionId,
agentId: entry.agentId ?? params.agentId,
text,
abortOrigin: params.abortOrigin,
session: params.session
})] : [];
});
const runIds = abortQueuedChatTurns(params.context.chatQueuedTurns, queuedPlan.authorized, params.stopReason);
const additionalAborted = canRunLifecycleCleanup ? params.onAuthorizedAfterQueuedAbort?.() ?? false : false;
for (const { runId, sessionKey } of authorizedRuns) if (abortChatRunById(params.ops, {
runId,
sessionKey,
stopReason: params.stopReason
}).aborted) runIds.push(runId);
const endedAt = Date.now();
const stopReason = params.stopReason ?? "rpc";
for (const { runId, sessionKey, payload } of pendingAgent.authorizedRuns) {
writePreRegisteredAgentAbort({
context: params.context,
runId,
sessionKey,
payload,
stopReason,
endedAt
});
runIds.push(runId);
}
for (const { runId, payload } of pendingChat.authorizedRuns) {
writePreRegisteredChatAbort({
context: params.context,
runId,
stopReason,
endedAt,
attemptId: normalizeUnknownChatText(payload.attemptId)
});
runIds.push(runId);
}
if (params.requester.isAdmin && canCancelWorkerSession) {
for (const runId of cancelWorkerInferenceForSession({
context: params.context,
sessionId: params.sessionId
})) if (!runIds.includes(runId)) runIds.push(runId);
}
return {
aborted: additionalAborted || runIds.length > 0,
runIds,
unauthorized: false
};
};
const hasOtherWork = matchedActiveRunIds.some((runId) => runId !== selectedRunId) || queuedPlan.matchedRunIds.some((runId) => runId !== selectedRunId) || pendingPlans.some((plan) => plan.matchedRunIds.some((runId) => runId !== selectedRunId)) || hasWorkerRun && (!selectedRunId || !workerSessionId || !workerService?.hasInferenceForSession(workerSessionId, selectedRunId));
return {
canCascade: canRunLifecycleCleanup && !hasUnauthorizedLifecycleOwner,
hasOtherWork,
abort: abortAuthorizedRuns,
async finish(result) {
if (result.aborted && snapshots.length > 0) {
const abortedRunIds = new Set(result.runIds);
await persistAbortedPartials({
context: params.context,
snapshots: snapshots.filter((snapshot) => abortedRunIds.has(snapshot.runId))
});
}
if (params.session && !params.session.ok) throw params.session.error;
}
};
}
async function abortChatRunsForSessionKeyWithPartials(params) {
if (params.cascadeDescendants) {
const queuedAbort = abortQueuedCollectorSession(params);
if (queuedAbort) {
const result = await queuedAbort;
return result.ok ? {
...result.value,
unauthorized: false
} : {
aborted: false,
runIds: [],
unauthorized: false,
error: result.error
};
}
}
const plan = prepareChatSessionAbort(params);
let result = {
aborted: false,
runIds: [],
unauthorized: false
};
let descendants;
if (params.cascadeDescendants && plan.canCascade) descendants = await abortControlledSubagents({
cfg: params.context.getRuntimeConfig(),
sessionKey: params.sessionKey,
agentId: params.agentId,
beforeKill: () => {
result = plan.abort();
return true;
}
});
else result = plan.abort();
if (!result.unauthorized && !result.error) params.onCancellationStarted?.();
await plan.finish(result);
return {
...result,
aborted: result.aborted || Boolean(descendants?.killed),
descendants
};
}
//#endregion
export { descendantAbortError as a, canRequesterAbortChatRun as c, readPreRegisteredRun as d, resolveChatAbortRequester as f, normalizeUnknownChatText as g, normalizeOptionalChatText as h, cancelWorkerInferenceForSession as i, canRequesterAbortPreRegisteredRun as l, writePreRegisteredChatAbort as m, abortControlledSubagents as n, hasGatewaySessionAbortOwner as o, writePreRegisteredAgentAbort as p, abortQueuedCollectorSession as r, buildAbortedChatSendPayload as s, abortChatRunsForSessionKeyWithPartials as t, readPreRegisteredAgentDedupePayloadForSession as u };