Files
openclaw/src/gateway/server-active-work.ts
Peter Steinberger 1bcc4c5e70 feat(gateway): add cooperative host suspension (#103618)
* feat(gateway): add cooperative suspension preparation

* style: satisfy suspension lint checks

* test(gateway): reset work admission between shared suites

* fix(gateway): reject upgrades during suspension

* fix(gateway): preserve admitted work during suspension

* test(gateway): isolate suspension and restart state

* fix(gateway): close suspension false-ready gaps

* refactor(protocol): slim suspension declaration graph

* refactor(plugin-sdk): sever protocol registry edges

* fix(gateway): preserve admitted restart follow-ups

* fix(gateway): make suspension recovery fail closed

* fix(protocol): keep validation formatter re-export only

* test(gateway): simplify deferred fixture type

* style(gateway): clarify suspension entry name

* fix(gateway): retain detached work admission
2026-07-10 20:24:53 +01:00

36 lines
1.6 KiB
TypeScript

// Adapts server-local chat and terminal state to the shared activity inspector.
import { getActiveCronJobCount } from "../cron/active-jobs.js";
import type { GatewayActiveWorkInspectors } from "../infra/gateway-active-work.js";
import { getSuspensionVisibleCronTaskRunCount } from "../tasks/cron-task-cancel.js";
import type { GatewayRequestContext } from "./server-methods/shared-types.js";
export function createGatewayServerActiveWorkInspectors(
context: Pick<
GatewayRequestContext,
"chatAbortControllers" | "chatQueuedTurns" | "cron" | "terminalSessions"
>,
): Partial<GatewayActiveWorkInspectors> {
return {
getCronRuns: () =>
Math.max(getActiveCronJobCount(), getSuspensionVisibleCronTaskRunCount()) +
(context.cron.getSuspensionBlockerCount?.() ?? 0),
getChatRuns: () =>
Array.from(context.chatAbortControllers.values()).filter(
(entry) => !entry.controller.signal.aborted && entry.registrationCleanupRequested !== true,
).length,
getQueuedTurns: () =>
Array.from(context.chatQueuedTurns.values()).filter(
(entry) => !entry.controller.signal.aborted,
).length,
getTerminalPersistence: () =>
Array.from(context.chatAbortControllers.values()).filter(
(entry) =>
entry.controlUiVisible !== false &&
entry.projectSessionTerminalPersisted !== true &&
(entry.projectSessionTerminalPending === true ||
entry.projectSessionTerminalPersistence !== undefined),
).length,
getTerminalSessions: () => context.terminalSessions?.size ?? 0,
};
}