UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

253 lines (252 loc) 10.5 kB
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 };