@mastra/core 0.2.0-alpha.98 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/agent/index.d.ts +6 -8
  2. package/dist/agent/index.js +15 -7
  3. package/dist/{telemetry-oCUM52DG.d.ts → base-BbtPAA6f.d.ts} +50 -8
  4. package/dist/{index-Cwb-5AzX.d.ts → base-Bpb7Dmwe.d.ts} +367 -320
  5. package/dist/base.d.ts +3 -43
  6. package/dist/base.js +3 -3
  7. package/dist/bundler/index.d.ts +3 -4
  8. package/dist/bundler/index.js +4 -4
  9. package/dist/{chunk-MCB4M5W4.js → chunk-22LC46YN.js} +3 -9
  10. package/dist/{chunk-MG3WAQV7.js → chunk-2JL6DQMZ.js} +20 -28
  11. package/dist/chunk-2SAHBQEF.js +3 -0
  12. package/dist/chunk-3HBFW3Q7.js +24 -0
  13. package/dist/{chunk-KNPBNSJ7.js → chunk-55GTEVHJ.js} +12 -13
  14. package/dist/chunk-65VPTVVP.js +218 -0
  15. package/dist/chunk-AWEACB2T.js +66 -0
  16. package/dist/chunk-C6A6W6XS.js +49 -0
  17. package/dist/chunk-FGZVE4CM.js +404 -0
  18. package/dist/{chunk-TYIBRZOY.js → chunk-J3W3IHDO.js} +120 -87
  19. package/dist/chunk-K36NSQWH.js +10 -0
  20. package/dist/{chunk-QXH6EK72.js → chunk-K4DFI76V.js} +382 -370
  21. package/dist/{chunk-42DYOLDV.js → chunk-MEISIZMP.js} +13 -21
  22. package/dist/chunk-MLWGYRJR.js +87 -0
  23. package/dist/{chunk-ICMEXHKD.js → chunk-O2VP5JBC.js} +48 -55
  24. package/dist/{chunk-ZJOMHCWE.js → chunk-OJ26F3J4.js} +98 -153
  25. package/dist/chunk-RG66XEJT.js +8 -0
  26. package/dist/chunk-SB37QG7O.js +1203 -0
  27. package/dist/chunk-SDBM53G4.js +32 -0
  28. package/dist/{chunk-4LJFWC2Q.js → chunk-SIFBBGY6.js} +59 -85
  29. package/dist/chunk-U6J2FOU4.js +624 -0
  30. package/dist/chunk-VB7CO5ND.js +31 -0
  31. package/dist/{chunk-C55JWGDU.js → chunk-ZJOXJFJI.js} +43 -15
  32. package/dist/deployer/index.d.ts +2 -4
  33. package/dist/deployer/index.js +5 -5
  34. package/dist/eval/index.d.ts +8 -13
  35. package/dist/eval/index.js +3 -3
  36. package/dist/filter/index.js +2 -2
  37. package/dist/hooks/index.d.ts +13 -18
  38. package/dist/hooks/index.js +2 -2
  39. package/dist/{index-CBZ2mk2H.d.ts → index-B2JCcAQt.d.ts} +1 -1
  40. package/dist/index.d.ts +15 -15
  41. package/dist/index.js +43 -69
  42. package/dist/integration/index.d.ts +8 -10
  43. package/dist/integration/index.js +6 -3
  44. package/dist/llm/index.d.ts +6 -8
  45. package/dist/llm/index.js +1 -1
  46. package/dist/logger/index.d.ts +1 -1
  47. package/dist/logger/index.js +2 -2
  48. package/dist/mastra/index.d.ts +10 -13
  49. package/dist/mastra/index.js +20 -4
  50. package/dist/memory/index.d.ts +8 -10
  51. package/dist/memory/index.js +11 -9
  52. package/dist/relevance/index.js +16 -8
  53. package/dist/storage/index.d.ts +21 -10
  54. package/dist/storage/index.js +8 -7
  55. package/dist/telemetry/index.d.ts +35 -5
  56. package/dist/telemetry/index.js +3 -2
  57. package/dist/telemetry/otel-vendor.d.ts +7 -0
  58. package/dist/telemetry/otel-vendor.js +8 -0
  59. package/dist/tools/index.d.ts +6 -8
  60. package/dist/tools/index.js +2 -2
  61. package/dist/tts/index.d.ts +2 -4
  62. package/dist/tts/index.js +6 -5
  63. package/dist/{metric-BWeQNZt6.d.ts → types-m9RryK9a.d.ts} +6 -1
  64. package/dist/utils.js +2 -2
  65. package/dist/vector/index.d.ts +4 -6
  66. package/dist/vector/index.js +4 -4
  67. package/dist/vector/libsql/index.d.ts +2 -4
  68. package/dist/vector/libsql/index.js +6 -6
  69. package/dist/{workflow-DTtv7_Eq.d.ts → workflow-Cy8UTGCt.d.ts} +3 -6
  70. package/dist/workflows/index.d.ts +7 -9
  71. package/dist/workflows/index.js +4 -4
  72. package/package.json +14 -10
  73. package/dist/chunk-4ZUSEHLH.js +0 -285
  74. package/dist/chunk-AJJZUHB4.js +0 -14
  75. package/dist/chunk-G4MCO7XF.js +0 -70
  76. package/dist/chunk-HBTQNIAX.js +0 -90
  77. package/dist/chunk-HPXWJBQK.js +0 -222
  78. package/dist/chunk-JJ57BXQR.js +0 -16
  79. package/dist/chunk-JP37ODNX.js +0 -36
  80. package/dist/chunk-K3N7KJHH.js +0 -52
  81. package/dist/chunk-MDM2JS2U.js +0 -1288
  82. package/dist/chunk-VOUPGVRD.js +0 -27
  83. package/dist/chunk-Z7JFMQZZ.js +0 -551
  84. /package/dist/{chunk-AE3H2QEY.js → chunk-VDOJTUYY.js} +0 -0
