UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

158 lines (157 loc) 7.99 kB
import { k as withTimeout } from "./fs-safe-B6pvPGnf.js"; import { f as isCompetingSessionWorkAdmissionActive, g as startSessionWorkAdmissionInterruption, h as runExclusiveSessionLifecycleMutation, i as closeSessionWorkAdmissions, t as SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS } from "./session-lifecycle-admission-CS8v45tk.js"; import { s as createAgentRunDirectAbortError } from "./run-termination-jabvTOp5.js"; import { h as replyRunRegistry, n as abortReplyRunBySessionId, u as isReplyRunActiveForSessionId, x as waitForReplyRunEndBySessionId } from "./reply-run-registry.registry-BMo0d96L.js"; import "./reply-run-registry-BlmBKV23.js"; import { N as waitForEmbeddedAgentRunEnd, f as isEmbeddedAgentRunInProgress, n as abortEmbeddedAgentRun } from "./runs-Cb42qain.js"; import { a as getCommandLaneSnapshot } from "./command-queue-C3Fv2rcU.js"; import { s as hasPendingFollowupQueueWork } from "./settings-jmDsm5RI.js"; import { t as resolveEmbeddedSessionLane } from "./lanes-CVttd5qX.js"; import { t as clearSessionQueues } from "./cleanup-DKkilV3a.js"; import { i as prepareSessionWorkerPlacementStop, n as prepareSessionWorkerPlacementMutationCheck } from "./session-placement-lifecycle-7DQHpaT9.js"; import { m as waitForChatAbortControllerRemoval } from "./chat-abort-qLn3eFOg.js"; import { o as hasGatewaySessionAbortOwner, t as abortChatRunsForSessionKeyWithPartials } from "./chat-abort-runtime-CKI3fkKr.js"; import { t as createChatAbortOps } from "./chat-abort-ops-zvMvu0-3.js"; import { t as asWorkerInferenceControl } from "./inference-control-CDvM08Nt.js"; import { t as beginWorkerInferenceSessionDrain } from "./inference-control-internal-CQh2JfZC.js"; //#region src/gateway/server-methods/sessions-lifecycle-drain.ts function hasAuthoritativeSessionWork(params, workerDrain, terminalDrain, workIdentities) { const sessionId = params.sessionId; return isCompetingSessionWorkAdmissionActive(params.storePath, params.lifecycleIdentities) || params.sessionKeys.some((key) => replyRunRegistry.isActive(key)) || Boolean(sessionId && isReplyRunActiveForSessionId(sessionId)) || Boolean(sessionId && isEmbeddedAgentRunInProgress(sessionId)) || hasPendingFollowupQueueWork(workIdentities) || workIdentities.some((key) => getCommandLaneSnapshot(resolveEmbeddedSessionLane(key)).queuedCount > 0) || hasGatewaySessionAbortOwner({ context: params.context, sessionKeys: params.sessionKeys, sessionId, agentId: params.agentId, defaultAgentId: params.defaultAgentId }) || Boolean(sessionId && params.context.workerSessionPlacementService?.getMany([sessionId]).get(sessionId)?.turnClaim) || workerDrain?.hasWork() === true || terminalDrain?.hasWork() === true; } /** Drain outside mutation locks; retain the closure until the final mutation owns ingress. */ async function prepareSessionLifecycleDrain(params) { const timeoutMs = SESSION_WORK_ADMISSION_DRAIN_TIMEOUT_MS; const workIdentities = Array.from(/* @__PURE__ */ new Set([...params.sessionKeys, ...params.sessionId ? [params.sessionId] : []])); const workerService = params.context.workerEnvironmentService; const workerControl = asWorkerInferenceControl(workerService); let workerDrain; let terminalDrain; let releaseAdmissions = () => {}; let released = false; const release = () => { if (released) return; released = true; try { terminalDrain?.release(); } finally { try { workerDrain?.release(); } finally { releaseAdmissions(); } } }; try { const prepared = await runExclusiveSessionLifecycleMutation({ scope: params.storePath, identities: params.lifecycleIdentities, run: async () => { params.authorize?.(); params.beforeCancel?.(); const reclaim = prepareSessionWorkerPlacementStop(params); releaseAdmissions = closeSessionWorkAdmissions({ scope: params.storePath, identities: params.lifecycleIdentities, reason: createAgentRunDirectAbortError() }); if (params.sessionId) { workerDrain = beginWorkerInferenceSessionDrain(workerService, params.sessionId); if (!workerDrain && workerControl?.hasInferenceForSession(params.sessionId) === true) throw new Error("Worker inference drain is unavailable"); terminalDrain = params.context.terminalSessions?.beginAgentSessionDrain({ kind: "agent", agentSessionKey: params.sessionKey, agentSessionId: params.sessionId, agentId: params.agentId }); } let controllerDrain = Promise.resolve(true); const cancellation = abortChatRunsForSessionKeyWithPartials({ context: params.context, ops: createChatAbortOps(params.context), sessionKey: params.sessionKeys[0], sessionKeyAliases: params.sessionKeys.slice(1), sessionId: params.sessionId, agentId: params.agentId, defaultAgentId: params.defaultAgentId, abortOrigin: "rpc", stopReason: params.action, requester: { isAdmin: true }, includeProtectedRuns: true, onControllerTargets: (targets) => { controllerDrain = waitForChatAbortControllerRemoval({ entries: params.context.chatAbortControllers, targets, timeoutMs }); }, onAuthorizedAfterQueuedAbort: () => { const cleared = clearSessionQueues(workIdentities); let aborted = cleared.followupCleared > 0 || cleared.laneCleared > 0; for (const key of params.sessionKeys) aborted = replyRunRegistry.abort(key) || aborted; if (params.sessionId) { aborted = abortReplyRunBySessionId(params.sessionId) || aborted; aborted = abortEmbeddedAgentRun(params.sessionId) || aborted; } return aborted; } }); cancellation.catch(() => {}); return { reclaim, cancellation, controllerDrain }; } }); if ((await prepared.cancellation).unauthorized) throw new Error("Session cancellation lost ownership"); params.authorize?.(); const { released: admittedWork } = startSessionWorkAdmissionInterruption({ scope: params.storePath, identities: params.lifecycleIdentities }); const replyWork = Promise.all([...params.sessionKeys.map((key) => replyRunRegistry.waitForIdle(key, timeoutMs)), ...params.sessionId ? [waitForReplyRunEndBySessionId(params.sessionId, timeoutMs)] : []]).then((results) => results.every(Boolean)); const embeddedWork = params.sessionId ? waitForEmbeddedAgentRunEnd(params.sessionId, timeoutMs) : Promise.resolve(true); const placementService = params.context.workerSessionPlacementService; const placementWork = (params.sessionId ? placementService?.getMany([params.sessionId]).get(params.sessionId) : void 0)?.turnClaim ? placementService?.waitForTurnClaimRelease ? placementService.waitForTurnClaimRelease(params.sessionId, { timeoutMs }).then(() => true) : Promise.resolve(false) : Promise.resolve(true); const workerWork = workerDrain ? withTimeout(workerDrain.drained, timeoutMs, "worker inference lifecycle drain").then(() => true) : Promise.resolve(true); const terminalWork = terminalDrain ? withTimeout(terminalDrain.drained, timeoutMs, "agent terminal lifecycle drain").then(() => true) : Promise.resolve(true); if (!(await Promise.all([ prepared.controllerDrain, replyWork, embeddedWork, placementWork, workerWork, terminalWork ])).every(Boolean)) throw new Error("Session work is still active after the lifecycle drain"); await prepared.reclaim(); await withTimeout(admittedWork, timeoutMs, "session work admission lifecycle drain"); const assertPlacementCurrent = prepareSessionWorkerPlacementMutationCheck({ context: params.context, sessionId: params.sessionId }); return { handoffToMutation: () => releaseAdmissions(), release, hasAuthoritativeWork: () => { try { assertPlacementCurrent(); } catch { return true; } return hasAuthoritativeSessionWork(params, workerDrain, terminalDrain, workIdentities); } }; } catch (error) { release(); throw error; } } //#endregion export { prepareSessionLifecycleDrain as t };