From af428d9b8a5bcb6f6ec770984e3741e3c7e0d97c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 11 Apr 2026 13:25:55 +0100 Subject: [PATCH] fix(cycles): split runtime taskflow type surface --- src/config/sessions/runtime-types.ts | 45 ++++++ src/plugins/runtime/runtime-taskflow.ts | 143 +----------------- src/plugins/runtime/runtime-taskflow.types.ts | 141 +++++++++++++++++ src/plugins/runtime/runtime-tasks.ts | 2 +- src/plugins/runtime/types-core.ts | 6 +- 5 files changed, 198 insertions(+), 139 deletions(-) create mode 100644 src/plugins/runtime/runtime-taskflow.types.ts diff --git a/src/config/sessions/runtime-types.ts b/src/config/sessions/runtime-types.ts index ad415929c31..a8282ceff8b 100644 --- a/src/config/sessions/runtime-types.ts +++ b/src/config/sessions/runtime-types.ts @@ -1,5 +1,6 @@ import type { MsgContext } from "../../auto-reply/templating.js"; import type { DeliveryContext } from "../../utils/delivery-context.shared.js"; +import type { SessionMaintenanceMode } from "../types.base.js"; import type { SessionEntry, GroupKeyResolution } from "./types.js"; export type ReadSessionUpdatedAt = (params: { @@ -7,6 +8,50 @@ export type ReadSessionUpdatedAt = (params: { sessionKey: string; }) => number | undefined; +export type SessionMaintenanceWarningRuntime = { + activeSessionKey: string; + activeUpdatedAt?: number; + totalEntries: number; + pruneAfterMs: number; + maxEntries: number; + wouldPrune: boolean; + wouldCap: boolean; +}; + +export type ResolvedSessionMaintenanceConfigRuntime = { + mode: SessionMaintenanceMode; + pruneAfterMs: number; + maxEntries: number; + rotateBytes: number; + resetArchiveRetentionMs: number | null; + maxDiskBytes: number | null; + highWaterBytes: number | null; +}; + +export type SessionMaintenanceApplyReportRuntime = { + mode: SessionMaintenanceMode; + beforeCount: number; + afterCount: number; + pruned: number; + capped: number; + diskBudget: Record | null; +}; + +export type SaveSessionStoreOptions = { + skipMaintenance?: boolean; + activeSessionKey?: string; + allowDropAcpMetaSessionKeys?: string[]; + onWarn?: (warning: SessionMaintenanceWarningRuntime) => void | Promise; + onMaintenanceApplied?: (report: SessionMaintenanceApplyReportRuntime) => void | Promise; + maintenanceOverride?: Partial; +}; + +export type SaveSessionStore = ( + storePath: string, + store: Record, + opts?: SaveSessionStoreOptions, +) => Promise; + export type RecordSessionMetaFromInbound = (params: { storePath: string; sessionKey: string; diff --git a/src/plugins/runtime/runtime-taskflow.ts b/src/plugins/runtime/runtime-taskflow.ts index f5e33df137a..ce2336163e5 100644 --- a/src/plugins/runtime/runtime-taskflow.ts +++ b/src/plugins/runtime/runtime-taskflow.ts @@ -1,4 +1,3 @@ -import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { cancelFlowByIdForOwner, getFlowTaskSummary, @@ -10,7 +9,7 @@ import { listTaskFlowsForOwner, resolveTaskFlowForLookupTokenForOwner, } from "../../tasks/task-flow-owner-access.js"; -import type { TaskFlowRecord, JsonValue } from "../../tasks/task-flow-registry.types.js"; +import type { TaskFlowRecord } from "../../tasks/task-flow-registry.types.js"; import { createManagedTaskFlow, failFlow, @@ -20,140 +19,14 @@ import { resumeFlow, setFlowWaiting, } from "../../tasks/task-flow-runtime-internal.js"; -import type { - TaskDeliveryStatus, - TaskDeliveryState, - TaskNotifyPolicy, - TaskRecord, - TaskRegistrySummary, - TaskRuntime, -} from "../../tasks/task-registry.types.js"; +import type { TaskDeliveryState } from "../../tasks/task-registry.types.js"; import { normalizeDeliveryContext } from "../../utils/delivery-context.shared.js"; -import type { OpenClawPluginToolContext } from "../tool-types.js"; - -export type ManagedTaskFlowRecord = TaskFlowRecord & { - syncMode: "managed"; - controllerId: string; -}; - -export type ManagedTaskFlowMutationErrorCode = "not_found" | "not_managed" | "revision_conflict"; - -export type ManagedTaskFlowMutationResult = - | { - applied: true; - flow: ManagedTaskFlowRecord; - } - | { - applied: false; - code: ManagedTaskFlowMutationErrorCode; - current?: TaskFlowRecord; - }; - -export type BoundTaskFlowTaskRunResult = - | { - created: true; - flow: ManagedTaskFlowRecord; - task: TaskRecord; - } - | { - created: false; - reason: string; - found: boolean; - flow?: TaskFlowRecord; - }; - -export type BoundTaskFlowCancelResult = Awaited>; - -export type BoundTaskFlowRuntime = { - readonly sessionKey: string; - readonly requesterOrigin?: TaskDeliveryState["requesterOrigin"]; - createManaged: (params: { - controllerId: string; - goal: string; - status?: ManagedTaskFlowRecord["status"]; - notifyPolicy?: TaskNotifyPolicy; - currentStep?: string | null; - stateJson?: JsonValue | null; - waitJson?: JsonValue | null; - cancelRequestedAt?: number | null; - createdAt?: number; - updatedAt?: number; - endedAt?: number | null; - }) => ManagedTaskFlowRecord; - get: (flowId: string) => TaskFlowRecord | undefined; - list: () => TaskFlowRecord[]; - findLatest: () => TaskFlowRecord | undefined; - resolve: (token: string) => TaskFlowRecord | undefined; - getTaskSummary: (flowId: string) => TaskRegistrySummary | undefined; - setWaiting: (params: { - flowId: string; - expectedRevision: number; - currentStep?: string | null; - stateJson?: JsonValue | null; - waitJson?: JsonValue | null; - blockedTaskId?: string | null; - blockedSummary?: string | null; - updatedAt?: number; - }) => ManagedTaskFlowMutationResult; - resume: (params: { - flowId: string; - expectedRevision: number; - status?: Extract; - currentStep?: string | null; - stateJson?: JsonValue | null; - updatedAt?: number; - }) => ManagedTaskFlowMutationResult; - finish: (params: { - flowId: string; - expectedRevision: number; - stateJson?: JsonValue | null; - updatedAt?: number; - endedAt?: number; - }) => ManagedTaskFlowMutationResult; - fail: (params: { - flowId: string; - expectedRevision: number; - stateJson?: JsonValue | null; - blockedTaskId?: string | null; - blockedSummary?: string | null; - updatedAt?: number; - endedAt?: number; - }) => ManagedTaskFlowMutationResult; - requestCancel: (params: { - flowId: string; - expectedRevision: number; - cancelRequestedAt?: number; - }) => ManagedTaskFlowMutationResult; - cancel: (params: { flowId: string; cfg: OpenClawConfig }) => Promise; - runTask: (params: { - flowId: string; - runtime: TaskRuntime; - sourceId?: string; - childSessionKey?: string; - parentTaskId?: string; - agentId?: string; - runId?: string; - label?: string; - task: string; - preferMetadata?: boolean; - notifyPolicy?: TaskNotifyPolicy; - deliveryStatus?: TaskDeliveryStatus; - status?: "queued" | "running"; - startedAt?: number; - lastEventAt?: number; - progressSummary?: string | null; - }) => BoundTaskFlowTaskRunResult; -}; - -export type PluginRuntimeTaskFlow = { - bindSession: (params: { - sessionKey: string; - requesterOrigin?: TaskDeliveryState["requesterOrigin"]; - }) => BoundTaskFlowRuntime; - fromToolContext: ( - ctx: Pick, - ) => BoundTaskFlowRuntime; -}; +import type { + BoundTaskFlowRuntime, + ManagedTaskFlowMutationResult, + ManagedTaskFlowRecord, + PluginRuntimeTaskFlow, +} from "./runtime-taskflow.types.js"; function assertSessionKey(sessionKey: string | undefined, errorMessage: string): string { const normalized = sessionKey?.trim(); diff --git a/src/plugins/runtime/runtime-taskflow.types.ts b/src/plugins/runtime/runtime-taskflow.types.ts new file mode 100644 index 00000000000..cc58d666995 --- /dev/null +++ b/src/plugins/runtime/runtime-taskflow.types.ts @@ -0,0 +1,141 @@ +import type { OpenClawConfig } from "../../config/types.openclaw.js"; +import type { JsonValue, TaskFlowRecord } from "../../tasks/task-flow-registry.types.js"; +import type { + TaskDeliveryState, + TaskDeliveryStatus, + TaskNotifyPolicy, + TaskRecord, + TaskRegistrySummary, + TaskRuntime, +} from "../../tasks/task-registry.types.js"; +import type { OpenClawPluginToolContext } from "../tool-types.js"; + +export type ManagedTaskFlowRecord = TaskFlowRecord & { + syncMode: "managed"; + controllerId: string; +}; + +export type ManagedTaskFlowMutationErrorCode = "not_found" | "not_managed" | "revision_conflict"; + +export type ManagedTaskFlowMutationResult = + | { + applied: true; + flow: ManagedTaskFlowRecord; + } + | { + applied: false; + code: ManagedTaskFlowMutationErrorCode; + current?: TaskFlowRecord; + }; + +export type BoundTaskFlowTaskRunResult = + | { + created: true; + flow: ManagedTaskFlowRecord; + task: TaskRecord; + } + | { + created: false; + reason: string; + found: boolean; + flow?: TaskFlowRecord; + }; + +export type BoundTaskFlowCancelResult = { + found: boolean; + cancelled: boolean; + reason?: string; + flow?: TaskFlowRecord; + tasks?: TaskRecord[]; +}; + +export type BoundTaskFlowRuntime = { + readonly sessionKey: string; + readonly requesterOrigin?: TaskDeliveryState["requesterOrigin"]; + createManaged: (params: { + controllerId: string; + goal: string; + status?: ManagedTaskFlowRecord["status"]; + notifyPolicy?: TaskNotifyPolicy; + currentStep?: string | null; + stateJson?: JsonValue | null; + waitJson?: JsonValue | null; + cancelRequestedAt?: number | null; + createdAt?: number; + updatedAt?: number; + endedAt?: number | null; + }) => ManagedTaskFlowRecord; + get: (flowId: string) => TaskFlowRecord | undefined; + list: () => TaskFlowRecord[]; + findLatest: () => TaskFlowRecord | undefined; + resolve: (token: string) => TaskFlowRecord | undefined; + getTaskSummary: (flowId: string) => TaskRegistrySummary | undefined; + setWaiting: (params: { + flowId: string; + expectedRevision: number; + currentStep?: string | null; + stateJson?: JsonValue | null; + waitJson?: JsonValue | null; + blockedTaskId?: string | null; + blockedSummary?: string | null; + updatedAt?: number; + }) => ManagedTaskFlowMutationResult; + resume: (params: { + flowId: string; + expectedRevision: number; + status?: Extract; + currentStep?: string | null; + stateJson?: JsonValue | null; + updatedAt?: number; + }) => ManagedTaskFlowMutationResult; + finish: (params: { + flowId: string; + expectedRevision: number; + stateJson?: JsonValue | null; + updatedAt?: number; + endedAt?: number; + }) => ManagedTaskFlowMutationResult; + fail: (params: { + flowId: string; + expectedRevision: number; + stateJson?: JsonValue | null; + blockedTaskId?: string | null; + blockedSummary?: string | null; + updatedAt?: number; + endedAt?: number; + }) => ManagedTaskFlowMutationResult; + requestCancel: (params: { + flowId: string; + expectedRevision: number; + cancelRequestedAt?: number; + }) => ManagedTaskFlowMutationResult; + cancel: (params: { flowId: string; cfg: OpenClawConfig }) => Promise; + runTask: (params: { + flowId: string; + runtime: TaskRuntime; + sourceId?: string; + childSessionKey?: string; + parentTaskId?: string; + agentId?: string; + runId?: string; + label?: string; + task: string; + preferMetadata?: boolean; + notifyPolicy?: TaskNotifyPolicy; + deliveryStatus?: TaskDeliveryStatus; + status?: "queued" | "running"; + startedAt?: number; + lastEventAt?: number; + progressSummary?: string | null; + }) => BoundTaskFlowTaskRunResult; +}; + +export type PluginRuntimeTaskFlow = { + bindSession: (params: { + sessionKey: string; + requesterOrigin?: TaskDeliveryState["requesterOrigin"]; + }) => BoundTaskFlowRuntime; + fromToolContext: ( + ctx: Pick, + ) => BoundTaskFlowRuntime; +}; diff --git a/src/plugins/runtime/runtime-tasks.ts b/src/plugins/runtime/runtime-tasks.ts index a1ba7a130db..6952d8dad6f 100644 --- a/src/plugins/runtime/runtime-tasks.ts +++ b/src/plugins/runtime/runtime-tasks.ts @@ -22,7 +22,7 @@ import { } from "../../tasks/task-owner-access.js"; import { normalizeDeliveryContext } from "../../utils/delivery-context.shared.js"; import type { OpenClawPluginToolContext } from "../tool-types.js"; -import type { PluginRuntimeTaskFlow } from "./runtime-taskflow.js"; +import type { PluginRuntimeTaskFlow } from "./runtime-taskflow.types.js"; import type { TaskFlowDetail, TaskFlowView, diff --git a/src/plugins/runtime/types-core.ts b/src/plugins/runtime/types-core.ts index e842ecaa1a6..3ce3240b5fb 100644 --- a/src/plugins/runtime/types-core.ts +++ b/src/plugins/runtime/types-core.ts @@ -56,7 +56,7 @@ export type PluginRuntimeCore = { session: { resolveStorePath: typeof import("../../config/sessions/paths.js").resolveStorePath; loadSessionStore: typeof import("../../config/sessions/store-load.js").loadSessionStore; - saveSessionStore: typeof import("../../config/sessions/store.js").saveSessionStore; + saveSessionStore: import("../../config/sessions/runtime-types.js").SaveSessionStore; resolveSessionFilePath: typeof import("../../config/sessions/paths.js").resolveSessionFilePath; }; }; @@ -146,10 +146,10 @@ export type PluginRuntimeCore = { runs: import("./runtime-tasks.js").PluginRuntimeTaskRuns; flows: import("./runtime-tasks.js").PluginRuntimeTaskFlows; /** @deprecated Use runtime.tasks.flows for DTO-based TaskFlow access. */ - flow: import("./runtime-taskflow.js").PluginRuntimeTaskFlow; + flow: import("./runtime-taskflow.types.js").PluginRuntimeTaskFlow; }; /** @deprecated Use runtime.tasks.flows for DTO-based TaskFlow access. */ - taskFlow: import("./runtime-taskflow.js").PluginRuntimeTaskFlow; + taskFlow: import("./runtime-taskflow.types.js").PluginRuntimeTaskFlow; modelAuth: { /** Resolve auth for a model. Only provider/model and optional cfg are used. */ getApiKeyForModel: (params: {