UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

224 lines (221 loc) 9.77 kB
'use strict'; var chunkBKPEQNQF_cjs = require('./chunk-BKPEQNQF.cjs'); var chunkM5AKMHS2_cjs = require('./chunk-M5AKMHS2.cjs'); var zod = require('zod'); var inputSchema = zod.z.object({ taskId: zod.z.string() }); var attemptOutcomeSchema = zod.z.enum(["success", "retry", "cancelled", "timed_out"]); var attemptOutputSchema = zod.z.object({ taskId: zod.z.string(), outcome: attemptOutcomeSchema, result: zod.z.unknown().optional(), error: zod.z.any().optional() }); var bodyIOSchema = zod.z.object({ taskId: zod.z.string(), done: zod.z.boolean().optional(), result: zod.z.unknown().optional() }); var bodyOutputSchema = zod.z.object({ taskId: zod.z.string(), done: zod.z.boolean(), result: zod.z.unknown().optional() }); var WORKFLOW_STATUS_TO_PERSIST = ["suspended", "pending", "paused", "waiting"]; function buildBackgroundTaskWorkflow(manager) { const runAttemptStep = chunkBKPEQNQF_cjs.createStep({ id: "run-attempt", inputSchema: bodyIOSchema, outputSchema: attemptOutputSchema, execute: async ({ inputData, abortSignal: workflowAbortSignal, suspend, resumeData }) => { const { taskId } = inputData; const storage = await manager.getStorage(); const task = await storage.getTask(taskId); if (!task || task.status === "cancelled") { manager.deregisterTaskContext(taskId); return { taskId, outcome: "cancelled" }; } const ctx = manager.taskContexts.get(taskId); const executor = ctx?.executor ?? manager.getStaticExecutor(task.toolName); if (!executor) { const errorInfo = { message: `No executor registered for tool "${task.toolName}". Register the tool on Mastra (so workers can resolve it cross-process) or run the task in the same process as the producer.` }; await storage.updateTask(taskId, { status: "failed", error: errorInfo, completedAt: /* @__PURE__ */ new Date() }); const failedTask = await storage.getTask(taskId); if (failedTask) { await manager.runLocalCompletionHooks(failedTask, "failed", { error: errorInfo }); await manager.publishLifecycleEvent("task.failed", failedTask); } manager.deregisterTaskContext(taskId); throw new Error(errorInfo.message); } const progressThrottleMs = manager.config.progressThrottleMs; const shouldThrottleProgress = typeof progressThrottleMs === "number" && Number.isFinite(progressThrottleMs) && progressThrottleMs > 0; let lastProgressEmitMs; const onProgress = async (chunk) => { if (shouldThrottleProgress) { const now = Date.now(); if (lastProgressEmitMs !== void 0 && now - lastProgressEmitMs < progressThrottleMs) return; lastProgressEmitMs = now; } await manager.publishLifecycleEvent("task.output", { ...task, chunk }); }; const abortController = new AbortController(); manager.activeAbortControllers.set(taskId, abortController); const onWorkflowAbort = () => abortController.abort(new Error("Task cancelled")); if (workflowAbortSignal.aborted) { abortController.abort(new Error("Task cancelled")); } else { workflowAbortSignal.addEventListener("abort", onWorkflowAbort, { once: true }); } const timeoutHandle = setTimeout(() => { abortController.abort(new Error(`Task timed out after ${task.timeoutMs}ms`)); }, task.timeoutMs); let pendingSuspend; const wrappedSuspend = async (data, suspendOptions) => { await storage.updateTask(taskId, { status: "suspended", suspendPayload: data, suspendedAt: /* @__PURE__ */ new Date() }); const suspendedTask = await storage.getTask(taskId); if (suspendedTask) { await manager.runLocalSuspendHooks(suspendedTask); await manager.publishLifecycleEvent("task.suspended", suspendedTask); } pendingSuspend = { data, suspendOptions }; }; try { const result = await executor.execute(task.args, { abortSignal: abortController.signal, onProgress, suspend: wrappedSuspend, // On resume the runtime populates `resumeData`; undefined on // the initial run. resumeData }); if (pendingSuspend) { return suspend(pendingSuspend.data, pendingSuspend.suspendOptions); } return { taskId, outcome: "success", result }; } catch (error) { const currentTask = await storage.getTask(taskId); if (!currentTask || currentTask.status === "cancelled") { manager.deregisterTaskContext(taskId); return { taskId, outcome: "cancelled" }; } if (abortController.signal.aborted || error?.name === "AbortError" || error?.message === "Task cancelled" || error?.message?.startsWith("Task timed out after ")) { return { taskId, outcome: "timed_out" }; } return { taskId, outcome: "retry", error: { message: error?.message ?? "Unknown error", stack: error?.stack } }; } finally { clearTimeout(timeoutHandle); workflowAbortSignal.removeEventListener("abort", onWorkflowAbort); manager.activeAbortControllers.delete(taskId); } } }); const classifyOutcomeStep = chunkBKPEQNQF_cjs.createStep({ id: "classify-outcome", inputSchema: attemptOutputSchema, outputSchema: bodyOutputSchema, execute: async ({ inputData }) => { const { taskId, outcome, result, error } = inputData; const storage = await manager.getStorage(); const task = await storage.getTask(taskId); if (!task) return { taskId, done: true }; if (outcome === "cancelled") { manager.deregisterTaskContext(taskId); return { taskId, done: true }; } if (outcome === "timed_out") { const status = task.status; if (status !== "timed_out" && status !== "cancelled") { await storage.updateTask(taskId, { status: "timed_out", error: { message: `Task timed out after ${task.timeoutMs}ms` }, completedAt: /* @__PURE__ */ new Date() }); const timedOutTask = await storage.getTask(taskId); if (timedOutTask) await manager.publishLifecycleEvent("task.failed", timedOutTask); } return { taskId, done: true }; } if (outcome === "success") { if (task.status === "cancelled") { manager.deregisterTaskContext(taskId); return { taskId, done: true }; } await storage.updateTask(taskId, { status: "completed", result, completedAt: /* @__PURE__ */ new Date() }); const completedTask = await storage.getTask(taskId); if (completedTask) { await manager.runLocalCompletionHooks(completedTask, "completed", { result }); await manager.publishLifecycleEvent("task.completed", completedTask); } return { taskId, done: true, result }; } if (task.retryCount < task.maxRetries) { await storage.updateTask(taskId, { retryCount: task.retryCount + 1, error: void 0, startedAt: /* @__PURE__ */ new Date() }); return { taskId, done: false }; } const errorInfo = error ?? { message: "Unknown error" }; await storage.updateTask(taskId, { status: "failed", error: errorInfo, completedAt: /* @__PURE__ */ new Date() }); const failedTask = await storage.getTask(taskId); if (failedTask) { await manager.runLocalCompletionHooks(failedTask, "failed", { error: errorInfo }); await manager.publishLifecycleEvent("task.failed", failedTask); } const thrown = new Error(errorInfo.message); if (errorInfo.stack) thrown.stack = errorInfo.stack; throw thrown; } }); const attemptBodyWorkflow = chunkBKPEQNQF_cjs.createWorkflow({ id: `${chunkM5AKMHS2_cjs.BACKGROUND_TASK_WORKFLOW_ID}__attempt`, inputSchema: bodyIOSchema, outputSchema: bodyOutputSchema, steps: [runAttemptStep, classifyOutcomeStep], options: { // `dountil` feeds the prior iteration's output back in as input. The // body's actual entry point only needs `taskId`, but the loop's // feedback shape includes `done`/`result`/etc. Skip validation rather // than widen every step's input schema. validateInputs: false, shouldPersistSnapshot: ({ workflowStatus }) => WORKFLOW_STATUS_TO_PERSIST.includes(workflowStatus), // Internal scheduler plumbing — hide workflow spans from exported // traces. The task body itself runs as user code and keeps its own // spans. tracingPolicy: { internal: 1 /* WORKFLOW */ } } }).then(runAttemptStep).then(classifyOutcomeStep).commit(); return chunkBKPEQNQF_cjs.createWorkflow({ id: chunkM5AKMHS2_cjs.BACKGROUND_TASK_WORKFLOW_ID, inputSchema, outputSchema: bodyOutputSchema, steps: [attemptBodyWorkflow], options: { shouldPersistSnapshot: ({ workflowStatus }) => WORKFLOW_STATUS_TO_PERSIST.includes(workflowStatus), // Internal scheduler plumbing — see the inner workflow comment. tracingPolicy: { internal: 1 /* WORKFLOW */ } } }).dountil(attemptBodyWorkflow, async ({ inputData }) => inputData?.done === true).commit(); } Object.defineProperty(exports, "BACKGROUND_TASK_WORKFLOW_ID", { enumerable: true, get: function () { return chunkM5AKMHS2_cjs.BACKGROUND_TASK_WORKFLOW_ID; } }); exports.buildBackgroundTaskWorkflow = buildBackgroundTaskWorkflow; //# sourceMappingURL=workflow-NQFS7R77.cjs.map //# sourceMappingURL=workflow-NQFS7R77.cjs.map