UNPKG

@mastra/core

Version:
284 lines (283 loc) 13.9 kB
import { standardSchemaToJSONSchema, toStandardSchema } from "../schema/index.js"; import { $t as createWorkflow, Qt as createEventedWorkflow, Sn as ExecutionEngine, Zt as cloneWorkflow, _n as DefaultExecutionEngine, bn as createStepFromTool, cn as Workflow, dn as isProcessor, fn as mapVariable, gn as predicateSchema, hn as evaluatePredicate, ln as cloneStep, mn as derivePredicateLabel, pn as predicateToCondition, sn as Run, un as createStep, vn as createMappingStep, yn as createStepFromAgent } from "../agent-Dj30gJa3.js"; import { n as validateCron, t as computeNextFireAt } from "../cron-B2j814dd.js"; import { A as getEntryId, C as runCountDeprecationMessage, D as validateStepStateData, E as validateStepResumeData, M as getStepResult, O as validateStepSuspendData, S as resolveForeachConcurrency, T as validateStepRequestContext, _ as getResumeLabelsByStepId, b as hydrateSerializedStepErrors, g as createTimeTravelExecutionParams, h as createRestartExecutionParams, j as getEntryWorkflow, k as waitForSuspendedSnapshot, m as createDeprecationProxy, p as cleanStepResult, v as getSingleStepEntryId, w as validateStepInput, x as isSingleStepEntry, y as getStepIds } from "../workflow-event-processor-BbED1LMn.js"; import { n as WorkflowScheduler, t as Scheduler } from "../scheduler-CY8m1fr_.js"; import { a as inferGraphSchemas, c as forEachSingleStepEntry, d as analyzeMapConfig, f as parseMapConfig, g as validateStorableJsonSchema, h as jsonSchemaToZod, i as validateWorkflowSchemas, l as forEachSingleStepEntryWithPath, m as toJsonSchemaOrUndefined, n as validateStoredWorkflow, o as validateWorkflowRefs, p as schemaCompatibility, r as validateWorkflowStructure, s as collectNestedWorkflowIds, t as assertValidStoredWorkflow, u as rehydrateWorkflow } from "../validate-BWdo4oEz.js"; //#region src/workflows/stored/serialize.ts /** * Live → Storable half of the workflow round-trip: walk a live `stepFlow` * (runtime references, closures) and emit the JSON-safe storable form * (ids + serialized mapping configs, no closures). * * The static subset that round-trips: * - agent / tool by id * - mapping with `value`, `step`, `initData`, `requestContextPath`, `template`, * `state` sources (no `fn` source — closures don't round-trip) * - sleep / sleepUntil with literal duration/date * - parallel (inner entries must themselves be static) * - foreach with literal concurrency * - conditional / loop with declarative predicates (closure predicates throw) * - generic `.then(step)` falls back to a minimal step descriptor — usable * only when the step's id resolves on the live Mastra at load time * * Anything outside the subset throws at `toStorableGraph` time: silent loss * would ship broken workflows unnoticed. */ /** * Walk a live `stepFlow` and emit a JSON-safe `SerializedStepFlowEntry[]` with * full (un-truncated) mapping configs and all step/agent/tool references stored * as ids. Throws on entries that can't round-trip (closures, closure predicates). */ function toStorableGraph(stepFlow) { return stepFlow.map((entry) => serializeEntry(entry)); } function serializeEntry(entry) { switch (entry.type) { case "step": case "agent": case "tool": case "mapping": return serializeSingleEntry(entry); case "sleep": if (typeof entry.duration !== "number") throw new Error(`Sleep step "${entry.id}" cannot be stored: dynamic duration (function) is not supported.`); return { type: "sleep", id: entry.id, duration: entry.duration }; case "sleepUntil": if (!(entry.date instanceof Date)) throw new Error(`SleepUntil step "${entry.id}" cannot be stored: dynamic date (function) is not supported.`); return { type: "sleepUntil", id: entry.id, date: entry.date }; case "parallel": return { type: "parallel", steps: entry.steps.map((s) => serializeSingleEntry(s)) }; case "foreach": if (entry.step.type === "mapping") throw new Error(`Foreach step cannot iterate a mapping: mappings project data, they don't execute per item. Use an agent, tool, or plain step as the foreach body.`); return { type: "foreach", step: serializeSingleEntry(entry.step), opts: typeof entry.opts.concurrency === "function" ? { fn: entry.opts.concurrency.toString() } : { concurrency: entry.opts.concurrency } }; case "conditional": { const predicates = entry.predicates; if (!predicates || predicates.some((p) => !p || typeof p !== "object")) throw new Error(`Conditional (branch) step cannot be stored: closure predicates do not round-trip. Use the declarative form ({ predicate: {...} }) for each branch.`); return { type: "conditional", steps: entry.steps.map((s) => serializeSingleEntry(s)), serializedConditions: entry.serializedConditions, predicates }; } case "loop": { const predicate = entry.predicate; if (!predicate || typeof predicate !== "object") throw new Error(`Loop step "${getSingleStepEntryId(entry.step)}" cannot be stored: closure predicates do not round-trip. Use the declarative form ({ predicate: {...} }).`); return { type: "loop", step: serializeSingleEntry(entry.step), serializedCondition: entry.serializedCondition, loopType: entry.loopType, predicate }; } default: throw new Error(`Unknown step entry type: ${JSON.stringify(entry)}`); } } function serializeSingleEntry(entry) { if (entry.type === "agent") { const options = pickSerializableStepOptions(entry.options, entry.id, "agent"); const outputSchema = extractStructuredOutputJsonSchema(entry.options, entry.id); return { type: "agent", id: entry.id, agentId: entry.agentId, description: entry.agent?.description, ...outputSchema ? { outputSchema } : {}, ...options ? { options } : {} }; } if (entry.type === "tool") { const options = pickSerializableStepOptions(entry.options, entry.id, "tool"); return { type: "tool", id: entry.id, toolId: entry.toolId, description: entry.tool?.description, ...options ? { options } : {} }; } if (entry.type === "mapping") { if (typeof entry.mapConfig === "function") throw new Error(`Mapping step "${entry.id}" cannot be stored: the function form does not round-trip. Use the declarative form (template / step / initData / value).`); const serialized = {}; for (const [key, mapping] of Object.entries(entry.mapConfig)) { const m = mapping; if (m.fn !== void 0) throw new Error(`Mapping step "${entry.id}" key "${key}" cannot be stored: source is a function.`); if (m.value !== void 0) serialized[key] = { value: m.value }; else if (m.requestContextPath) serialized[key] = { requestContextPath: m.requestContextPath }; else if (typeof m.template === "string") serialized[key] = { template: m.template }; else if (m.initData) serialized[key] = { initData: m.initData?.id, path: m.path }; else if (m.step) serialized[key] = { step: Array.isArray(m.step) ? m.step.map((s) => s?.id) : m.step?.id, path: m.path }; else serialized[key] = m; } return { type: "mapping", id: entry.id, mapConfig: JSON.stringify(serialized) }; } if (entry.step?.component === "WORKFLOW") { const nestedFlow = entry.step.serializedStepGraph ?? entry.step.serializedStepFlow; return { type: "workflow", id: entry.step.id, workflowId: entry.step.id, ...entry.step.description ? { description: entry.step.description } : {}, ...nestedFlow ? { serializedStepFlow: nestedFlow } : {} }; } return { type: "step", step: stepDescriptor(entry.step) }; } function stepDescriptor(step) { return { id: step.id, description: step.description, metadata: step.metadata, component: step.component, canSuspend: Boolean(step.suspendSchema || step.resumeSchema) }; } /** * Pull the JSON-safe fields (`retries`, `metadata`) out of the options bag * carried on a live agent/tool `SingleStepEntry`. Closure-valued fields must * hard-crash here rather than silently vanish through storage. */ function pickSerializableStepOptions(options, entryId, kind) { if (!options || typeof options !== "object") return void 0; for (const { key, hint } of [ { key: "onFinish", hint: "callback closure" }, { key: "onChunk", hint: "callback closure" }, { key: "onError", hint: "callback closure" }, { key: "onStepFinish", hint: "callback closure" }, { key: "onAbort", hint: "callback closure" }, { key: "toolChoice", hint: "may be a function" } ]) if (typeof options[key] === "function") throw new Error(`${kind === "agent" ? "Agent" : "Tool"} step "${entryId}" cannot be stored: option "${key}" is a ${hint} that does not round-trip. Remove it or move that logic outside the persisted workflow.`); if (typeof options.scorers === "function") throw new Error(`${kind === "agent" ? "Agent" : "Tool"} step "${entryId}" cannot be stored: "scorers" is a function; only the static array form round-trips.`); const out = {}; if (typeof options.retries === "number") out.retries = options.retries; if (options.metadata && typeof options.metadata === "object") out.metadata = options.metadata; return Object.keys(out).length > 0 ? out : void 0; } /** * If the agent-step options carry `structuredOutput.schema`, that schema IS * the step's output shape (see `createStepFromAgent`). Emit it as JSON Schema * so rehydration can wire the same structured output back in. */ function extractStructuredOutputJsonSchema(options, entryId) { const raw = options?.structuredOutput?.schema; if (raw === void 0 || raw === null) return void 0; try { return standardSchemaToJSONSchema(toStandardSchema(raw)); } catch (e) { throw new Error(`Agent step "${entryId}" cannot be stored: structuredOutput.schema is not convertible to JSON Schema (${e.message}).`); } } //#endregion //#region src/workflows/state-reader.ts const getStep = (state, stepId) => state.steps?.[stepId]; const getFirstStepResult = (step) => { return Array.isArray(step) ? step.find((result) => result?.status === "suspended") ?? step[0] : step; }; const getNestedSuspendPath = (step) => { const path = getFirstStepResult(step)?.suspendPayload?.__workflow_meta?.path; return Array.isArray(path) ? path.filter((part) => typeof part === "string") : []; }; function getWorkflowStepOutput(state, stepId) { const step = getStep(state, stepId); return Array.isArray(step) ? step.map((result) => result?.output) : step?.output; } function getWorkflowStepPayload(state, stepId) { const step = getStep(state, stepId); return Array.isArray(step) ? step.map((result) => result?.payload) : step?.payload; } function getWorkflowResumeLabel(state, label) { const resumeLabel = state.resumeLabels?.[label]; return resumeLabel ? { ...resumeLabel } : void 0; } function getWorkflowResumeLabels(state) { return Object.entries(state.resumeLabels ?? {}).reduce((labels, [label, value]) => { labels[label] = { ...value }; return labels; }, {}); } function getWorkflowSuspendedSteps(state) { return Object.entries(state.suspendedPaths ?? {}).map(([stepId, executionPath]) => { const step = getStep(state, stepId); const firstStepResult = getFirstStepResult(step); const nestedPath = getNestedSuspendPath(step); const path = nestedPath.length > 0 ? nestedPath[0] === stepId ? nestedPath : [stepId, ...nestedPath] : [stepId]; const resumeLabels = Object.entries(state.resumeLabels ?? {}).reduce((labels, [label, value]) => { if (value.stepId === stepId) labels[label] = { ...value }; return labels; }, {}); return { stepId, path, executionPath, step, payload: Array.isArray(step) ? step.map((result) => result?.payload) : step?.payload, suspendPayload: firstStepResult?.suspendPayload, suspendOutput: firstStepResult?.suspendOutput, resumeLabels }; }); } function getWorkflowSuspendedStep(state) { return getWorkflowSuspendedSteps(state)[0]; } function createWorkflowStateReader(state) { return { getStatus: () => state.status, getResult: () => state.result, getError: () => state.error, getStepOutput: (stepId) => getWorkflowStepOutput(state, stepId), getStepPayload: (stepId) => getWorkflowStepPayload(state, stepId), getSuspendedStep: () => getWorkflowSuspendedStep(state), getSuspendedSteps: () => getWorkflowSuspendedSteps(state), getResumeLabel: (label) => getWorkflowResumeLabel(state, label), getResumeLabels: () => getWorkflowResumeLabels(state) }; } //#endregion export { DefaultExecutionEngine, ExecutionEngine, Run, Scheduler, Workflow, WorkflowScheduler, analyzeMapConfig, assertValidStoredWorkflow, cleanStepResult, cloneStep, cloneWorkflow, collectNestedWorkflowIds, computeNextFireAt, createDeprecationProxy, createEventedWorkflow, createMappingStep, createRestartExecutionParams, createStep, createStepFromAgent, createStepFromTool, createTimeTravelExecutionParams, createWorkflow, createWorkflowStateReader, derivePredicateLabel, evaluatePredicate, forEachSingleStepEntry, forEachSingleStepEntryWithPath, getEntryId, getEntryWorkflow, getResumeLabelsByStepId, getSingleStepEntryId, getStepIds, getStepResult, getWorkflowResumeLabel, getWorkflowResumeLabels, getWorkflowStepOutput, getWorkflowStepPayload, getWorkflowSuspendedStep, getWorkflowSuspendedSteps, hydrateSerializedStepErrors, inferGraphSchemas, isProcessor, isSingleStepEntry, jsonSchemaToZod, mapVariable, parseMapConfig, predicateSchema, predicateToCondition, rehydrateWorkflow, resolveForeachConcurrency, runCountDeprecationMessage, schemaCompatibility, toJsonSchemaOrUndefined, toStorableGraph, validateCron, validateStepInput, validateStepRequestContext, validateStepResumeData, validateStepStateData, validateStepSuspendData, validateStorableJsonSchema, validateStoredWorkflow, validateWorkflowRefs, validateWorkflowSchemas, validateWorkflowStructure, waitForSuspendedSnapshot }; //# sourceMappingURL=index.js.map