import type { OpenClawConfig } from "../../config/config.js"; import { cancelTaskById, listTasksForFlowId } from "../../tasks/runtime-internal.js"; import { mapTaskFlowDetail, mapTaskFlowView, mapTaskRunAggregateSummary, mapTaskRunDetail, mapTaskRunView, } from "../../tasks/task-domain-views.js"; import { getFlowTaskSummary } from "../../tasks/task-executor.js"; import { getTaskFlowByIdForOwner, listTaskFlowsForOwner, findLatestTaskFlowForOwner, resolveTaskFlowForLookupTokenForOwner, } from "../../tasks/task-flow-owner-access.js"; import { findLatestTaskForRelatedSessionKeyForOwner, getTaskByIdForOwner, listTasksForRelatedSessionKeyForOwner, resolveTaskForLookupTokenForOwner, } from "../../tasks/task-owner-access.js"; import { normalizeDeliveryContext } from "../../utils/delivery-context.js"; import type { OpenClawPluginToolContext } from "../types.js"; import type { PluginRuntimeTaskFlow } from "./runtime-taskflow.js"; import type { TaskFlowDetail, TaskFlowView, TaskRunAggregateSummary, TaskRunCancelResult, TaskRunDetail, TaskRunView, } from "./task-domain-types.js"; function assertSessionKey(sessionKey: string | undefined, errorMessage: string): string { const normalized = sessionKey?.trim(); if (!normalized) { throw new Error(errorMessage); } return normalized; } function mapCancelledTaskResult( result: Awaited>, ): TaskRunCancelResult { return { found: result.found, cancelled: result.cancelled, ...(result.reason ? { reason: result.reason } : {}), ...(result.task ? { task: mapTaskRunDetail(result.task) } : {}), }; } export type BoundTaskRunsRuntime = { readonly sessionKey: string; readonly requesterOrigin?: ReturnType; get: (taskId: string) => TaskRunDetail | undefined; list: () => TaskRunView[]; findLatest: () => TaskRunDetail | undefined; resolve: (token: string) => TaskRunDetail | undefined; cancel: (params: { taskId: string; cfg: OpenClawConfig }) => Promise; }; export type PluginRuntimeTaskRuns = { bindSession: (params: { sessionKey: string; requesterOrigin?: import("../../tasks/task-registry.types.js").TaskDeliveryState["requesterOrigin"]; }) => BoundTaskRunsRuntime; fromToolContext: ( ctx: Pick, ) => BoundTaskRunsRuntime; }; export type BoundTaskFlowsRuntime = { readonly sessionKey: string; readonly requesterOrigin?: ReturnType; get: (flowId: string) => TaskFlowDetail | undefined; list: () => TaskFlowView[]; findLatest: () => TaskFlowDetail | undefined; resolve: (token: string) => TaskFlowDetail | undefined; getTaskSummary: (flowId: string) => TaskRunAggregateSummary | undefined; }; export type PluginRuntimeTaskFlows = { bindSession: (params: { sessionKey: string; requesterOrigin?: import("../../tasks/task-registry.types.js").TaskDeliveryState["requesterOrigin"]; }) => BoundTaskFlowsRuntime; fromToolContext: ( ctx: Pick, ) => BoundTaskFlowsRuntime; }; export type PluginRuntimeTasks = { runs: PluginRuntimeTaskRuns; flows: PluginRuntimeTaskFlows; /** @deprecated Use runtime.tasks.flows for DTO-based TaskFlow access. */ flow: PluginRuntimeTaskFlow; }; function createBoundTaskRunsRuntime(params: { sessionKey: string; requesterOrigin?: import("../../tasks/task-registry.types.js").TaskDeliveryState["requesterOrigin"]; }): BoundTaskRunsRuntime { const ownerKey = assertSessionKey( params.sessionKey, "Tasks runtime requires a bound sessionKey.", ); const requesterOrigin = params.requesterOrigin ? normalizeDeliveryContext(params.requesterOrigin) : undefined; return { sessionKey: ownerKey, ...(requesterOrigin ? { requesterOrigin } : {}), get: (taskId) => { const task = getTaskByIdForOwner({ taskId, callerOwnerKey: ownerKey }); return task ? mapTaskRunDetail(task) : undefined; }, list: () => listTasksForRelatedSessionKeyForOwner({ relatedSessionKey: ownerKey, callerOwnerKey: ownerKey, }).map((task) => mapTaskRunView(task)), findLatest: () => { const task = findLatestTaskForRelatedSessionKeyForOwner({ relatedSessionKey: ownerKey, callerOwnerKey: ownerKey, }); return task ? mapTaskRunDetail(task) : undefined; }, resolve: (token) => { const task = resolveTaskForLookupTokenForOwner({ token, callerOwnerKey: ownerKey, }); return task ? mapTaskRunDetail(task) : undefined; }, cancel: async ({ taskId, cfg }) => { const task = getTaskByIdForOwner({ taskId, callerOwnerKey: ownerKey, }); if (!task) { return { found: false, cancelled: false, reason: "Task not found.", }; } return mapCancelledTaskResult( await cancelTaskById({ cfg, taskId: task.taskId, }), ); }, }; } function createBoundTaskFlowsRuntime(params: { sessionKey: string; requesterOrigin?: import("../../tasks/task-registry.types.js").TaskDeliveryState["requesterOrigin"]; }): BoundTaskFlowsRuntime { const ownerKey = assertSessionKey( params.sessionKey, "TaskFlow runtime requires a bound sessionKey.", ); const requesterOrigin = params.requesterOrigin ? normalizeDeliveryContext(params.requesterOrigin) : undefined; const getDetail = (flowId: string): TaskFlowDetail | undefined => { const flow = getTaskFlowByIdForOwner({ flowId, callerOwnerKey: ownerKey, }); if (!flow) { return undefined; } const tasks = listTasksForFlowId(flow.flowId); return mapTaskFlowDetail({ flow, tasks, summary: getFlowTaskSummary(flow.flowId), }); }; return { sessionKey: ownerKey, ...(requesterOrigin ? { requesterOrigin } : {}), get: (flowId) => getDetail(flowId), list: () => listTaskFlowsForOwner({ callerOwnerKey: ownerKey, }).map((flow) => mapTaskFlowView(flow)), findLatest: () => { const flow = findLatestTaskFlowForOwner({ callerOwnerKey: ownerKey, }); return flow ? getDetail(flow.flowId) : undefined; }, resolve: (token) => { const flow = resolveTaskFlowForLookupTokenForOwner({ token, callerOwnerKey: ownerKey, }); return flow ? getDetail(flow.flowId) : undefined; }, getTaskSummary: (flowId) => { const flow = getTaskFlowByIdForOwner({ flowId, callerOwnerKey: ownerKey, }); return flow ? mapTaskRunAggregateSummary(getFlowTaskSummary(flow.flowId)) : undefined; }, }; } export function createRuntimeTaskRuns(): PluginRuntimeTaskRuns { return { bindSession: (params) => createBoundTaskRunsRuntime({ sessionKey: params.sessionKey, requesterOrigin: params.requesterOrigin, }), fromToolContext: (ctx) => createBoundTaskRunsRuntime({ sessionKey: assertSessionKey( ctx.sessionKey, "Tasks runtime requires tool context with a sessionKey.", ), requesterOrigin: ctx.deliveryContext, }), }; } export function createRuntimeTaskFlows(): PluginRuntimeTaskFlows { return { bindSession: (params) => createBoundTaskFlowsRuntime({ sessionKey: params.sessionKey, requesterOrigin: params.requesterOrigin, }), fromToolContext: (ctx) => createBoundTaskFlowsRuntime({ sessionKey: assertSessionKey( ctx.sessionKey, "TaskFlow runtime requires tool context with a sessionKey.", ), requesterOrigin: ctx.deliveryContext, }), }; } export function createRuntimeTasks(params: { legacyTaskFlow: PluginRuntimeTaskFlow; }): PluginRuntimeTasks { return { runs: createRuntimeTaskRuns(), flows: createRuntimeTaskFlows(), flow: params.legacyTaskFlow, }; }