@@ -0,0 +1,1203 @@
1
+ import { MastraBase } from './chunk-AWEACB2T.js';
2
+ import { context, trace } from '@opentelemetry/api';
3
+ import { get } from 'radash';
4
+ import sift from 'sift';
5
+ import { setup, createActor, assign, fromPromise } from 'xstate';
6
+ import 'zod';
7
+
8
+ var Step = class {
9
+ id;
10
+ description;
11
+ inputSchema;
12
+ outputSchema;
13
+ payload;
14
+ execute;
15
+ retryConfig;
16
+ mastra;
17
+ constructor({
18
+ id,
19
+ description,
20
+ execute,
21
+ payload,
22
+ outputSchema,
23
+ inputSchema,
24
+ retryConfig
25
+ }) {
26
+ this.id = id;
27
+ this.description = description ?? "";
28
+ this.inputSchema = inputSchema;
29
+ this.payload = payload;
30
+ this.outputSchema = outputSchema;
31
+ this.execute = execute;
32
+ this.retryConfig = retryConfig;
33
+ }
34
+ };
35
+ function createStep(opts) {
36
+ return new Step(opts);
37
+ }
38
+
39
+ // src/workflows/utils.ts
40
+ function isErrorEvent(stateEvent) {
41
+ return stateEvent.type.startsWith("xstate.error.actor.");
42
+ }
43
+ function isTransitionEvent(stateEvent) {
44
+ return stateEvent.type.startsWith("xstate.done.actor.");
45
+ }
46
+ function isVariableReference(value) {
47
+ return typeof value === "object" && "step" in value && "path" in value;
48
+ }
49
+ function getStepResult(result) {
50
+ if (result?.status === "success") return result.output;
51
+ return undefined;
52
+ }
53
+
54
+ // src/workflows/workflow.ts
55
+ var Workflow = class extends MastraBase {
56
+ name;
57
+ triggerSchema;
58
+ /** XState machine instance that orchestrates the workflow execution */
59
+ #machine;
60
+ /** XState actor instance that manages the workflow execution */
61
+ #actor = null;
62
+ #runId;
63
+ #retryConfig;
64
+ #mastra;
65
+ // registers stepIds on `after` calls
66
+ #afterStepStack = [];
67
+ #lastStepStack = [];
68
+ #stepGraph = { initial: [] };
69
+ #stepSubscriberGraph = {};
70
+ #steps = {};
71
+ #onStepTransition = /* @__PURE__ */ new Set();
72
+ #executionSpan;
73
+ /**
74
+ * Creates a new Workflow instance
75
+ * @param name - Identifier for the workflow (not necessarily unique)
76
+ * @param logger - Optional logger instance
77
+ */
78
+ constructor({ name, triggerSchema, retryConfig, mastra }) {
79
+ super({ component: "WORKFLOW", name });
80
+ this.name = name;
81
+ this.#retryConfig = retryConfig;
82
+ this.triggerSchema = triggerSchema;
83
+ this.#runId = crypto.randomUUID();
84
+ this.#mastra = mastra;
85
+ if (mastra?.logger) {
86
+ this.logger = mastra?.logger;
87
+ }
88
+ this.initializeMachine();
89
+ }
90
+ /**
91
+ * Initializes the XState machine for the workflow
92
+ *
93
+ * Registers the machine's types, actions, actors, initial context, entry actions, initial state, and states
94
+ * @returns The initialized machine
95
+ */
96
+ initializeMachine() {
97
+ const machine = setup({
98
+ types: {},
99
+ delays: this.#makeDelayMap(),
100
+ actions: this.#getDefaultActions(),
101
+ actors: this.#getDefaultActors()
102
+ }).createMachine({
103
+ id: this.name,
104
+ type: "parallel",
105
+ context: ({ input }) => ({
106
+ ...input
107
+ }),
108
+ states: this.#buildStateHierarchy(this.#stepGraph)
109
+ });
110
+ this.#machine = machine;
111
+ return machine;
112
+ }
113
+ step(step, config) {
114
+ const { variables = {} } = config || {};
115
+ const requiredData = {};
116
+ for (const [key, variable] of Object.entries(variables)) {
117
+ if (variable && isVariableReference(variable)) {
118
+ requiredData[key] = variable;
119
+ }
120
+ }
121
+ const stepKey = this.#makeStepKey(step);
122
+ const graphEntry = {
123
+ step,
124
+ config: {
125
+ ...this.#makeStepDef(stepKey),
126
+ ...config,
127
+ data: requiredData
128
+ }
129
+ };
130
+ this.#steps[stepKey] = step;
131
+ const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
132
+ const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
133
+ if (parentStepKey && stepGraph) {
134
+ if (!stepGraph.initial.some((step2) => step2.step.id === stepKey)) {
135
+ stepGraph.initial.push(graphEntry);
136
+ }
137
+ stepGraph[stepKey] = [];
138
+ } else {
139
+ if (!this.#stepGraph[stepKey]) this.#stepGraph[stepKey] = [];
140
+ this.#stepGraph.initial.push(graphEntry);
141
+ }
142
+ this.#lastStepStack.push(stepKey);
143
+ return this;
144
+ }
145
+ then(step, config) {
146
+ const { variables = {} } = config || {};
147
+ const requiredData = {};
148
+ for (const [key, variable] of Object.entries(variables)) {
149
+ if (variable && isVariableReference(variable)) {
150
+ requiredData[key] = variable;
151
+ }
152
+ }
153
+ const lastStepKey = this.#lastStepStack[this.#lastStepStack.length - 1];
154
+ const stepKey = this.#makeStepKey(step);
155
+ const graphEntry = {
156
+ step,
157
+ config: {
158
+ ...this.#makeStepDef(stepKey),
159
+ ...config,
160
+ data: requiredData
161
+ }
162
+ };
163
+ this.#steps[stepKey] = step;
164
+ if (!lastStepKey) return this;
165
+ const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
166
+ const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
167
+ if (parentStepKey && stepGraph && stepGraph[lastStepKey]) {
168
+ stepGraph[lastStepKey].push(graphEntry);
169
+ } else {
170
+ if (!this.#stepGraph[lastStepKey]) this.#stepGraph[lastStepKey] = [];
171
+ this.#stepGraph[lastStepKey].push(graphEntry);
172
+ }
173
+ return this;
174
+ }
175
+ after(step) {
176
+ const stepKey = this.#makeStepKey(step);
177
+ this.#afterStepStack.push(stepKey);
178
+ if (!this.#stepSubscriberGraph[stepKey]) {
179
+ this.#stepSubscriberGraph[stepKey] = { initial: [] };
180
+ }
181
+ return this;
182
+ }
183
+ /**
184
+ * Executes the workflow with the given trigger data
185
+ * @param triggerData - Initial data to start the workflow with
186
+ * @returns Promise resolving to workflow results or rejecting with error
187
+ * @throws Error if trigger schema validation fails
188
+ */
189
+ createRun() {
190
+ const runId = crypto.randomUUID();
191
+ this.#runId = runId;
192
+ return {
193
+ runId,
194
+ start: async ({ triggerData } = {}) => this.execute({ triggerData })
195
+ };
196
+ }
197
+ async execute({
198
+ triggerData,
199
+ snapshot,
200
+ runId,
201
+ stepId
202
+ } = {}) {
203
+ if (runId) {
204
+ this.#runId = runId;
205
+ this.logger.debug(`Workflow snapshot received`, { runId: this.#runId, snapshot });
206
+ }
207
+ this.#executionSpan = this.#mastra?.telemetry?.tracer.startSpan(`workflow.${this.name}.execute`, {
208
+ attributes: { componentName: this.name, runId: this.#runId }
209
+ });
210
+ const machineInput = snapshot ? snapshot.context : {
211
+ // Maintain the original step results and their output
212
+ steps: {},
213
+ triggerData: triggerData || {},
214
+ attempts: Object.keys(this.#steps).reduce(
215
+ (acc, stepKey) => {
216
+ acc[stepKey] = this.#steps[stepKey]?.retryConfig?.attempts || this.#retryConfig?.attempts || 3;
217
+ return acc;
218
+ },
219
+ {}
220
+ )
221
+ };
222
+ this.logger.debug(`Machine input prepared`, { runId: this.#runId, machineInput });
223
+ const actorSnapshot = snapshot ? {
224
+ ...snapshot,
225
+ context: machineInput
226
+ } : undefined;
227
+ this.logger.debug(`Creating actor with configuration`, {
228
+ machineInput,
229
+ actorSnapshot,
230
+ machineStates: this.#machine.config.states,
231
+ runId: this.#runId
232
+ });
233
+ this.#actor = createActor(this.#machine, {
234
+ inspect: (inspectionEvent) => {
235
+ this.logger.debug("XState inspection event", {
236
+ type: inspectionEvent.type,
237
+ event: inspectionEvent.event,
238
+ runId: this.#runId
239
+ });
240
+ },
241
+ input: machineInput,
242
+ snapshot: actorSnapshot
243
+ });
244
+ this.#actor.start();
245
+ if (stepId) {
246
+ this.#actor.send({ type: "RESET_TO_PENDING", stepId });
247
+ }
248
+ this.logger.debug("Actor started", { runId: this.#runId });
249
+ return new Promise((resolve, reject) => {
250
+ if (!this.#actor) {
251
+ const e = new Error("Actor not initialized");
252
+ this.#executionSpan?.recordException(e);
253
+ this.#executionSpan?.end();
254
+ reject(e);
255
+ return;
256
+ }
257
+ const suspendedPaths = /* @__PURE__ */ new Set();
258
+ this.#actor.subscribe(async (state) => {
259
+ if (this.#onStepTransition) {
260
+ this.#onStepTransition.forEach((onTransition) => {
261
+ onTransition({
262
+ runId: this.#runId,
263
+ value: state.value,
264
+ context: state.context,
265
+ activePaths: this.#getActivePathsAndStatus(state.value),
266
+ timestamp: Date.now()
267
+ });
268
+ });
269
+ }
270
+ this.#getSuspendedPaths({
271
+ value: state.value,
272
+ path: "",
273
+ suspendedPaths
274
+ });
275
+ const allStatesValue = state.value;
276
+ const allStatesComplete = this.#recursivelyCheckForFinalState({
277
+ value: allStatesValue,
278
+ suspendedPaths,
279
+ path: ""
280
+ });
281
+ this.logger.debug("State completion check", {
282
+ allStatesComplete,
283
+ suspendedPaths: Array.from(suspendedPaths),
284
+ runId: this.#runId
285
+ });
286
+ if (!allStatesComplete) return;
287
+ try {
288
+ await this.#persistWorkflowSnapshot();
289
+ this.#cleanup();
290
+ this.#executionSpan?.end();
291
+ resolve({
292
+ triggerData,
293
+ results: state.context.steps,
294
+ runId: this.#runId
295
+ });
296
+ } catch (error) {
297
+ this.logger.debug("Failed to persist final snapshot", { error });
298
+ this.#cleanup();
299
+ this.#executionSpan?.end();
300
+ resolve({
301
+ triggerData,
302
+ results: state.context.steps,
303
+ runId: this.#runId
304
+ });
305
+ }
306
+ });
307
+ });
308
+ }
309
+ /**
310
+ * Rebuilds the machine with the current steps configuration and validates the workflow
311
+ *
312
+ * This is the last step of a workflow builder method chain
313
+ * @throws Error if validation fails
314
+ *
315
+ * @returns this instance for method chaining
316
+ */
317
+ commit() {
318
+ this.initializeMachine();
319
+ return this;
320
+ }
321
+ // record all object paths that leads to a suspended state
322
+ #getSuspendedPaths({
323
+ value,
324
+ path,
325
+ suspendedPaths
326
+ }) {
327
+ if (typeof value === "string") {
328
+ if (value === "suspended") {
329
+ suspendedPaths.add(path);
330
+ }
331
+ } else {
332
+ Object.keys(value).forEach(
333
+ (key) => this.#getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
334
+ );
335
+ }
336
+ }
337
+ #isFinalState(status) {
338
+ return ["completed", "failed"].includes(status);
339
+ }
340
+ #recursivelyCheckForFinalState({
341
+ value,
342
+ suspendedPaths,
343
+ path
344
+ }) {
345
+ if (typeof value === "string") {
346
+ return this.#isFinalState(value) || suspendedPaths.has(path);
347
+ }
348
+ return Object.keys(value).every(
349
+ (key) => this.#recursivelyCheckForFinalState({ value: value[key], suspendedPaths, path: path ? `${path}.${key}` : key })
350
+ );
351
+ }
352
+ #buildBaseState(stepNode, nextSteps = []) {
353
+ const nextStep = nextSteps.shift();
354
+ return {
355
+ initial: "pending",
356
+ on: {
357
+ RESET_TO_PENDING: {
358
+ target: ".pending"
359
+ // Note the dot to target child state
360
+ }
361
+ },
362
+ states: {
363
+ pending: {
364
+ entry: () => {
365
+ this.logger.debug(`Step ${stepNode.step.id} pending`, {
366
+ stepId: stepNode.step.id,
367
+ runId: this.#runId
368
+ });
369
+ },
370
+ exit: () => {
371
+ this.logger.debug(`Step ${stepNode.step.id} finished pending`, {
372
+ stepId: stepNode.step.id,
373
+ runId: this.#runId
374
+ });
375
+ },
376
+ invoke: {
377
+ src: "conditionCheck",
378
+ input: ({ context }) => {
379
+ return {
380
+ context,
381
+ stepNode
382
+ };
383
+ },
384
+ onDone: [
385
+ {
386
+ guard: ({ event }) => {
387
+ return event.output.type === "SUSPENDED";
388
+ },
389
+ target: "suspended",
390
+ actions: [
391
+ assign({
392
+ steps: ({ context, event }) => {
393
+ if (event.output.type !== "SUSPENDED") return context.steps;
394
+ return {
395
+ ...context.steps,
396
+ [stepNode.step.id]: {
397
+ status: "suspended",
398
+ ...context.steps?.[stepNode.step.id] || {}
399
+ }
400
+ };
401
+ },
402
+ attempts: ({ context, event }) => {
403
+ if (event.output.type !== "SUSPENDED") return context.attempts;
404
+ return { ...context.attempts, [stepNode.step.id]: stepNode.step.retryConfig?.attempts || 3 };
405
+ }
406
+ })
407
+ ]
408
+ },
409
+ {
410
+ guard: ({ event }) => {
411
+ return event.output.type === "WAITING";
412
+ },
413
+ target: "waiting",
414
+ actions: [
415
+ { type: "decrementAttemptCount", params: { stepId: stepNode.step.id } },
416
+ assign({
417
+ steps: ({ context, event }) => {
418
+ if (event.output.type !== "WAITING") return context.steps;
419
+ return {
420
+ ...context.steps,
421
+ [stepNode.step.id]: {
422
+ status: "waiting"
423
+ }
424
+ };
425
+ }
426
+ })
427
+ ]
428
+ },
429
+ {
430
+ guard: ({ event }) => {
431
+ return event.output.type === "CONDITIONS_MET";
432
+ },
433
+ target: "executing"
434
+ },
435
+ {
436
+ guard: ({ event }) => {
437
+ return event.output.type === "CONDITION_FAILED";
438
+ },
439
+ target: "failed",
440
+ actions: assign({
441
+ steps: ({ context, event }) => {
442
+ if (event.output.type !== "CONDITION_FAILED") return context.steps;
443
+ this.logger.debug(`Workflow condition check failed`, {
444
+ error: event.output.error,
445
+ stepId: stepNode.step.id
446
+ });
447
+ return {
448
+ ...context.steps,
449
+ [stepNode.step.id]: {
450
+ status: "failed",
451
+ error: event.output.error
452
+ }
453
+ };
454
+ }
455
+ })
456
+ }
457
+ ]
458
+ }
459
+ },
460
+ waiting: {
461
+ entry: () => {
462
+ this.logger.debug(`Step ${stepNode.step.id} waiting`, {
463
+ stepId: stepNode.step.id,
464
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
465
+ runId: this.#runId
466
+ });
467
+ },
468
+ exit: () => {
469
+ this.logger.debug(`Step ${stepNode.step.id} finished waiting`, {
470
+ stepId: stepNode.step.id,
471
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
472
+ runId: this.#runId
473
+ });
474
+ },
475
+ after: {
476
+ [stepNode.step.id]: {
477
+ target: "pending"
478
+ }
479
+ }
480
+ },
481
+ suspended: {
482
+ type: "final",
483
+ entry: [
484
+ () => {
485
+ this.logger.debug(`Step ${stepNode.step.id} suspended`, {
486
+ stepId: stepNode.step.id,
487
+ runId: this.#runId
488
+ });
489
+ },
490
+ assign({
491
+ steps: ({ context }) => ({
492
+ ...context.steps,
493
+ [stepNode.step.id]: {
494
+ ...context?.steps?.[stepNode.step.id] || {},
495
+ status: "suspended"
496
+ }
497
+ })
498
+ })
499
+ ]
500
+ // after: {
501
+ // [stepNode.step.id]: {
502
+ // target: 'pending',
503
+ // actions: [
504
+ // assign({
505
+ // attempts: ({ context }: { context: WorkflowContext }) => ({
506
+ // ...context.attempts,
507
+ // [stepNode.step.id]: this.#steps[stepNode.step.id]?.retryConfig?.attempts || 3,
508
+ // }),
509
+ // }),
510
+ // ],
511
+ // }
512
+ // },
513
+ // entry: () => {
514
+ // this.logger.debug(`Step ${stepNode.step.id} suspended ${new Date().toISOString()}`);
515
+ // },
516
+ // exit: () => {
517
+ // this.logger.debug(`Step ${stepNode.step.id} finished suspended ${new Date().toISOString()}`);
518
+ // },
519
+ // after: {
520
+ // [stepNode.step.id]: {
521
+ // target: 'suspended',
522
+ // },
523
+ // },
524
+ },
525
+ executing: {
526
+ entry: () => {
527
+ this.logger.debug(`Step ${stepNode.step.id} executing`, {
528
+ stepId: stepNode.step.id,
529
+ runId: this.#runId
530
+ });
531
+ },
532
+ on: {
533
+ SUSPENDED: {
534
+ target: "suspended",
535
+ actions: [
536
+ assign({
537
+ steps: ({ context }) => ({
538
+ ...context.steps,
539
+ [stepNode.step.id]: {
540
+ status: "suspended"
541
+ }
542
+ })
543
+ })
544
+ ]
545
+ }
546
+ },
547
+ invoke: {
548
+ src: "resolverFunction",
549
+ input: ({ context }) => ({
550
+ context,
551
+ stepNode
552
+ }),
553
+ onDone: {
554
+ target: "runningSubscribers",
555
+ actions: [
556
+ ({ event }) => this.logger.debug(`Step ${stepNode.step.id} finished executing`, {
557
+ stepId: stepNode.step.id,
558
+ output: event.output,
559
+ runId: this.#runId
560
+ }),
561
+ { type: "updateStepResult", params: { stepId: stepNode.step.id } },
562
+ { type: "spawnSubscribers", params: { stepId: stepNode.step.id } }
563
+ ]
564
+ },
565
+ onError: {
566
+ target: "failed",
567
+ actions: [{ type: "setStepError", params: { stepId: stepNode.step.id } }]
568
+ }
569
+ }
570
+ },
571
+ runningSubscribers: {
572
+ entry: () => {
573
+ this.logger.debug(`Step ${stepNode.step.id} running subscribers`, {
574
+ stepId: stepNode.step.id,
575
+ runId: this.#runId
576
+ });
577
+ },
578
+ exit: () => {
579
+ this.logger.debug(`Step ${stepNode.step.id} finished running subscribers`, {
580
+ stepId: stepNode.step.id,
581
+ runId: this.#runId
582
+ });
583
+ },
584
+ invoke: {
585
+ src: "spawnSubscriberFunction",
586
+ input: ({ context }) => ({
587
+ parentStepId: stepNode.step.id,
588
+ context
589
+ }),
590
+ onDone: {
591
+ target: nextStep ? nextStep.step.id : "completed",
592
+ actions: [
593
+ assign({
594
+ steps: ({ context, event }) => ({
595
+ ...context.steps,
596
+ ...event.output.steps
597
+ })
598
+ }),
599
+ () => this.logger.debug(`Subscriber execution completed`, { stepId: stepNode.step.id })
600
+ ]
601
+ },
602
+ onError: {
603
+ target: nextStep ? nextStep.step.id : "completed",
604
+ actions: ({ event }) => {
605
+ this.logger.debug(`Subscriber execution failed`, {
606
+ error: event.error,
607
+ stepId: stepNode.step.id
608
+ });
609
+ }
610
+ }
611
+ }
612
+ },
613
+ completed: {
614
+ type: "final",
615
+ entry: [
616
+ { type: "notifyStepCompletion", params: { stepId: stepNode.step.id } },
617
+ { type: "snapshotStep", params: { stepId: stepNode.step.id } },
618
+ { type: "persistSnapshot" }
619
+ ]
620
+ },
621
+ failed: {
622
+ type: "final",
623
+ entry: [
624
+ { type: "notifyStepCompletion", params: { stepId: stepNode.step.id } },
625
+ { type: "snapshotStep", params: { stepId: stepNode.step.id } },
626
+ { type: "persistSnapshot" }
627
+ ]
628
+ },
629
+ // build chain of next steps recursively
630
+ ...nextStep ? { [nextStep.step.id]: { ...this.#buildBaseState(nextStep, nextSteps) } } : {}
631
+ }
632
+ };
633
+ }
634
+ #makeStepKey(step) {
635
+ return `${step.id}`;
636
+ }
637
+ /**
638
+ * Builds the state hierarchy for the workflow
639
+ * @returns Object representing the state hierarchy
640
+ */
641
+ #buildStateHierarchy(stepGraph) {
642
+ const states = {};
643
+ stepGraph.initial.forEach((stepNode) => {
644
+ const nextSteps = [...stepGraph[stepNode.step.id] || []];
645
+ states[stepNode.step.id] = {
646
+ ...this.#buildBaseState(stepNode, nextSteps)
647
+ };
648
+ });
649
+ return states;
650
+ }
651
+ #getDefaultActions() {
652
+ return {
653
+ updateStepResult: assign({
654
+ steps: ({ context, event }) => {
655
+ if (!isTransitionEvent(event)) return context.steps;
656
+ const { stepId, result } = event.output;
657
+ return {
658
+ ...context.steps,
659
+ [stepId]: {
660
+ status: "success",
661
+ output: result
662
+ }
663
+ };
664
+ }
665
+ }),
666
+ setStepError: assign({
667
+ steps: ({ context, event }, params) => {
668
+ if (!isErrorEvent(event)) return context.steps;
669
+ const { stepId } = params;
670
+ if (!stepId) return context.steps;
671
+ return {
672
+ ...context.steps,
673
+ [stepId]: {
674
+ status: "failed",
675
+ error: event.error.message
676
+ }
677
+ };
678
+ }
679
+ }),
680
+ notifyStepCompletion: async (_, params) => {
681
+ const { stepId } = params;
682
+ this.logger.debug(`Step ${stepId} completed`);
683
+ },
684
+ snapshotStep: assign({
685
+ _snapshot: ({}, params) => {
686
+ const { stepId } = params;
687
+ return { stepId };
688
+ }
689
+ }),
690
+ persistSnapshot: async ({ context }) => {
691
+ if (context._snapshot) {
692
+ return await this.#persistWorkflowSnapshot();
693
+ }
694
+ return;
695
+ },
696
+ decrementAttemptCount: assign({
697
+ attempts: ({ context, event }, params) => {
698
+ if (!isTransitionEvent(event)) return context.attempts;
699
+ const { stepId } = params;
700
+ const attemptCount = context.attempts[stepId];
701
+ if (attemptCount === undefined) return context.attempts;
702
+ return { ...context.attempts, [stepId]: attemptCount - 1 };
703
+ }
704
+ })
705
+ };
706
+ }
707
+ #getInjectables() {
708
+ return {
709
+ runId: this.#runId,
710
+ mastra: this.#mastra
711
+ };
712
+ }
713
+ #getDefaultActors() {
714
+ return {
715
+ resolverFunction: fromPromise(async ({ input }) => {
716
+ const { stepNode, context } = input;
717
+ const injectables = this.#getInjectables();
718
+ const resolvedData = this.#resolveVariables({
719
+ stepConfig: stepNode.config,
720
+ context,
721
+ stepId: stepNode.step.id
722
+ });
723
+ this.logger.debug(`Resolved variables for ${stepNode.step.id}`, {
724
+ resolvedData,
725
+ runId: this.#runId
726
+ });
727
+ const result = await stepNode.config.handler({
728
+ context: resolvedData,
729
+ suspend: async () => {
730
+ if (this.#actor) {
731
+ context.steps[stepNode.step.id] = {
732
+ status: "suspended"
733
+ };
734
+ await this.#persistWorkflowSnapshot();
735
+ this.logger.debug(`Sending SUSPENDED event for step ${stepNode.step.id}`);
736
+ this.#actor?.send({ type: "SUSPENDED", stepId: stepNode.step.id });
737
+ } else {
738
+ this.logger.debug(`Actor not available for step ${stepNode.step.id}`);
739
+ }
740
+ },
741
+ ...injectables
742
+ });
743
+ this.logger.debug(`Step ${stepNode.step.id} result`, {
744
+ stepId: stepNode.step.id,
745
+ result,
746
+ runId: this.#runId
747
+ });
748
+ return {
749
+ stepId: stepNode.step.id,
750
+ result
751
+ };
752
+ }),
753
+ conditionCheck: fromPromise(async ({ input }) => {
754
+ const { context, stepNode } = input;
755
+ const stepConfig = stepNode.config;
756
+ const attemptCount = context.attempts[stepNode.step.id];
757
+ this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
758
+ stepId: stepNode.step.id,
759
+ runId: this.#runId
760
+ });
761
+ this.logger.debug(`Attempt count for step ${stepNode.step.id}`, {
762
+ attemptCount,
763
+ attempts: context.attempts,
764
+ runId: this.#runId,
765
+ stepId: stepNode.step.id
766
+ });
767
+ if (!attemptCount || attemptCount < 0) {
768
+ if (stepConfig?.snapshotOnTimeout) {
769
+ return { type: "SUSPENDED", stepId: stepNode.step.id };
770
+ }
771
+ return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
772
+ }
773
+ if (!stepConfig?.when) {
774
+ return { type: "CONDITIONS_MET" };
775
+ }
776
+ this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
777
+ stepId: stepNode.step.id,
778
+ runId: this.#runId
779
+ });
780
+ if (typeof stepConfig?.when === "function") {
781
+ const conditionMet = await stepConfig.when({ context });
782
+ if (conditionMet) {
783
+ this.logger.debug(`Condition met for step ${stepNode.step.id}`, {
784
+ stepId: stepNode.step.id,
785
+ runId: this.#runId
786
+ });
787
+ return { type: "CONDITIONS_MET" };
788
+ }
789
+ if (!attemptCount || attemptCount < 0) {
790
+ return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
791
+ }
792
+ return { type: "WAITING", stepId: stepNode.step.id };
793
+ } else {
794
+ const conditionMet = this.#evaluateCondition(stepConfig.when, context);
795
+ if (!conditionMet) {
796
+ return {
797
+ type: "CONDITION_FAILED",
798
+ error: `Step:${stepNode.step.id} condition check failed`
799
+ };
800
+ }
801
+ }
802
+ return { type: "CONDITIONS_MET" };
803
+ }),
804
+ spawnSubscriberFunction: fromPromise(
805
+ async ({
806
+ input
807
+ }) => {
808
+ const { parentStepId, context } = input;
809
+ const stepGraph = this.#stepSubscriberGraph[parentStepId];
810
+ if (!stepGraph) {
811
+ return {
812
+ steps: {}
813
+ };
814
+ }
815
+ const subscriberMachine = setup({
816
+ types: {},
817
+ delays: this.#makeDelayMap(),
818
+ actions: this.#getDefaultActions(),
819
+ actors: this.#getDefaultActors()
820
+ }).createMachine({
821
+ id: `${this.name}-subscriber-${parentStepId}`,
822
+ context,
823
+ type: "parallel",
824
+ states: this.#buildStateHierarchy(stepGraph)
825
+ });
826
+ const actor = createActor(subscriberMachine, { input: context });
827
+ actor.start();
828
+ return new Promise((resolve) => {
829
+ const suspendedPaths = /* @__PURE__ */ new Set();
830
+ actor.subscribe((state) => {
831
+ this.#getSuspendedPaths({
832
+ value: state.value,
833
+ path: "",
834
+ suspendedPaths
835
+ });
836
+ const allStatesValue = state.value;
837
+ const allStatesComplete = this.#recursivelyCheckForFinalState({
838
+ value: allStatesValue,
839
+ suspendedPaths,
840
+ path: ""
841
+ });
842
+ if (allStatesComplete) {
843
+ actor.stop();
844
+ resolve({
845
+ steps: state.context.steps
846
+ });
847
+ }
848
+ });
849
+ });
850
+ }
851
+ )
852
+ };
853
+ }
854
+ /**
855
+ * Persists the workflow state to the database
856
+ */
857
+ async #persistWorkflowSnapshot() {
858
+ const snapshotFromActor = this.#actor?.getPersistedSnapshot();
859
+ if (!this.#mastra?.storage) {
860
+ this.logger.debug("Snapshot cannot be persisted. Mastra engine is not initialized", {
861
+ runId: this.#runId
862
+ });
863
+ return;
864
+ }
865
+ if (!snapshotFromActor) {
866
+ this.logger.debug("Snapshot cannot be persisted. No snapshot received.", { runId: this.#runId });
867
+ return;
868
+ }
869
+ if (this.#mastra?.storage) {
870
+ await this.#mastra.storage.persistWorkflowSnapshot({
871
+ workflowName: this.name,
872
+ runId: this.#runId,
873
+ snapshot: snapshotFromActor
874
+ });
875
+ }
876
+ return this.#runId;
877
+ }
878
+ async #loadWorkflowSnapshot(runId) {
879
+ if (!this.#mastra?.storage) {
880
+ this.logger.debug("Snapshot cannot be loaded. Mastra engine is not initialized", { runId });
881
+ return;
882
+ }
883
+ return this.#mastra.storage.loadWorkflowSnapshot({ runId, workflowName: this.name });
884
+ }
885
+ /**
886
+ * Resolves variables for a step from trigger data or previous step results
887
+ * @param stepConfig - Configuration of the step needing variable resolution
888
+ * @param context - Current workflow context containing results and trigger data
889
+ * @returns Object containing resolved variable values
890
+ */
891
+ #resolveVariables({
892
+ stepConfig,
893
+ context,
894
+ stepId
895
+ }) {
896
+ this.logger.debug(`Resolving variables for step ${stepId}`, {
897
+ stepId,
898
+ runId: this.#runId
899
+ });
900
+ const resolvedData = {
901
+ ...context,
902
+ getStepPayload: (stepId2) => {
903
+ if (stepId2 === "trigger") {
904
+ return context.triggerData;
905
+ }
906
+ const result = context.steps[stepId2];
907
+ if (result && result.status === "success") {
908
+ return result.output;
909
+ }
910
+ return undefined;
911
+ }
912
+ };
913
+ for (const [key, variable] of Object.entries(stepConfig.data)) {
914
+ const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id]);
915
+ this.logger.debug(
916
+ `Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id}`,
917
+ {
918
+ sourceData,
919
+ path: variable.path,
920
+ runId: this.#runId
921
+ }
922
+ );
923
+ if (!sourceData && variable.step !== "trigger") {
924
+ resolvedData[key] = undefined;
925
+ continue;
926
+ }
927
+ const value = variable.path === "" || variable.path === "." ? sourceData : get(sourceData, variable.path);
928
+ this.logger.debug(`Resolved variable ${key}`, {
929
+ value,
930
+ runId: this.#runId
931
+ });
932
+ resolvedData[key] = value;
933
+ }
934
+ return resolvedData;
935
+ }
936
+ /**
937
+ * Evaluates a single condition against workflow context
938
+ */
939
+ #evaluateCondition(condition, context) {
940
+ let andBranchResult = true;
941
+ let baseResult = true;
942
+ let orBranchResult = true;
943
+ const simpleCondition = Object.entries(condition).find(([key]) => key.includes("."));
944
+ if (simpleCondition) {
945
+ const [key, queryValue] = simpleCondition;
946
+ const [stepId, ...pathParts] = key.split(".");
947
+ const path = pathParts.join(".");
948
+ const sourceData = stepId === "trigger" ? context.triggerData : getStepResult(context.steps[stepId]);
949
+ this.logger.debug(`Got condition data from step ${stepId}`, {
950
+ stepId,
951
+ sourceData,
952
+ runId: this.#runId
953
+ });
954
+ if (!sourceData) {
955
+ return false;
956
+ }
957
+ let value = get(sourceData, path);
958
+ if (stepId !== "trigger" && path === "status" && !value) {
959
+ value = "success";
960
+ }
961
+ if (typeof queryValue === "object" && queryValue !== null) {
962
+ baseResult = sift(queryValue)(value);
963
+ } else {
964
+ baseResult = value === queryValue;
965
+ }
966
+ }
967
+ if ("ref" in condition) {
968
+ const { ref, query } = condition;
969
+ const sourceData = ref.step === "trigger" ? context.triggerData : getStepResult(context.steps[ref.step.id]);
970
+ this.logger.debug(`Got condition data from ${ref.step === "trigger" ? "trigger" : ref.step.id}`, {
971
+ sourceData,
972
+ runId: this.#runId
973
+ });
974
+ if (!sourceData) {
975
+ return false;
976
+ }
977
+ let value = get(sourceData, ref.path);
978
+ if (ref.step !== "trigger" && ref.path === "status" && !value) {
979
+ value = "success";
980
+ }
981
+ baseResult = sift(query)(value);
982
+ }
983
+ if ("and" in condition) {
984
+ andBranchResult = condition.and.every((cond) => this.#evaluateCondition(cond, context));
985
+ this.logger.debug(`Evaluated AND condition`, {
986
+ andBranchResult,
987
+ runId: this.#runId
988
+ });
989
+ }
990
+ if ("or" in condition) {
991
+ orBranchResult = condition.or.some((cond) => this.#evaluateCondition(cond, context));
992
+ this.logger.debug(`Evaluated OR condition`, {
993
+ orBranchResult,
994
+ runId: this.#runId
995
+ });
996
+ }
997
+ const finalResult = baseResult && andBranchResult && orBranchResult;
998
+ this.logger.debug(`Evaluated condition`, {
999
+ finalResult,
1000
+ runId: this.#runId
1001
+ });
1002
+ return finalResult;
1003
+ }
1004
+ #makeStepDef(stepId) {
1005
+ const executeStep = (handler2, spanName, attributes) => {
1006
+ return async (data) => {
1007
+ return await context.with(trace.setSpan(context.active(), this.#executionSpan), async () => {
1008
+ return this.#mastra.telemetry.traceMethod(handler2, {
1009
+ spanName,
1010
+ attributes
1011
+ })(data);
1012
+ });
1013
+ };
1014
+ };
1015
+ const handler = async ({ context, ...rest }) => {
1016
+ const targetStep = this.#steps[stepId];
1017
+ if (!targetStep) throw new Error(`Step not found`);
1018
+ const { payload = {}, execute } = targetStep;
1019
+ const mergedData = {
1020
+ ...payload,
1021
+ ...context
1022
+ };
1023
+ const finalAction = this.#mastra?.telemetry ? executeStep(execute, `workflow.${this.name}.action.${stepId}`, {
1024
+ componentName: this.name,
1025
+ runId: context.runId ?? this.#runId
1026
+ }) : execute;
1027
+ return finalAction ? await finalAction({ context: mergedData, ...rest }) : {};
1028
+ };
1029
+ const finalHandler = ({ context, ...rest }) => {
1030
+ if (this.#executionSpan) {
1031
+ return executeStep(handler, `workflow.${this.name}.step.${stepId}`, {
1032
+ componentName: this.name,
1033
+ runId: context.runId ?? this.#runId
1034
+ })({ context, ...rest });
1035
+ }
1036
+ return handler({ context, ...rest });
1037
+ };
1038
+ return {
1039
+ handler: finalHandler,
1040
+ data: {}
1041
+ };
1042
+ }
1043
+ /**
1044
+ * Creates a map of step IDs to their respective delay values
1045
+ * @returns Object mapping step IDs to delay values
1046
+ */
1047
+ #makeDelayMap() {
1048
+ const delayMap = {};
1049
+ Object.keys(this.#steps).forEach((stepId) => {
1050
+ delayMap[stepId] = this.#steps[stepId]?.retryConfig?.delay || this.#retryConfig?.delay || 1e3;
1051
+ });
1052
+ return delayMap;
1053
+ }
1054
+ /**
1055
+ * Cleans up the actor instance
1056
+ */
1057
+ #cleanup() {
1058
+ if (this.#actor) {
1059
+ this.#actor.stop();
1060
+ this.#actor = null;
1061
+ }
1062
+ }
1063
+ #getActivePathsAndStatus(value) {
1064
+ const paths = [];
1065
+ const traverse = (current, path = []) => {
1066
+ for (const [key, value2] of Object.entries(current)) {
1067
+ const currentPath = [...path, key];
1068
+ if (typeof value2 === "string") {
1069
+ paths.push({
1070
+ stepPath: currentPath,
1071
+ stepId: key,
1072
+ status: value2
1073
+ });
1074
+ } else if (typeof value2 === "object" && value2 !== null) {
1075
+ traverse(value2, currentPath);
1076
+ }
1077
+ }
1078
+ };
1079
+ traverse(value);
1080
+ return paths;
1081
+ }
1082
+ async getState(runId) {
1083
+ if (this.#runId === runId && this.#actor) {
1084
+ const snapshot = this.#actor.getSnapshot();
1085
+ const m = this.#getActivePathsAndStatus(snapshot.value);
1086
+ return {
1087
+ runId,
1088
+ value: snapshot.value,
1089
+ context: snapshot.context,
1090
+ activePaths: m,
1091
+ timestamp: Date.now()
1092
+ };
1093
+ }
1094
+ const storedSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
1095
+ runId,
1096
+ workflowName: this.name
1097
+ });
1098
+ if (storedSnapshot) {
1099
+ const parsed = storedSnapshot;
1100
+ const m = this.#getActivePathsAndStatus(parsed.value);
1101
+ return {
1102
+ runId,
1103
+ value: parsed.value,
1104
+ context: parsed.context,
1105
+ activePaths: m,
1106
+ timestamp: Date.now()
1107
+ };
1108
+ }
1109
+ return null;
1110
+ }
1111
+ watch(onTransition) {
1112
+ this.#onStepTransition.add(onTransition);
1113
+ return () => {
1114
+ this.#onStepTransition.delete(onTransition);
1115
+ };
1116
+ }
1117
+ async resume({
1118
+ runId,
1119
+ stepId,
1120
+ context: resumeContext
1121
+ }) {
1122
+ const snapshot = await this.#loadWorkflowSnapshot(runId);
1123
+ if (!snapshot) {
1124
+ throw new Error(`No snapshot found for workflow run ${runId}`);
1125
+ }
1126
+ let parsedSnapshot;
1127
+ try {
1128
+ parsedSnapshot = typeof snapshot === "string" ? JSON.parse(snapshot) : snapshot;
1129
+ } catch (error) {
1130
+ this.logger.debug("Failed to parse workflow snapshot for resume", { error, runId });
1131
+ throw new Error("Failed to parse workflow snapshot");
1132
+ }
1133
+ if (resumeContext) {
1134
+ parsedSnapshot.context.steps[stepId] = {
1135
+ status: "success",
1136
+ output: {
1137
+ ...parsedSnapshot?.context?.steps?.[stepId]?.output || {},
1138
+ ...resumeContext
1139
+ }
1140
+ };
1141
+ }
1142
+ if (parsedSnapshot.children) {
1143
+ Object.entries(parsedSnapshot.children).forEach(([_childId, child]) => {
1144
+ if (child.snapshot?.input?.stepNode) {
1145
+ const stepDef = this.#makeStepDef(child.snapshot.input.stepNode.step.id);
1146
+ child.snapshot.input.stepNode.config = {
1147
+ ...child.snapshot.input.stepNode.config,
1148
+ ...stepDef
1149
+ };
1150
+ child.snapshot.input.context = parsedSnapshot.context;
1151
+ }
1152
+ });
1153
+ }
1154
+ const updateStepInHierarchy = (value, targetStepId) => {
1155
+ const result = {};
1156
+ for (const key of Object.keys(value)) {
1157
+ const currentValue = value[key];
1158
+ if (key === targetStepId) {
1159
+ result[key] = "pending";
1160
+ } else if (typeof currentValue === "object" && currentValue !== null) {
1161
+ result[key] = updateStepInHierarchy(currentValue, targetStepId);
1162
+ } else {
1163
+ result[key] = currentValue;
1164
+ }
1165
+ }
1166
+ return result;
1167
+ };
1168
+ parsedSnapshot.value = updateStepInHierarchy(parsedSnapshot.value, stepId);
1169
+ if (parsedSnapshot.context?.attempts) {
1170
+ parsedSnapshot.context.attempts[stepId] = this.#steps[stepId]?.retryConfig?.attempts || this.#retryConfig?.attempts || 3;
1171
+ }
1172
+ this.logger.debug("Resuming workflow with updated snapshot", {
1173
+ updatedSnapshot: parsedSnapshot,
1174
+ runId,
1175
+ stepId
1176
+ });
1177
+ return this.execute({
1178
+ snapshot: parsedSnapshot,
1179
+ runId,
1180
+ stepId
1181
+ });
1182
+ }
1183
+ __registerPrimitives(p) {
1184
+ if (p.telemetry) {
1185
+ this.__setTelemetry(p.telemetry);
1186
+ }
1187
+ if (p.logger) {
1188
+ this.__setLogger(p.logger);
1189
+ }
1190
+ this.#mastra = p;
1191
+ }
1192
+ get stepGraph() {
1193
+ return this.#stepGraph;
1194
+ }
1195
+ get stepSubscriberGraph() {
1196
+ return this.#stepSubscriberGraph;
1197
+ }
1198
+ get steps() {
1199
+ return this.#steps;
1200
+ }
1201
+ };
1202
+
1203
+ export { Step, Workflow, createStep, getStepResult, isErrorEvent, isTransitionEvent, isVariableReference };