openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
253 lines (252 loc) • 10.5 kB
JavaScript
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js";
import { O as parseAgentSessionKey } from "./session-key-BnWWjqNc.js";
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { H as validateChatAbortParams } from "./src-BiL5aQto.js";
import { d as errorShape } from "./error-codes-Bo8q2D1o.js";
import { i as resolveSessionStoreKey } from "./session-store-key-8xEjWSNi.js";
import { i as tryResolveSessionCompatibilityOwnerAgentId, n as resolveRequestedSessionAgentId } from "./session-request-agent-CCRSEGCB.js";
import { r as loadGatewaySessionEntry } from "./session-utils-store-CInT2loy.js";
import "./session-utils-Cai0_C6U.js";
import { t as abortChatRunById } from "./chat-abort-qLn3eFOg.js";
import { t as chatRunBelongsToAgent } from "./chat-run-owner-DPtcuc7L.js";
import { t as abortQueuedChatTurnById } from "./chat-queued-turns-hwiIcr_T.js";
import { t as assertValidParams } from "./validation-pzrlzFvo.js";
import { a as descendantAbortError, c as canRequesterAbortChatRun, f as resolveChatAbortRequester, g as normalizeUnknownChatText, h as normalizeOptionalChatText, i as cancelWorkerInferenceForSession, l as canRequesterAbortPreRegisteredRun, m as writePreRegisteredChatAbort, n as abortControlledSubagents, p as writePreRegisteredAgentAbort, t as abortChatRunsForSessionKeyWithPartials, u as readPreRegisteredAgentDedupePayloadForSession } from "./chat-abort-runtime-CKI3fkKr.js";
import { t as createChatAbortOps } from "./chat-abort-ops-zvMvu0-3.js";
import { n as pendingChatSendDedupeKey } from "./server-shared-C-7Ahu3n.js";
import { i as persistAbortedPartials, r as captureAbortedPartial } from "./chat-transcript-persistence-Bo3WmQ0i.js";
import { t as asWorkerInferenceControl } from "./inference-control-CDvM08Nt.js";
//#region src/gateway/server-methods/chat-abort-handler.ts
async function handleChatAbortRequestWithLifecycle({ params, respond, context, client, sessionMutationAuthorization }, lifecycle = {}) {
if (!assertValidParams(params, validateChatAbortParams, "chat.abort", respond)) return;
const { sessionKey: rawSessionKey, runId, preserveSideRuns } = params;
const agentIdOverride = normalizeOptionalChatText(params.agentId);
const abortCfg = context.getRuntimeConfig();
const parsedAbortSessionKey = parseAgentSessionKey(rawSessionKey);
const compatibilityDefaultAgentId = tryResolveSessionCompatibilityOwnerAgentId(abortCfg, rawSessionKey);
const inferredSessionAgentId = !agentIdOverride && parsedAbortSessionKey ? normalizeAgentId(parsedAbortSessionKey.agentId) : void 0;
const bareSessionAgentResolution = !parsedAbortSessionKey ? resolveRequestedSessionAgentId(abortCfg, rawSessionKey, agentIdOverride) : void 0;
if (bareSessionAgentResolution && !bareSessionAgentResolution.ok) {
respond(false, void 0, bareSessionAgentResolution.error);
return;
}
const abortAgentId = parsedAbortSessionKey ? agentIdOverride ?? inferredSessionAgentId : bareSessionAgentResolution?.agentId;
if (!abortAgentId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, rawSessionKey.trim().toLowerCase() === "global" ? "agentId is required for global chat.abort when no compatibility owner exists" : "agentId is required for unscoped chat.abort when no compatibility owner exists"));
return;
}
if (agentIdOverride && parsedAbortSessionKey && normalizeAgentId(parsedAbortSessionKey.agentId) !== normalizeAgentId(agentIdOverride)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `agentId "${agentIdOverride}" does not match session key "${rawSessionKey}"`));
return;
}
const canonicalAbortSessionKey = resolveSessionStoreKey({
cfg: abortCfg,
sessionKey: rawSessionKey,
storeAgentId: abortAgentId
});
const ops = createChatAbortOps(context);
const requester = resolveChatAbortRequester(client);
const sessionLoadOptions = { agentId: abortAgentId };
const abortSession = (() => {
try {
return {
ok: true,
value: loadGatewaySessionEntry(canonicalAbortSessionKey, sessionLoadOptions)
};
} catch (error) {
return {
ok: false,
error
};
}
})();
const abortSessionEntry = abortSession.ok ? abortSession.value.entry : void 0;
const cancelWorkerRun = (sessionId = abortSessionEntry?.sessionId) => requester.isAdmin ? cancelWorkerInferenceForSession({
context,
sessionId,
...runId ? { runId } : {}
}) : [];
const respondWithWorkerRuns = (localRunIds, sessionId) => {
const runIds = [.../* @__PURE__ */ new Set([...localRunIds, ...cancelWorkerRun(sessionId)])];
if (!abortSession.ok) throw abortSession.error;
respond(true, {
ok: true,
aborted: runIds.length > 0,
runIds
});
};
if (!runId) {
const res = await abortChatRunsForSessionKeyWithPartials({
context,
ops,
sessionKey: canonicalAbortSessionKey,
sessionKeyAliases: canonicalAbortSessionKey === rawSessionKey ? void 0 : [rawSessionKey],
agentId: abortAgentId,
sessionId: abortSessionEntry?.sessionId,
session: abortSession,
defaultAgentId: compatibilityDefaultAgentId,
abortOrigin: "rpc",
stopReason: "rpc",
requester,
assertCurrent: sessionMutationAuthorization?.assertCurrent,
preserveSideRuns,
excludeRunIds: lifecycle.excludeRunIds,
onAuthorizedAfterQueuedAbort: lifecycle.onAuthorizedAfterQueuedAbort,
cascadeDescendants: lifecycle.cascadeDescendants
});
if (res.unauthorized) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
const error = res.error ?? descendantAbortError(res.descendants, "Session");
if (error) {
respond(false, void 0, error);
return;
}
respond(true, {
ok: true,
aborted: res.aborted,
runIds: res.runIds
});
return;
}
const normalizedAgentIdOverride = normalizeAgentId(abortAgentId);
const authorizeRunTarget = (target) => {
if (target.sessionKey !== rawSessionKey && target.sessionKey !== canonicalAbortSessionKey && !canRequesterAbortChatRun(target, requester, { requireOwnerMatch: true })) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "runId does not match sessionKey"));
return false;
}
if (!chatRunBelongsToAgent({
agentId: target.agentId,
sessionKey: target.sessionKey,
defaultAgentId: compatibilityDefaultAgentId
}, normalizedAgentIdOverride)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "runId does not match agentId"));
return false;
}
if (!canRequesterAbortChatRun(target, requester)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return false;
}
return true;
};
const active = context.chatAbortControllers.get(runId);
if (!active) {
const readPendingRunForAbort = (entry) => {
for (const sessionKey of /* @__PURE__ */ new Set([canonicalAbortSessionKey, rawSessionKey])) {
const payload = readPreRegisteredAgentDedupePayloadForSession({
entry,
runId,
sessionKey,
agentId: abortAgentId,
defaultAgentId: compatibilityDefaultAgentId,
includeHidden: true
});
if (payload) return {
sessionKey: normalizeUnknownChatText(payload.sessionKey) ? sessionKey : void 0,
payload
};
}
};
const pendingChatMatch = readPendingRunForAbort(context.dedupe.get(pendingChatSendDedupeKey(runId)));
if (pendingChatMatch) {
if (!canRequesterAbortPreRegisteredRun(pendingChatMatch.payload, requester)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
writePreRegisteredChatAbort({
context,
runId,
stopReason: "rpc",
attemptId: normalizeUnknownChatText(pendingChatMatch.payload.attemptId)
});
respondWithWorkerRuns([runId]);
return;
}
const pendingAgentMatch = readPendingRunForAbort(context.dedupe.get(`agent:${runId}`));
if (pendingAgentMatch) {
const pendingAgentPayload = pendingAgentMatch.payload;
if (!canRequesterAbortPreRegisteredRun(pendingAgentPayload, requester)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
writePreRegisteredAgentAbort({
context,
runId,
sessionKey: pendingAgentMatch.sessionKey,
payload: pendingAgentPayload,
stopReason: "rpc"
});
respondWithWorkerRuns([runId]);
return;
}
const chatQueuedTurns = context.chatQueuedTurns;
const queued = chatQueuedTurns.get(runId);
if (queued) {
if (!authorizeRunTarget(queued)) return;
respondWithWorkerRuns(abortQueuedChatTurnById(chatQueuedTurns, {
runId,
sessionKey: queued.sessionKey,
stopReason: "rpc",
allowSessionMismatch: true
}).aborted ? [runId] : []);
return;
}
const workerSessionId = abortSessionEntry?.sessionId;
if (!workerSessionId || !asWorkerInferenceControl(context.workerEnvironmentService)?.hasInferenceForSession(workerSessionId, runId)) {
if (!abortSession.ok) throw abortSession.error;
respond(true, {
ok: true,
aborted: false,
runIds: []
});
return;
}
if (!requester.isAdmin) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
respondWithWorkerRuns([]);
return;
}
if (!authorizeRunTarget(active)) return;
let aborted = false;
const { sessionKey, sessionId, agentId, controlUiVisible } = active;
const partialText = context.chatRunState.resolveBuffer(runId, { final: true }).text;
const snapshot = controlUiVisible !== false && partialText?.trim() ? captureAbortedPartial({
runId,
sessionKey,
sessionId,
agentId: agentId ?? abortAgentId,
text: partialText,
abortOrigin: "rpc",
...sessionKey === rawSessionKey || sessionKey === canonicalAbortSessionKey ? { session: abortSession } : {}
}) : void 0;
const descendants = await abortControlledSubagents({
cfg: abortCfg,
sessionKey,
agentId,
requesterTurnRunId: runId,
beforeKill: () => aborted = abortChatRunById(ops, {
runId,
sessionKey,
stopReason: "rpc"
}).aborted
});
if (aborted && snapshot) await persistAbortedPartials({
context,
snapshots: [snapshot]
});
if (!abortSession.ok) throw abortSession.error;
const descendantError = descendantAbortError(descendants, "Parent run");
if (descendantError) {
respond(false, void 0, descendantError);
return;
}
respondWithWorkerRuns(aborted ? [runId] : [], sessionId);
}
async function handleChatAbortRequest(options) {
await handleChatAbortRequestWithLifecycle(options);
}
//#endregion
export { handleChatAbortRequestWithLifecycle as n, handleChatAbortRequest as t };