openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
589 lines (588 loc) • 25.6 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { r as resolveStateDir } from "./state-dir-CYkBUd_G.mjs";
import { r as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs";
import { r as isIncognitoSessionKey } from "./session-key-CmZ4o9-l.mjs";
import "./session-key-DY3MOX4N.mjs";
import { h as parseAgentSessionKey } from "./session-key-utils-CDyBC9Gn.mjs";
import { i as isIncognitoOpenClawAgentSqlitePath, l as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs";
import { c as SqliteWorkerError } from "./sqlite-worker-contract-C51cJHzg.mjs";
import { r as cloneEnvWithPlatformSemantics } from "./config-env-vars-BzUE_dOh.mjs";
import { n as runOpenClawAgentWriteAdmission } from "./openclaw-agent-write-admission-CXJiE5VB.mjs";
import { i as toDatabaseOptions } from "./session-accessor.sqlite-scope-helpers-CfDTAEsL.mjs";
import { n as captureSessionStoreCandidateIdentities, t as assertSessionStoreReadCandidate } from "./session-store-read-candidates-CXD-JYGz.mjs";
import { G as validateChatAbortParams } from "./src-D6kL8tMP.mjs";
import { t as ErrorCodes } from "./gateway-error-details-gTekQWj2.mjs";
import { d as errorShape } from "./error-codes-D0WRV4Bq.mjs";
import { f as resolveSqliteWriteAdmissionScope, i as prepareSqliteScope, s as resolveSqliteScope } from "./session-accessor.sqlite-scope-BkgwxatT.mjs";
import { a as withSessionEntryWorker } from "./session-accessor.sqlite-replacement-worker-vT9ZZh6F.mjs";
import { t as captureSessionStoreReadCandidates } from "./session-store-target-inventory-C9ERDnSH.mjs";
import { r as resolveRequestedSessionAgentId, s as tryResolveSessionCompatibilityOwnerAgentId } from "./session-request-agent-BWnhhVvT.mjs";
import { a as resolveSessionStoreKey } from "./session-store-key-Dvf3CKvN.mjs";
import { t as chatRunBelongsToAgent } from "./chat-run-owner-DsPSU6Vj.mjs";
import { r as isChatAbortControllerEntryAbortable, t as abortChatRunById } from "./chat-abort-BnB7jJDN.mjs";
import { i as isQueuedChatTurnForSession, t as abortQueuedChatTurnById } from "./chat-queued-turns-Cr3X0g10.mjs";
import { l as resolveStateContentionPresentation } from "./chat-display-projection.core-BOF-lEvI.mjs";
import { a as readGatewayRequestMutationAuthority } from "./session-mutation-guards-CQnYdW-6.mjs";
import { r as loadGatewaySessionEntry } from "./session-utils-store-qn-zT-Fk.mjs";
import { n as captureExecRequestCancellation } from "./bash-process-control-CcTL6Huf.mjs";
import "./session-utils-BLqrCe75.mjs";
import { i as persistAbortedPartials } from "./chat-transcript-persistence-JKSwSL50.mjs";
import { a as withAbortedPartialPersistenceWarning, i as deferAbortedPartialPersistence, n as abortedPartialPersistenceError, r as captureAbortedPartial } from "./chat-aborted-partial-C13jjK9r.mjs";
import { n as emitSessionsChanged } from "./session-change-event-DbHnHE9x.mjs";
import { i as getWorkerInferenceSessionControl } from "./inference-control-internal-BLOysNzr.mjs";
import { n as createChatAbortOps, t as captureWorkerInferenceForSession } from "./chat-abort-ops-Cgfm8bo7.mjs";
import { t as assertValidParams } from "./validation-UW_NLjlV.mjs";
import { n as formatStopRequest } from "./control-plane-audit-DhEbrRsy.mjs";
import { n as pendingChatSendDedupeKey } from "./server-shared-C-7Ahu3n.mjs";
import { d as resolveChatAbortRequester, f as writePreRegisteredAgentAbort, i as descendantAbortError, l as readPreRegisteredAgentDedupePayloadForSession, o as canRequesterAbortChatRun, p as writePreRegisteredChatAbort, r as abortControlledSubagents, s as canRequesterAbortPreRegisteredRun, t as abortChatRunsForSessionKeyWithPartials } from "./chat-abort-runtime-DNr1DIGd.mjs";
//#region src/config/sessions/session-pending-input-withdrawal.ts
function readWithdrawalResult(receipt, input) {
return isRecord(receipt) && receipt.kind === "session-pending-input-withdrawal" && receipt.sessionKey === input.sessionKey && receipt.sessionId === input.sessionId && receipt.runId === input.runId && typeof receipt.withdrawn === "boolean" ? receipt.withdrawn : void 0;
}
/** The caller retains live cancellation authority until withdrawal commits. */
async function discardSessionPendingInput(scope, runId, assertCurrent) {
assertCurrent();
const env = cloneEnvWithPlatformSemantics(scope.env ?? process.env);
env.OPENCLAW_STATE_DIR = resolveStateDir(env);
const target = {
...scope,
env
};
const logical = resolveSqliteScope({
...target,
storePath: void 0
});
const storePath = logical.path ?? target.storePath ?? resolveOpenClawAgentSqlitePath(toDatabaseOptions(logical));
const input = {
sessionKey: logical.sessionKey,
sessionId: target.sessionId,
runId
};
if (isIncognitoOpenClawAgentSqlitePath(storePath, toDatabaseOptions(logical))) throw new Error("Queued input removal is unavailable for incognito chats; use Stop to cancel execution");
const candidates = captureSessionStoreReadCandidates(storePath);
const identities = captureSessionStoreCandidateIdentities(candidates);
const writeAdmission = resolveSqliteWriteAdmissionScope(target);
const withdraw = async () => {
const resolved = await prepareSqliteScope(target);
assertCurrent();
const options = toDatabaseOptions(resolved);
const path = resolveOpenClawAgentSqlitePath(options);
const identity = identities.get(assertSessionStoreReadCandidate(path, candidates));
if (!identity) throw new Error("Pending input withdrawal changed its captured database owner");
if (!identity.key.startsWith("file:")) return false;
const assertHeld = () => {
assertSessionStoreReadCandidate(path, candidates);
assertExistingDatabaseIdentity(path, identity.key, identity.birthtime);
assertCurrent();
};
assertHeld();
let admitted;
return withSessionEntryWorker({
...options,
path
}, void 0, assertHeld, async (execution, source) => {
return await execution.runExisting(source, async (worker) => {
const outcome = await worker.execute({
type: "session.pendingInputs.withdraw",
input
}).then(() => ({ ok: true }), (error) => ({
ok: false,
error
}));
if (admitted) {
await admitted.retained.settled;
const withdrawn = readWithdrawalResult(admitted.admission.committed?.facts, input);
if (admitted.admission.settlement?.kind === "completed" && withdrawn !== void 0) return withdrawn;
}
if (!outcome.ok) throw outcome.error;
throw new SqliteWorkerError("Pending input withdrawal has no confirmed native completion and commit receipt", "outcome-unknown");
}) ?? false;
}, (admission, retained, facts) => {
if (!isRecord(facts) || readWithdrawalResult(facts.publication, input) === void 0) throw new Error("Pending input withdrawal commit omitted its exact receipt");
admitted = {
admission,
retained
};
});
};
return writeAdmission ? runOpenClawAgentWriteAdmission(toDatabaseOptions(writeAdmission), withdraw, true) : withdraw();
}
//#endregion
//#region src/gateway/server-methods/chat-abort-handler.ts
function captureAbortTargetIdentity(entries, runId, entry) {
const { sessionKey, sessionId, agentId } = entry;
return () => entries.get(runId) === entry && entry.sessionKey === sessionKey && entry.sessionId === sessionId && entry.agentId === agentId;
}
async function handleChatAbortRequestWithLifecycle(options, lifecycle = {}) {
const { params, respond, context, client, sessionMutationAuthorization } = options;
const authority = readGatewayRequestMutationAuthority(options);
const requester = resolveChatAbortRequester(client, sessionMutationAuthorization);
const assertCurrent = () => {
authority.assertCurrent();
sessionMutationAuthorization?.assertCurrent();
requester.sessionAuthority?.assertCurrent();
};
if (!assertValidParams(params, validateChatAbortParams, "chat.abort", respond)) return;
const { sessionKey: rawSessionKey, runId, preserveSideRuns, discardPendingInput } = params;
if (discardPendingInput && !runId) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "discardPendingInput requires an exact runId"));
return;
}
const agentIdOverride = normalizeOptionalString(params.agentId);
const abortCfg = context.getRuntimeConfig();
const parsedAbortSessionKey = parseAgentSessionKey(rawSessionKey);
const compatibilityDefaultAgentId = tryResolveSessionCompatibilityOwnerAgentId(abortCfg, rawSessionKey);
const bareSessionAgentResolution = !parsedAbortSessionKey ? resolveRequestedSessionAgentId(abortCfg, rawSessionKey, agentIdOverride) : void 0;
if (bareSessionAgentResolution && !bareSessionAgentResolution.ok) {
respond(false, void 0, bareSessionAgentResolution.error);
return;
}
const abortAgentId = parsedAbortSessionKey ? agentIdOverride ?? normalizeAgentId(parsedAbortSessionKey.agentId) : 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
});
if (discardPendingInput && isIncognitoSessionKey(canonicalAbortSessionKey)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "Removing accepted queued input is unavailable in incognito sessions. Use Stop to cancel it."));
return;
}
const narrow = authority.sessionScope === "operator.sessions.write" || requester.sessionAuthority !== void 0;
const admittedTarget = sessionMutationAuthorization?.admittedTarget;
if (narrow && (!admittedTarget?.sessionId.trim() || admittedTarget.sessionKey !== canonicalAbortSessionKey || admittedTarget.agentId !== normalizeAgentId(abortAgentId))) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "session target is unavailable"));
return;
}
const requiredSessionId = narrow ? admittedTarget?.sessionId : void 0;
const ops = createChatAbortOps(context);
const abortSession = (() => {
try {
return {
ok: true,
value: loadGatewaySessionEntry(canonicalAbortSessionKey, { agentId: abortAgentId })
};
} catch (error) {
return {
ok: false,
error
};
}
})();
const abortSessionEntry = abortSession.ok ? abortSession.value.entry : void 0;
if (!runId) {
const res = await abortChatRunsForSessionKeyWithPartials({
context,
ops,
sessionKey: canonicalAbortSessionKey,
sessionKeyAliases: canonicalAbortSessionKey === rawSessionKey ? void 0 : [rawSessionKey],
agentId: abortAgentId,
sessionId: abortSessionEntry?.sessionId,
requiredSessionId,
session: abortSession,
defaultAgentId: compatibilityDefaultAgentId,
abortOrigin: "rpc",
stopReason: "rpc",
requester,
assertCurrent,
preserveSideRuns,
onAuthorizedAfterQueuedAbort: lifecycle.onAuthorizedAfterQueuedAbort,
cascadeDescendants: lifecycle.cascadeDescendants
});
if (res.unauthorized) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
if (res.descendants?.killed || res.descendants?.continuationRetired) lifecycle.onDescendantsCancelled?.();
const error = res.error ?? descendantAbortError(res.descendants, "Session");
if (error) {
respond(false, void 0, withAbortedPartialPersistenceWarning(error, res.warning));
return;
}
respond(true, {
ok: true,
aborted: res.aborted,
runIds: res.runIds,
...res.warning ? { warning: res.warning } : {}
});
return;
}
const normalizedAgentIdOverride = normalizeAgentId(abortAgentId);
const authorizeRunTarget = (target) => {
let error;
if (discardPendingInput && target.sessionKey !== rawSessionKey && target.sessionKey !== canonicalAbortSessionKey) error = "discarded input runId does not match sessionKey";
else if (narrow && target.sessionId !== requiredSessionId) error = "runId does not match session incarnation";
else if (target.sessionKey !== rawSessionKey && target.sessionKey !== canonicalAbortSessionKey && (narrow || !canRequesterAbortChatRun(target, requester, { requireOwnerMatch: true }))) error = "runId does not match sessionKey";
else if (!chatRunBelongsToAgent({
agentId: target.agentId,
sessionKey: target.sessionKey,
defaultAgentId: compatibilityDefaultAgentId
}, normalizedAgentIdOverride)) error = "runId does not match agentId";
else if (!canRequesterAbortChatRun(target, requester)) error = "unauthorized";
if (error) respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, error));
return error === void 0;
};
const active = context.chatAbortControllers.get(runId);
const withdrawalQueue = discardPendingInput ? context.chatQueuedTurns.get(runId) : void 0;
const withdrawalScope = withdrawalQueue && {
sessionKey: withdrawalQueue.sessionKey,
sessionId: withdrawalQueue.sessionId,
agentId: withdrawalQueue.agentId
};
const ownsWithdrawalQueue = () => Boolean(withdrawalQueue && withdrawalScope && context.chatQueuedTurns.get(runId) === withdrawalQueue && isQueuedChatTurnForSession(context.chatQueuedTurns, runId, withdrawalScope));
if (discardPendingInput) {
if (active && !authorizeRunTarget(active) || withdrawalQueue && !authorizeRunTarget(withdrawalQueue)) return;
if (!ownsWithdrawalQueue() || active && withdrawalQueue?.controller !== active.controller) {
respond(true, {
ok: true,
aborted: false,
runIds: []
});
return;
}
}
const workerTarget = getWorkerInferenceSessionControl(context.workerEnvironmentService)?.resolveSessionTargetForRunId(runId);
const workerCancellation = captureWorkerInferenceForSession({
context,
sessionId: active?.sessionId ?? workerTarget?.sessionId ?? abortSessionEntry?.sessionId,
runId
});
let inputWithdrawn = false;
const holdPendingInputWithdrawal = (controller) => {
if (!discardPendingInput) return;
const queued = withdrawalQueue?.controller === controller ? withdrawalQueue : void 0;
const activeCurrent = active && captureAbortTargetIdentity(context.chatAbortControllers, runId, active);
const queuedCurrent = queued && captureAbortTargetIdentity(context.chatQueuedTurns, runId, queued);
const release = queued?.holdPendingInputWithdrawal?.();
if (!queued || !release) throw new Error("Queued input is already starting; refresh before removing it.");
return () => {
try {
if (!inputWithdrawn || controller.signal.aborted) return;
if (active && active.controller === controller && activeCurrent?.()) abortChatRunById(ops, {
runId,
sessionKey: active.sessionKey,
stopReason: "rpc"
});
if (!controller.signal.aborted && queued.controller === controller && queuedCurrent?.()) abortQueuedChatTurnById(context.chatQueuedTurns, {
runId,
sessionKey: queued.sessionKey,
stopReason: "rpc"
});
} finally {
release();
}
};
};
const discardBeforeAbort = async (target, ownsTarget) => {
if (!abortSession.ok) throw abortSession.error;
const captured = {
agentId: target.agentId ?? abortAgentId,
sessionKey: target.sessionKey,
sessionId: target.sessionId,
storePath: abortSession.value.storePath
};
inputWithdrawn = await discardSessionPendingInput(captured, runId, () => {
assertCurrent();
if (!ownsTarget()) throw new Error("Run changed before input removal; refresh and retry.");
});
if (inputWithdrawn) emitSessionsChanged(context, {
sessionKey: captured.sessionKey,
sessionId: captured.sessionId,
agentId: captured.agentId,
reason: "agent.input.settled"
}, { accessChanged: false });
};
const respondWithWorkerRuns = async (localRunIds, warning, commandsAborted = false) => {
const runIds = new Set(localRunIds);
if (inputWithdrawn) runIds.add(runId);
if (requester.isAdmin) {
assertCurrent();
await workerCancellation?.cancel({
assertCurrent,
onCancelled: (id) => runIds.add(id)
});
}
if (!abortSession.ok) throw abortSession.error;
respond(true, {
ok: true,
aborted: runIds.size > 0 || commandsAborted,
runIds: [...runIds],
...warning ? { warning } : {}
});
};
if (!active) {
const readPendingRunForAbort = (entry) => {
for (const sessionKey of /* @__PURE__ */ new Set([canonicalAbortSessionKey, rawSessionKey])) {
const payload = readPreRegisteredAgentDedupePayloadForSession({
entry,
runId,
sessionKey,
agentId: abortAgentId,
defaultAgentId: compatibilityDefaultAgentId,
requiredSessionId
});
if (payload) return {
sessionKey: normalizeOptionalString(payload.sessionKey) ? sessionKey : void 0,
payload
};
}
};
const pendingChatMatch = !discardPendingInput && readPendingRunForAbort(context.dedupe.get(pendingChatSendDedupeKey(runId)));
if (pendingChatMatch) {
if (!canRequesterAbortPreRegisteredRun(pendingChatMatch.payload, requester)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
assertCurrent();
await respondWithWorkerRuns(writePreRegisteredChatAbort({
context,
runId,
stopReason: "rpc",
attemptId: normalizeOptionalString(pendingChatMatch.payload.attemptId),
expectedPayload: pendingChatMatch.payload
}) ? [runId] : []);
return;
}
const pendingAgentEntry = context.dedupe.get(`agent:${runId}`);
const pendingAgentMatch = !discardPendingInput && readPendingRunForAbort(pendingAgentEntry);
if (pendingAgentMatch) {
const pendingAgentPayload = pendingAgentMatch.payload;
if (!canRequesterAbortPreRegisteredRun(pendingAgentPayload, requester)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
let aborted = false;
const descendants = await abortControlledSubagents({
cfg: abortCfg,
sessionKey: pendingAgentMatch.sessionKey ?? canonicalAbortSessionKey,
agentId: abortAgentId,
requesterTurnRunId: runId,
assertCurrent,
beforeKill: () => {
assertCurrent();
return aborted = writePreRegisteredAgentAbort({
context,
runId,
sessionKey: pendingAgentMatch.sessionKey,
payload: pendingAgentPayload,
expectedPayload: pendingAgentPayload,
stopReason: "rpc"
});
}
});
const error = descendantAbortError(descendants, "Parent run");
if (error) {
respond(false, void 0, error);
return;
}
await respondWithWorkerRuns(aborted ? [runId] : []);
return;
}
const chatQueuedTurns = context.chatQueuedTurns;
const queued = chatQueuedTurns.get(runId);
if (queued) {
if (!discardPendingInput && !authorizeRunTarget(queued)) return;
const { sessionKey, sessionId, agentId } = queued;
const isQueuedCurrent = captureAbortTargetIdentity(chatQueuedTurns, runId, queued);
const ownsTarget = () => chatQueuedTurns.get(runId) === queued && isQueuedChatTurnForSession(chatQueuedTurns, runId, {
sessionKey,
sessionId,
agentId
});
const releaseWithdrawal = holdPendingInputWithdrawal(queued.controller);
try {
if (discardPendingInput) {
await discardBeforeAbort(queued, ownsTarget);
if (!inputWithdrawn) {
respond(true, {
ok: true,
aborted: false,
runIds: []
});
return;
}
}
assertCurrent();
if (discardPendingInput && !ownsTarget()) {
await respondWithWorkerRuns([]);
return;
}
if (!isQueuedCurrent()) throw new Error("Run changed before cancellation; retry Stop.");
await respondWithWorkerRuns(abortQueuedChatTurnById(chatQueuedTurns, {
runId,
sessionKey: queued.sessionKey,
stopReason: "rpc",
allowSessionMismatch: true
}).aborted ? [runId] : []);
} finally {
releaseWithdrawal?.();
}
return;
}
const commands = captureExecRequestCancellation({
runId,
sessionKey: canonicalAbortSessionKey,
sessionId: abortSessionEntry?.sessionId,
agentId: abortAgentId
});
if (!discardPendingInput && commands.owners.length > 0) {
for (const owner of commands.owners) {
const identity = owner.identity;
if (!identity.sessionKey || !identity.sessionId || !canRequesterAbortChatRun(identity, requester, { requireOwnerMatch: true })) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "unauthorized"));
return;
}
if (!authorizeRunTarget({
...identity,
sessionKey: identity.sessionKey,
sessionId: identity.sessionId
})) return;
}
const descendants = await abortControlledSubagents({
cfg: abortCfg,
sessionKey: canonicalAbortSessionKey,
agentId: abortAgentId,
sessionId: abortSessionEntry?.sessionId,
requesterTurnRunId: runId,
execCancellation: commands,
assertCurrent,
beforeKill: () => {
assertCurrent();
if (context.chatAbortControllers.has(runId)) throw new Error("Run changed before cancellation; retry Stop.");
return true;
}
});
const error = descendantAbortError(descendants, "Parent run");
if (error) {
respond(false, void 0, error);
return;
}
await respondWithWorkerRuns([], void 0, descendants?.execAborted);
return;
}
if (!workerCancellation?.runIds.length) {
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;
}
await respondWithWorkerRuns([]);
return;
}
if (!discardPendingInput && !authorizeRunTarget(active)) return;
let aborted = false;
const { sessionKey, sessionId, agentId, controlUiVisible } = active;
const isActiveCurrent = captureAbortTargetIdentity(context.chatAbortControllers, runId, active);
const ownsTarget = () => isActiveCurrent() && isChatAbortControllerEntryAbortable(active) && (!discardPendingInput || ownsWithdrawalQueue());
const releaseWithdrawal = holdPendingInputWithdrawal(active.controller);
try {
if (discardPendingInput) {
await discardBeforeAbort(active, ownsTarget);
if (!inputWithdrawn) {
respond(true, {
ok: true,
aborted: false,
runIds: []
});
return;
}
}
assertCurrent();
if (discardPendingInput && !ownsTarget()) {
await respondWithWorkerRuns([]);
return;
}
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",
resolveTerminalProducer: active.resolveTerminalProducer,
...sessionKey === rawSessionKey || sessionKey === canonicalAbortSessionKey ? { session: abortSession } : {}
}) : void 0;
let descendants;
let failure;
let warning;
try {
descendants = await abortControlledSubagents({
cfg: abortCfg,
sessionKey,
agentId,
requesterTurnRunId: runId,
assertCurrent,
beforeKill: () => {
assertCurrent();
if (!isActiveCurrent()) {
if (inputWithdrawn) return false;
throw new Error("Run changed before cancellation; retry Stop.");
}
return abortChatRunById(ops, {
runId,
sessionKey,
stopReason: "rpc",
onAbortCommitted: () => {
aborted = true;
deferAbortedPartialPersistence(snapshot, context);
}
}).aborted;
}
});
} catch (error) {
failure = { error };
}
if (aborted && snapshot) try {
warning = await persistAbortedPartials({
context,
snapshots: [snapshot]
});
} catch (error) {
if (failure) throw new AggregateError([failure.error, error], "Chat cancellation and persistence failed", { cause: error });
throw error;
}
if (failure) throw abortedPartialPersistenceError(failure.error, warning);
if (!abortSession.ok) throw abortedPartialPersistenceError(abortSession.error, warning);
const descendantError = descendantAbortError(descendants, "Parent run");
if (descendantError) {
respond(false, void 0, withAbortedPartialPersistenceWarning(descendantError, warning));
return;
}
try {
await respondWithWorkerRuns(aborted ? [runId] : [], warning);
} catch (error) {
throw abortedPartialPersistenceError(error, warning);
}
} finally {
releaseWithdrawal?.();
}
}
async function handleChatAbortRequest(options) {
if (validateChatAbortParams(options.params)) options.context.logGateway.info(formatStopRequest("chat.abort", options.client, options.params));
try {
await handleChatAbortRequestWithLifecycle(options);
} catch (error) {
const contention = resolveStateContentionPresentation(error);
if (!contention) throw error;
options.respond(false, void 0, errorShape(ErrorCodes.UNAVAILABLE, "The server is busy. Check this turn's status before trying Stop again.\n\nSQLite transaction admission remained busy. Stopping may already have taken effect.", { details: { errorKind: contention.errorKind } }));
}
}
//#endregion
export { handleChatAbortRequestWithLifecycle as n, handleChatAbortRequest as t };