UNPKG

@mastra/core

Version:
1 lines 19.7 kB
{"version":3,"file":"workflow-BHmP62a4.cjs","names":["z","createStep","createWorkflow","BACKGROUND_TASK_WORKFLOW_ID"],"sources":["../src/background-tasks/workflow.ts"],"sourcesContent":["import { z } from 'zod';\nimport { InternalSpans } from '../observability';\nimport type { SuspendOptions } from '../workflows';\nimport { createStep, createWorkflow } from '../workflows';\nimport type { BackgroundTaskManager } from './manager';\nimport type { BackgroundTaskStatus } from './types';\nimport { BACKGROUND_TASK_WORKFLOW_ID } from './workflow-id';\n\nexport { BACKGROUND_TASK_WORKFLOW_ID } from './workflow-id';\n\nconst inputSchema = z.object({ taskId: z.string() });\n\nconst attemptOutcomeSchema = z.enum(['success', 'retry', 'failed', 'cancelled', 'timed_out']);\n\nconst attemptOutputSchema = z.object({\n taskId: z.string(),\n outcome: attemptOutcomeSchema,\n result: z.unknown().optional(),\n error: z.any().optional(),\n});\n\nconst bodyIOSchema = z.object({\n taskId: z.string(),\n done: z.boolean().optional(),\n result: z.unknown().optional(),\n});\n\nconst bodyOutputSchema = z.object({\n taskId: z.string(),\n done: z.boolean(),\n result: z.unknown().optional(),\n});\n\nconst WORKFLOW_STATUS_TO_PERSIST = ['suspended', 'pending', 'paused', 'waiting'];\n\n/**\n * Builds the per-task workflow that owns executor + retries.\n *\n * Uses the standard (default) execution engine so the workflow runs entirely\n * in-process on whatever host calls `run.start()`. This is critical for\n * distributed deployments where the background-task worker must\n * execute tools locally — routing through the evented pipeline would send\n * step execution to the orchestration worker / API, which don't have the\n * internal workflow or task contexts registered.\n *\n * Shape: outer workflow runs an inner `[run-attempt, classify-outcome]`\n * workflow inside a `dountil` loop. `run-attempt` invokes the executor and\n * categorises the outcome; `classify-outcome` persists final state, advances\n * retry bookkeeping, and decides whether the loop is done. The dountil\n * predicate exits on `done === true`.\n *\n * Step bodies close over `manager` directly — the bg-tasks layer is the only\n * consumer of the `@internal` private fields.\n */\nexport function buildBackgroundTaskWorkflow(manager: BackgroundTaskManager) {\n const runAttemptStep = createStep({\n id: 'run-attempt',\n inputSchema: bodyIOSchema,\n outputSchema: attemptOutputSchema,\n execute: async ({ inputData, abortSignal: workflowAbortSignal, suspend, resumeData }) => {\n const { taskId } = inputData;\n const storage = await manager.getStorage();\n const task = await storage.getTask(taskId);\n if (!task || task.status === 'cancelled') {\n manager.deregisterTaskContext(taskId);\n return { taskId, outcome: 'cancelled' as const };\n }\n\n // Resolve the executor. Two paths:\n // 1. Per-task `TaskContext` registered on the producer (in-process).\n // Carries closure-captured state (e.g. agent memory hooks) and\n // wins when present.\n // 2. Static executor registered by tool name. Used by remote workers\n // that received the dispatch via PubSub and don't have access to\n // the producer's per-task closure. Agent-owned executors are\n // namespaced as `agentId:toolName` to avoid cross-agent collisions;\n // we try the namespaced key first, then fall back to the plain key.\n const ctx = manager.taskContexts.get(taskId);\n const executor =\n ctx?.executor ??\n (task.agentId ? manager.getStaticExecutor(`${task.agentId}:${task.toolName}`) : undefined) ??\n manager.getStaticExecutor(task.toolName);\n if (!executor) {\n const errorInfo = {\n message:\n `No executor registered for tool \"${task.toolName}\". ` +\n `Register the tool on Mastra (so workers can resolve it cross-process) ` +\n `or run the task in the same process as the producer.`,\n };\n await storage.updateTask(taskId, { status: 'failed', error: errorInfo, completedAt: new Date() });\n const failedTask = await storage.getTask(taskId);\n if (failedTask) {\n await manager.runLocalCompletionHooks(failedTask, 'failed', { error: errorInfo });\n await manager.publishLifecycleEvent('task.failed', failedTask);\n }\n manager.deregisterTaskContext(taskId);\n throw new Error(errorInfo.message);\n }\n\n // Throttled progress publisher.\n const progressThrottleMs = manager.config.progressThrottleMs;\n const shouldThrottleProgress =\n typeof progressThrottleMs === 'number' && Number.isFinite(progressThrottleMs) && progressThrottleMs > 0;\n let lastProgressEmitMs: number | undefined;\n const onProgress = async (chunk: any) => {\n if (shouldThrottleProgress) {\n const now = Date.now();\n if (lastProgressEmitMs !== undefined && now - lastProgressEmitMs < progressThrottleMs) return;\n lastProgressEmitMs = now;\n }\n await manager.publishLifecycleEvent('task.output', { ...task, chunk });\n };\n\n const abortController = new AbortController();\n manager.activeAbortControllers.set(taskId, abortController);\n // Wire the workflow's run-level abort signal into our local controller\n // so `workflow.getRun(taskId).cancel()` propagates to the executor.\n const onWorkflowAbort = () => abortController.abort(new Error('Task cancelled'));\n if (workflowAbortSignal.aborted) {\n abortController.abort(new Error('Task cancelled'));\n } else {\n workflowAbortSignal.addEventListener('abort', onWorkflowAbort, { once: true });\n }\n const timeoutHandle = setTimeout(() => {\n abortController.abort(new Error(`Task timed out after ${task.timeoutMs}ms`));\n }, task.timeoutMs);\n\n // Wrap the workflow runtime's `suspend` so we persist\n // `status: 'suspended'` + `suspendPayload`, fire the per-task\n // suspend hook (so the bg-task's `onResult` updates the agent's\n // message list), and publish the lifecycle event before\n // delegating. The runtime's `suspend` does not throw — it sets a\n // flag the step-executor reads after `execute` returns. We\n // capture the args here and call the runtime's suspend from the\n // step body after the executor returns, so `wrappedSuspend` can\n // safely run all its side effects synchronously inside the\n // tool's call.\n let pendingSuspend: { data?: unknown; suspendOptions?: SuspendOptions } | undefined;\n const wrappedSuspend = async (data?: unknown, suspendOptions?: SuspendOptions) => {\n await storage.updateTask(taskId, {\n status: 'suspended',\n suspendPayload: data,\n suspendedAt: new Date(),\n });\n const suspendedTask = await storage.getTask(taskId);\n if (suspendedTask) {\n // Suspend is non-terminal — DO NOT use `runLocalCompletionHooks`\n // here. That helper deregisters the task context in its `finally`\n // block, which would strand the resume call (the workflow step\n // body re-enters and looks up `manager.taskContexts.get(taskId)`).\n await manager.runLocalSuspendHooks(suspendedTask);\n await manager.publishLifecycleEvent('task.suspended', suspendedTask);\n }\n pendingSuspend = { data, suspendOptions };\n };\n\n try {\n const result = await executor.execute(task.args, {\n abortSignal: abortController.signal,\n onProgress,\n suspend: wrappedSuspend,\n // On resume the runtime populates `resumeData`; undefined on\n // the initial run.\n resumeData,\n });\n\n if (pendingSuspend) {\n return suspend(pendingSuspend.data, pendingSuspend.suspendOptions as SuspendOptions);\n }\n\n return { taskId, outcome: 'success' as const, result };\n } catch (error: any) {\n const currentTask = await storage.getTask(taskId);\n if (!currentTask || (currentTask.status as BackgroundTaskStatus) === 'cancelled') {\n manager.deregisterTaskContext(taskId);\n return { taskId, outcome: 'cancelled' as const };\n }\n\n // Treat any aborted-signal exit as a timeout. The cancel path is\n // already handled by the storage-status check above, so if we reach\n // here with `signal.aborted`, it's the timeout abort. The\n // `AbortError` / message checks are belt-and-braces for executors\n // that throw their own abort error instead of propagating ours.\n if (\n abortController.signal.aborted ||\n error?.name === 'AbortError' ||\n error?.message === 'Task cancelled' ||\n error?.message?.startsWith('Task timed out after ')\n ) {\n return { taskId, outcome: 'timed_out' as const };\n }\n\n // Authorization denials are non-retryable — retrying cannot succeed\n // and would just burn attempts before surfacing the denial.\n if (error?.name === 'FGADeniedError') {\n return {\n taskId,\n outcome: 'failed' as const,\n error: { name: error.name, message: error?.message ?? 'Authorization denied', stack: error?.stack },\n };\n }\n\n return {\n taskId,\n outcome: 'retry' as const,\n error: { message: error?.message ?? 'Unknown error', stack: error?.stack },\n };\n } finally {\n clearTimeout(timeoutHandle);\n workflowAbortSignal.removeEventListener('abort', onWorkflowAbort);\n manager.activeAbortControllers.delete(taskId);\n }\n },\n });\n\n const classifyOutcomeStep = createStep({\n id: 'classify-outcome',\n inputSchema: attemptOutputSchema,\n outputSchema: bodyOutputSchema,\n execute: async ({ inputData }) => {\n const { taskId, outcome, result, error } = inputData;\n const storage = await manager.getStorage();\n const task = await storage.getTask(taskId);\n if (!task) return { taskId, done: true };\n\n if (outcome === 'cancelled') {\n manager.deregisterTaskContext(taskId);\n return { taskId, done: true };\n }\n\n if (outcome === 'timed_out') {\n const status = task.status as string;\n if (status !== 'timed_out' && status !== 'cancelled') {\n await storage.updateTask(taskId, {\n status: 'timed_out',\n error: { message: `Task timed out after ${task.timeoutMs}ms` },\n completedAt: new Date(),\n });\n const timedOutTask = await storage.getTask(taskId);\n if (timedOutTask) await manager.publishLifecycleEvent('task.failed', timedOutTask);\n }\n return { taskId, done: true };\n }\n\n if (outcome === 'success') {\n if ((task.status as BackgroundTaskStatus) === 'cancelled') {\n manager.deregisterTaskContext(taskId);\n return { taskId, done: true };\n }\n await storage.updateTask(taskId, { status: 'completed', result, completedAt: new Date() });\n const completedTask = await storage.getTask(taskId);\n if (completedTask) {\n await manager.runLocalCompletionHooks(completedTask, 'completed', { result });\n await manager.publishLifecycleEvent('task.completed', completedTask);\n }\n return { taskId, done: true, result };\n }\n\n // outcome === 'retry' | 'failed'\n if (outcome === 'retry' && task.retryCount < task.maxRetries) {\n await storage.updateTask(taskId, {\n retryCount: task.retryCount + 1,\n error: undefined,\n startedAt: new Date(),\n });\n return { taskId, done: false };\n }\n\n // Retries exhausted (or non-retryable failure): persist failure and\n // throw so the workflow run ends\n // in `failed` rather than completing cleanly. Throw matches the prior\n // single-step behavior — workflow-run history stays accurate.\n const errorInfo = error ?? { message: 'Unknown error' };\n await storage.updateTask(taskId, { status: 'failed', error: errorInfo, completedAt: new Date() });\n const failedTask = await storage.getTask(taskId);\n if (failedTask) {\n await manager.runLocalCompletionHooks(failedTask, 'failed', { error: errorInfo });\n await manager.publishLifecycleEvent('task.failed', failedTask);\n }\n const thrown = new Error(errorInfo.message);\n if (errorInfo.name) thrown.name = errorInfo.name;\n if (errorInfo.stack) thrown.stack = errorInfo.stack;\n throw thrown;\n },\n });\n\n const attemptBodyWorkflow = createWorkflow({\n id: `${BACKGROUND_TASK_WORKFLOW_ID}__attempt`,\n inputSchema: bodyIOSchema,\n outputSchema: bodyOutputSchema,\n steps: [runAttemptStep, classifyOutcomeStep],\n options: {\n // `dountil` feeds the prior iteration's output back in as input. The\n // body's actual entry point only needs `taskId`, but the loop's\n // feedback shape includes `done`/`result`/etc. Skip validation rather\n // than widen every step's input schema.\n validateInputs: false,\n shouldPersistSnapshot: ({ workflowStatus }) => WORKFLOW_STATUS_TO_PERSIST.includes(workflowStatus),\n // Internal scheduler plumbing — hide workflow spans from exported\n // traces. The task body itself runs as user code and keeps its own\n // spans.\n tracingPolicy: {\n internal: InternalSpans.WORKFLOW,\n },\n },\n })\n .then(runAttemptStep)\n .then(classifyOutcomeStep)\n .commit();\n\n return createWorkflow({\n id: BACKGROUND_TASK_WORKFLOW_ID,\n inputSchema,\n outputSchema: bodyOutputSchema,\n steps: [attemptBodyWorkflow],\n options: {\n shouldPersistSnapshot: ({ workflowStatus }) => WORKFLOW_STATUS_TO_PERSIST.includes(workflowStatus),\n // Internal scheduler plumbing — see the inner workflow comment.\n tracingPolicy: {\n internal: InternalSpans.WORKFLOW,\n },\n },\n })\n .dountil(attemptBodyWorkflow, async ({ inputData }) => inputData?.done === true)\n .commit();\n}\n"],"mappings":"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"}