@mastra/core 0.7.0 → 0.8.0-alpha.1

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 (69) hide show
  1. package/dist/agent/index.cjs +2 -2
  2. package/dist/agent/index.d.cts +3 -1
  3. package/dist/agent/index.d.ts +3 -1
  4. package/dist/agent/index.js +1 -1
  5. package/dist/{base-Cyl73WbV.d.ts → base-B65ZjbJw.d.ts} +100 -29
  6. package/dist/{base-C0wILuA9.d.cts → base-CYeyHJtc.d.cts} +100 -29
  7. package/dist/{chunk-ZBKJDQPM.js → chunk-5U7ZB5ID.js} +7 -0
  8. package/dist/{chunk-43SD5CUE.js → chunk-6IH4PY2A.js} +60 -6
  9. package/dist/{chunk-SMBKF6K5.js → chunk-APV5PNPE.js} +9 -0
  10. package/dist/chunk-AZEVFYZU.cjs +4609 -0
  11. package/dist/{chunk-ASFUEC75.cjs → chunk-BS2HQKYH.cjs} +61 -6
  12. package/dist/{chunk-YXJQFZOW.cjs → chunk-FKP3IMFA.cjs} +7 -0
  13. package/dist/{chunk-U7ONOIBO.cjs → chunk-G3GVZCXA.cjs} +9 -0
  14. package/dist/chunk-HWCOUI5E.js +4582 -0
  15. package/dist/{chunk-QM6WIIPM.js → chunk-TKOMVZT3.js} +1 -1
  16. package/dist/{chunk-WESJ2ZY7.cjs → chunk-TKOVKRVO.cjs} +2 -2
  17. package/dist/eval/index.d.cts +3 -1
  18. package/dist/eval/index.d.ts +3 -1
  19. package/dist/index.cjs +53 -42
  20. package/dist/index.d.cts +7 -5
  21. package/dist/index.d.ts +7 -5
  22. package/dist/index.js +6 -6
  23. package/dist/integration/index.d.cts +3 -1
  24. package/dist/integration/index.d.ts +3 -1
  25. package/dist/llm/index.d.cts +3 -1
  26. package/dist/llm/index.d.ts +3 -1
  27. package/dist/mastra/index.cjs +2 -2
  28. package/dist/mastra/index.d.cts +3 -1
  29. package/dist/mastra/index.d.ts +3 -1
  30. package/dist/mastra/index.js +1 -1
  31. package/dist/memory/index.cjs +6 -2
  32. package/dist/memory/index.d.cts +3 -1
  33. package/dist/memory/index.d.ts +3 -1
  34. package/dist/memory/index.js +1 -1
  35. package/dist/network/index.cjs +2 -2
  36. package/dist/network/index.d.cts +3 -1
  37. package/dist/network/index.d.ts +3 -1
  38. package/dist/network/index.js +1 -1
  39. package/dist/relevance/index.cjs +4 -4
  40. package/dist/relevance/index.d.cts +3 -1
  41. package/dist/relevance/index.d.ts +3 -1
  42. package/dist/relevance/index.js +1 -1
  43. package/dist/server/index.cjs +17 -0
  44. package/dist/server/index.d.cts +37 -0
  45. package/dist/server/index.d.ts +37 -0
  46. package/dist/server/index.js +15 -0
  47. package/dist/storage/index.d.cts +3 -1
  48. package/dist/storage/index.d.ts +3 -1
  49. package/dist/storage/libsql/index.d.cts +3 -1
  50. package/dist/storage/libsql/index.d.ts +3 -1
  51. package/dist/telemetry/index.d.cts +3 -1
  52. package/dist/telemetry/index.d.ts +3 -1
  53. package/dist/tools/index.d.cts +3 -1
  54. package/dist/tools/index.d.ts +3 -1
  55. package/dist/utils.d.cts +5 -3
  56. package/dist/utils.d.ts +5 -3
  57. package/dist/vector/libsql/index.cjs +3 -3
  58. package/dist/vector/libsql/index.js +1 -1
  59. package/dist/voice/index.d.cts +3 -1
  60. package/dist/voice/index.d.ts +3 -1
  61. package/dist/workflows/index.cjs +28 -20
  62. package/dist/workflows/index.d.cts +14 -5
  63. package/dist/workflows/index.d.ts +14 -5
  64. package/dist/workflows/index.js +1 -1
  65. package/package.json +4 -2
  66. package/dist/chunk-C6BBAS4I.cjs +0 -1715
  67. package/dist/chunk-GG6TEAMJ.cjs +0 -2289
  68. package/dist/chunk-R2M5CZ5U.js +0 -2264
  69. package/dist/chunk-VNQRLYIA.js +0 -1715
@@ -1,2264 +0,0 @@
1
- import { createMastraProxy } from './chunk-2YF5JYTJ.js';
2
- import { MastraBase } from './chunk-VN4M67DA.js';
3
- import { context, trace } from '@opentelemetry/api';
4
- import { z } from 'zod';
5
- import { get } from 'radash';
6
- import EventEmitter from 'node:events';
7
- import sift from 'sift';
8
- import { createActor, assign, fromPromise, setup } from 'xstate';
9
-
10
- // src/workflows/step.ts
11
- var Step = class {
12
- id;
13
- description;
14
- inputSchema;
15
- outputSchema;
16
- payload;
17
- execute;
18
- retryConfig;
19
- mastra;
20
- constructor({
21
- id,
22
- description,
23
- execute,
24
- payload,
25
- outputSchema,
26
- inputSchema,
27
- retryConfig
28
- }) {
29
- this.id = id;
30
- this.description = description ?? "";
31
- this.inputSchema = inputSchema;
32
- this.payload = payload;
33
- this.outputSchema = outputSchema;
34
- this.execute = execute;
35
- this.retryConfig = retryConfig;
36
- }
37
- };
38
- function createStep(opts) {
39
- return new Step(opts);
40
- }
41
-
42
- // src/workflows/types.ts
43
- var WhenConditionReturnValue = /* @__PURE__ */ ((WhenConditionReturnValue2) => {
44
- WhenConditionReturnValue2["CONTINUE"] = "continue";
45
- WhenConditionReturnValue2["CONTINUE_FAILED"] = "continue_failed";
46
- WhenConditionReturnValue2["ABORT"] = "abort";
47
- WhenConditionReturnValue2["LIMBO"] = "limbo";
48
- return WhenConditionReturnValue2;
49
- })(WhenConditionReturnValue || {});
50
- function isErrorEvent(stateEvent) {
51
- return stateEvent.type.startsWith("xstate.error.actor.");
52
- }
53
- function isTransitionEvent(stateEvent) {
54
- return stateEvent.type.startsWith("xstate.done.actor.");
55
- }
56
- function isVariableReference(value) {
57
- return typeof value === "object" && "step" in value && "path" in value;
58
- }
59
- function getStepResult(result) {
60
- if (result?.status === "success") return result.output;
61
- return void 0;
62
- }
63
- function getSuspendedPaths({
64
- value,
65
- path,
66
- suspendedPaths
67
- }) {
68
- if (typeof value === "string") {
69
- if (value === "suspended") {
70
- suspendedPaths.add(path);
71
- }
72
- } else {
73
- Object.keys(value).forEach(
74
- (key) => getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
75
- );
76
- }
77
- }
78
- function isFinalState(status) {
79
- return ["completed", "failed"].includes(status);
80
- }
81
- function isLimboState(status) {
82
- return status === "limbo";
83
- }
84
- function recursivelyCheckForFinalState({
85
- value,
86
- suspendedPaths,
87
- path
88
- }) {
89
- if (typeof value === "string") {
90
- return isFinalState(value) || isLimboState(value) || suspendedPaths.has(path);
91
- }
92
- return Object.keys(value).every(
93
- (key) => recursivelyCheckForFinalState({ value: value[key], suspendedPaths, path: path ? `${path}.${key}` : key })
94
- );
95
- }
96
- function getActivePathsAndStatus(value) {
97
- const paths = [];
98
- const traverse = (current, path = []) => {
99
- for (const [key, value2] of Object.entries(current)) {
100
- const currentPath = [...path, key];
101
- if (typeof value2 === "string") {
102
- paths.push({
103
- stepPath: currentPath,
104
- stepId: key,
105
- status: value2
106
- });
107
- } else if (typeof value2 === "object" && value2 !== null) {
108
- traverse(value2, currentPath);
109
- }
110
- }
111
- };
112
- traverse(value);
113
- return paths;
114
- }
115
- function mergeChildValue(startStepId, parent, child) {
116
- const traverse = (current) => {
117
- const obj = {};
118
- for (const [key, value] of Object.entries(current)) {
119
- if (key === startStepId) {
120
- obj[key] = { ...child };
121
- } else if (typeof value === "string") {
122
- obj[key] = value;
123
- } else if (typeof value === "object" && value !== null) {
124
- obj[key] = traverse(value);
125
- }
126
- }
127
- return obj;
128
- };
129
- return traverse(parent);
130
- }
131
- var updateStepInHierarchy = (value, targetStepId) => {
132
- const result = {};
133
- for (const key of Object.keys(value)) {
134
- const currentValue = value[key];
135
- if (key === targetStepId) {
136
- result[key] = "pending";
137
- } else if (typeof currentValue === "object" && currentValue !== null) {
138
- result[key] = updateStepInHierarchy(currentValue, targetStepId);
139
- } else {
140
- result[key] = currentValue;
141
- }
142
- }
143
- return result;
144
- };
145
- function getResultActivePaths(state) {
146
- return getActivePathsAndStatus(state.value).reduce((acc, curr) => {
147
- const entry = { status: curr.status };
148
- if (curr.status === "suspended") {
149
- entry.suspendPayload = state.context.steps[curr.stepId].suspendPayload;
150
- }
151
- acc.set(curr.stepId, entry);
152
- return acc;
153
- }, /* @__PURE__ */ new Map());
154
- }
155
- function isWorkflow(step) {
156
- return !!step?.name;
157
- }
158
- function resolveVariables({
159
- runId,
160
- logger,
161
- variables,
162
- context
163
- }) {
164
- const resolvedData = {};
165
- for (const [key, variable] of Object.entries(variables)) {
166
- const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id ?? variable.step.name]);
167
- logger.debug(
168
- `Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id ?? variable.step.name}`,
169
- {
170
- sourceData,
171
- path: variable.path,
172
- runId
173
- }
174
- );
175
- if (!sourceData && variable.step !== "trigger") {
176
- resolvedData[key] = void 0;
177
- continue;
178
- }
179
- const value = variable.path === "" || variable.path === "." ? sourceData : get(sourceData, variable.path);
180
- logger.debug(`Resolved variable ${key}`, {
181
- value,
182
- runId
183
- });
184
- resolvedData[key] = value;
185
- }
186
- return resolvedData;
187
- }
188
- function workflowToStep(workflow, { mastra }) {
189
- workflow.setNested(true);
190
- return {
191
- id: workflow.name,
192
- workflow,
193
- execute: async ({ context, suspend, emit, runId, mastra: mastra2 }) => {
194
- if (mastra2) {
195
- workflow.__registerMastra(mastra2);
196
- workflow.__registerPrimitives({
197
- logger: mastra2.getLogger(),
198
- telemetry: mastra2.getTelemetry()
199
- });
200
- }
201
- const run = context.isResume ? workflow.createRun({ runId: context.isResume.runId }) : workflow.createRun();
202
- const unwatch = run.watch((state) => {
203
- emit("state-update", workflow.name, state.value, { ...context, ...{ [workflow.name]: state.context } });
204
- });
205
- const awaitedResult = context.isResume && context.isResume.stepId.includes(".") ? await run.resume({
206
- stepId: context.isResume.stepId.split(".").slice(1).join("."),
207
- context: context.inputData
208
- }) : await run.start({
209
- triggerData: context.inputData
210
- });
211
- unwatch();
212
- if (!awaitedResult) {
213
- throw new Error("Workflow run failed");
214
- }
215
- if (awaitedResult.activePaths?.size > 0) {
216
- const suspendedStep = [...awaitedResult.activePaths.entries()].find(([stepId, { status }]) => {
217
- return status === "suspended";
218
- });
219
- if (suspendedStep) {
220
- await suspend(suspendedStep[1].suspendPayload, { ...awaitedResult, runId: run.runId });
221
- }
222
- }
223
- return { ...awaitedResult, runId: run.runId };
224
- }
225
- };
226
- }
227
- var Machine = class extends EventEmitter {
228
- logger;
229
- #mastra;
230
- #workflowInstance;
231
- #executionSpan;
232
- #stepGraph;
233
- #machine;
234
- #runId;
235
- #startStepId;
236
- name;
237
- #actor = null;
238
- #steps = {};
239
- #retryConfig;
240
- constructor({
241
- logger,
242
- mastra,
243
- workflowInstance,
244
- executionSpan,
245
- name,
246
- runId,
247
- steps,
248
- stepGraph,
249
- retryConfig,
250
- startStepId
251
- }) {
252
- super();
253
- this.#mastra = mastra;
254
- this.#workflowInstance = workflowInstance;
255
- this.#executionSpan = executionSpan;
256
- this.logger = logger;
257
- this.#runId = runId;
258
- this.#startStepId = startStepId;
259
- this.name = name;
260
- this.#stepGraph = stepGraph;
261
- this.#steps = steps;
262
- this.#retryConfig = retryConfig;
263
- this.initializeMachine();
264
- }
265
- get startStepId() {
266
- return this.#startStepId;
267
- }
268
- async execute({
269
- stepId,
270
- input,
271
- snapshot,
272
- resumeData
273
- } = {}) {
274
- if (snapshot) {
275
- this.logger.debug(`Workflow snapshot received`, { runId: this.#runId, snapshot });
276
- }
277
- const origSteps = input.steps;
278
- const isResumedInitialStep = this.#stepGraph?.initial[0]?.step?.id === stepId;
279
- if (isResumedInitialStep) {
280
- snapshot = void 0;
281
- input.steps = {};
282
- }
283
- this.logger.debug(`Machine input prepared`, { runId: this.#runId, input });
284
- const actorSnapshot = snapshot ? {
285
- ...snapshot,
286
- context: {
287
- ...input,
288
- inputData: { ...snapshot?.context?.inputData || {}, ...resumeData },
289
- // ts-ignore is needed here because our snapshot types don't really match xstate snapshot types right now. We should fix this in general.
290
- // @ts-ignore
291
- isResume: { runId: snapshot?.context?.steps[stepId.split(".")?.[0]]?.output?.runId || this.#runId, stepId }
292
- }
293
- } : void 0;
294
- this.logger.debug(`Creating actor with configuration`, {
295
- input,
296
- actorSnapshot,
297
- runId: this.#runId,
298
- machineStates: this.#machine.config.states
299
- });
300
- this.#actor = createActor(this.#machine, {
301
- inspect: (inspectionEvent) => {
302
- this.logger.debug("XState inspection event", {
303
- type: inspectionEvent.type,
304
- event: inspectionEvent.event,
305
- runId: this.#runId
306
- });
307
- },
308
- input: {
309
- ...input,
310
- inputData: { ...snapshot?.context?.inputData || {}, ...resumeData }
311
- },
312
- snapshot: actorSnapshot
313
- });
314
- this.#actor.start();
315
- if (stepId) {
316
- this.#actor.send({ type: "RESET_TO_PENDING", stepId });
317
- }
318
- this.logger.debug("Actor started", { runId: this.#runId });
319
- return new Promise((resolve, reject) => {
320
- if (!this.#actor) {
321
- this.logger.error("Actor not initialized", { runId: this.#runId });
322
- const e = new Error("Actor not initialized");
323
- this.#executionSpan?.recordException(e);
324
- this.#executionSpan?.end();
325
- reject(e);
326
- return;
327
- }
328
- const suspendedPaths = /* @__PURE__ */ new Set();
329
- this.#actor.subscribe(async (state) => {
330
- this.emit("state-update", this.#startStepId, state.value, state.context);
331
- getSuspendedPaths({
332
- value: state.value,
333
- path: "",
334
- suspendedPaths
335
- });
336
- const allStatesValue = state.value;
337
- const allStatesComplete = recursivelyCheckForFinalState({
338
- value: allStatesValue,
339
- suspendedPaths,
340
- path: ""
341
- });
342
- this.logger.debug("State completion check", {
343
- allStatesComplete,
344
- suspendedPaths: Array.from(suspendedPaths),
345
- runId: this.#runId
346
- });
347
- if (!allStatesComplete) {
348
- this.logger.debug("Not all states complete", {
349
- allStatesComplete,
350
- suspendedPaths: Array.from(suspendedPaths),
351
- runId: this.#runId
352
- });
353
- return;
354
- }
355
- try {
356
- this.logger.debug("All states complete", { runId: this.#runId });
357
- await this.#workflowInstance.persistWorkflowSnapshot();
358
- this.#cleanup();
359
- this.#executionSpan?.end();
360
- resolve({
361
- results: isResumedInitialStep ? { ...origSteps, ...state.context.steps } : state.context.steps,
362
- activePaths: getResultActivePaths(
363
- state
364
- )
365
- });
366
- } catch (error) {
367
- this.logger.debug("Failed to persist final snapshot", { error });
368
- this.#cleanup();
369
- this.#executionSpan?.end();
370
- resolve({
371
- results: isResumedInitialStep ? { ...origSteps, ...state.context.steps } : state.context.steps,
372
- activePaths: getResultActivePaths(
373
- state
374
- )
375
- });
376
- }
377
- });
378
- });
379
- }
380
- #cleanup() {
381
- if (this.#actor) {
382
- this.#actor.stop();
383
- this.#actor = null;
384
- }
385
- this.removeAllListeners();
386
- }
387
- #makeDelayMap() {
388
- const delayMap = {};
389
- Object.keys(this.#steps).forEach((stepId) => {
390
- delayMap[stepId] = this.#steps[stepId]?.retryConfig?.delay || this.#retryConfig?.delay || 1e3;
391
- });
392
- return delayMap;
393
- }
394
- #getDefaultActions() {
395
- return {
396
- updateStepResult: assign({
397
- steps: ({ context, event }) => {
398
- if (!isTransitionEvent(event)) return context.steps;
399
- const { stepId, result } = event.output;
400
- return {
401
- ...context.steps,
402
- [stepId]: {
403
- status: "success",
404
- output: result
405
- }
406
- };
407
- }
408
- }),
409
- setStepError: assign({
410
- steps: ({ context, event }, params) => {
411
- if (!isErrorEvent(event)) return context.steps;
412
- const { stepId } = params;
413
- if (!stepId) return context.steps;
414
- return {
415
- ...context.steps,
416
- [stepId]: {
417
- status: "failed",
418
- error: event.error.message
419
- }
420
- };
421
- }
422
- }),
423
- notifyStepCompletion: async (_, params) => {
424
- const { stepId } = params;
425
- this.logger.debug(`Step ${stepId} completed`);
426
- },
427
- snapshotStep: assign({
428
- _snapshot: ({}, params) => {
429
- const { stepId } = params;
430
- return { stepId };
431
- }
432
- }),
433
- persistSnapshot: async ({ context }) => {
434
- if (context._snapshot) {
435
- await this.#workflowInstance.persistWorkflowSnapshot();
436
- }
437
- return;
438
- },
439
- decrementAttemptCount: assign({
440
- attempts: ({ context, event }, params) => {
441
- if (!isTransitionEvent(event)) return context.attempts;
442
- const { stepId } = params;
443
- const attemptCount = context.attempts[stepId];
444
- if (attemptCount === void 0) return context.attempts;
445
- return { ...context.attempts, [stepId]: attemptCount - 1 };
446
- }
447
- })
448
- };
449
- }
450
- #getDefaultActors() {
451
- return {
452
- resolverFunction: fromPromise(async ({ input }) => {
453
- const { stepNode, context } = input;
454
- const attemptCount = context.attempts[stepNode.step.id];
455
- const resolvedData = this.#resolveVariables({
456
- stepConfig: stepNode.config,
457
- context,
458
- stepId: stepNode.step.id
459
- });
460
- this.logger.debug(`Resolved variables for ${stepNode.step.id}`, {
461
- resolvedData,
462
- runId: this.#runId
463
- });
464
- const logger = this.logger;
465
- let mastraProxy = void 0;
466
- if (this.#mastra) {
467
- mastraProxy = createMastraProxy({ mastra: this.#mastra, logger });
468
- }
469
- let result = void 0;
470
- try {
471
- result = await stepNode.config.handler({
472
- context: {
473
- ...context,
474
- inputData: { ...context?.inputData || {}, ...resolvedData },
475
- getStepResult: (stepId) => {
476
- const resolvedStepId = typeof stepId === "string" ? stepId : stepId.id;
477
- if (resolvedStepId === "trigger") {
478
- return context.triggerData;
479
- }
480
- const result2 = context.steps[resolvedStepId];
481
- if (result2 && result2.status === "success") {
482
- return result2.output;
483
- }
484
- return void 0;
485
- }
486
- },
487
- emit: (event, ...args) => {
488
- this.emit(event, ...args);
489
- },
490
- suspend: async (payload, softSuspend) => {
491
- await this.#workflowInstance.suspend(stepNode.step.id, this);
492
- if (this.#actor) {
493
- context.steps[stepNode.step.id] = {
494
- status: "suspended",
495
- suspendPayload: payload,
496
- output: softSuspend
497
- };
498
- this.logger.debug(`Sending SUSPENDED event for step ${stepNode.step.id}`);
499
- this.#actor?.send({
500
- type: "SUSPENDED",
501
- suspendPayload: payload,
502
- stepId: stepNode.step.id,
503
- softSuspend
504
- });
505
- } else {
506
- this.logger.debug(`Actor not available for step ${stepNode.step.id}`);
507
- }
508
- },
509
- runId: this.#runId,
510
- mastra: mastraProxy
511
- });
512
- } catch (error) {
513
- this.logger.debug(`Step ${stepNode.step.id} failed`, {
514
- stepId: stepNode.step.id,
515
- error,
516
- runId: this.#runId
517
- });
518
- this.logger.debug(`Attempt count for step ${stepNode.step.id}`, {
519
- attemptCount,
520
- attempts: context.attempts,
521
- runId: this.#runId,
522
- stepId: stepNode.step.id
523
- });
524
- if (!attemptCount || attemptCount < 0) {
525
- return {
526
- type: "STEP_FAILED",
527
- error: error instanceof Error ? error.message : `Step:${stepNode.step.id} failed with error: ${error}`,
528
- stepId: stepNode.step.id
529
- };
530
- }
531
- return { type: "STEP_WAITING", stepId: stepNode.step.id };
532
- }
533
- this.logger.debug(`Step ${stepNode.step.id} result`, {
534
- stepId: stepNode.step.id,
535
- result,
536
- runId: this.#runId
537
- });
538
- return {
539
- type: "STEP_SUCCESS",
540
- result,
541
- stepId: stepNode.step.id
542
- };
543
- }),
544
- conditionCheck: fromPromise(async ({ input }) => {
545
- const { context, stepNode } = input;
546
- const stepConfig = stepNode.config;
547
- this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
548
- stepId: stepNode.step.id,
549
- runId: this.#runId
550
- });
551
- if (!stepConfig?.when) {
552
- return { type: "CONDITIONS_MET" };
553
- }
554
- this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
555
- stepId: stepNode.step.id,
556
- runId: this.#runId
557
- });
558
- if (typeof stepConfig?.when === "function") {
559
- let conditionMet = await stepConfig.when({
560
- context: {
561
- ...context,
562
- getStepResult: (stepId) => {
563
- const resolvedStepId = typeof stepId === "string" ? stepId : stepId.id;
564
- if (resolvedStepId === "trigger") {
565
- return context.triggerData;
566
- }
567
- const result = context.steps[resolvedStepId];
568
- if (result && result.status === "success") {
569
- return result.output;
570
- }
571
- return void 0;
572
- }
573
- },
574
- mastra: this.#mastra
575
- });
576
- if (conditionMet === "abort" /* ABORT */) {
577
- conditionMet = false;
578
- } else if (conditionMet === "continue_failed" /* CONTINUE_FAILED */) {
579
- return { type: "CONDITIONS_SKIP_TO_COMPLETED" };
580
- } else if (conditionMet === "limbo" /* LIMBO */) {
581
- return { type: "CONDITIONS_LIMBO" };
582
- } else if (conditionMet) {
583
- this.logger.debug(`Condition met for step ${stepNode.step.id}`, {
584
- stepId: stepNode.step.id,
585
- runId: this.#runId
586
- });
587
- return { type: "CONDITIONS_MET" };
588
- }
589
- return this.#workflowInstance.hasSubscribers(stepNode.step.id) ? { type: "CONDITIONS_SKIPPED" } : { type: "CONDITIONS_LIMBO" };
590
- } else {
591
- const conditionMet = this.#evaluateCondition(stepConfig.when, context);
592
- if (!conditionMet) {
593
- return {
594
- type: "CONDITION_FAILED",
595
- error: `Step:${stepNode.step.id} condition check failed`
596
- };
597
- }
598
- }
599
- return { type: "CONDITIONS_MET" };
600
- }),
601
- spawnSubscriberFunction: fromPromise(
602
- async ({
603
- input
604
- }) => {
605
- const { parentStepId, context } = input;
606
- const result = await this.#workflowInstance.runMachine(parentStepId, context);
607
- return Promise.resolve({
608
- steps: result.reduce((acc, r) => {
609
- return { ...acc, ...r?.results };
610
- }, {})
611
- });
612
- }
613
- )
614
- };
615
- }
616
- #resolveVariables({
617
- stepConfig,
618
- context,
619
- stepId
620
- }) {
621
- this.logger.debug(`Resolving variables for step ${stepId}`, {
622
- stepId,
623
- runId: this.#runId
624
- });
625
- const resolvedData = {};
626
- for (const [key, variable] of Object.entries(stepConfig.data)) {
627
- const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id]);
628
- this.logger.debug(
629
- `Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id}`,
630
- {
631
- sourceData,
632
- path: variable.path,
633
- runId: this.#runId
634
- }
635
- );
636
- if (!sourceData && variable.step !== "trigger") {
637
- resolvedData[key] = void 0;
638
- continue;
639
- }
640
- const value = variable.path === "" || variable.path === "." ? sourceData : get(sourceData, variable.path);
641
- this.logger.debug(`Resolved variable ${key}`, {
642
- value,
643
- runId: this.#runId
644
- });
645
- resolvedData[key] = value;
646
- }
647
- return resolvedData;
648
- }
649
- initializeMachine() {
650
- const machine = setup({
651
- types: {},
652
- delays: this.#makeDelayMap(),
653
- actions: this.#getDefaultActions(),
654
- actors: this.#getDefaultActors()
655
- }).createMachine({
656
- id: this.name,
657
- type: "parallel",
658
- context: ({ input }) => ({
659
- ...input
660
- }),
661
- states: this.#buildStateHierarchy(this.#stepGraph)
662
- });
663
- this.#machine = machine;
664
- return machine;
665
- }
666
- #buildStateHierarchy(stepGraph) {
667
- const states = {};
668
- stepGraph.initial.forEach((stepNode) => {
669
- const nextSteps = [...stepGraph[stepNode.step.id] || []];
670
- states[stepNode.step.id] = {
671
- ...this.#buildBaseState(stepNode, nextSteps)
672
- };
673
- });
674
- return states;
675
- }
676
- #buildBaseState(stepNode, nextSteps = []) {
677
- const nextStep = nextSteps.shift();
678
- return {
679
- initial: "pending",
680
- on: {
681
- RESET_TO_PENDING: {
682
- target: ".pending"
683
- // Note the dot to target child state
684
- }
685
- },
686
- states: {
687
- pending: {
688
- entry: () => {
689
- this.logger.debug(`Step ${stepNode.step.id} pending`, {
690
- stepId: stepNode.step.id,
691
- runId: this.#runId
692
- });
693
- },
694
- exit: () => {
695
- this.logger.debug(`Step ${stepNode.step.id} finished pending`, {
696
- stepId: stepNode.step.id,
697
- runId: this.#runId
698
- });
699
- },
700
- invoke: {
701
- src: "conditionCheck",
702
- input: ({ context }) => {
703
- return {
704
- context,
705
- stepNode
706
- };
707
- },
708
- onDone: [
709
- {
710
- guard: ({ event }) => {
711
- return event.output.type === "SUSPENDED";
712
- },
713
- target: "suspended",
714
- actions: [
715
- assign({
716
- steps: ({ context, event }) => {
717
- if (event.output.type !== "SUSPENDED") return context.steps;
718
- if (event.output.softSuspend) {
719
- return {
720
- ...context.steps,
721
- [stepNode.step.id]: {
722
- status: "suspended",
723
- ...context.steps?.[stepNode.step.id] || {},
724
- output: event.output.softSuspend
725
- }
726
- };
727
- }
728
- return {
729
- ...context.steps,
730
- [stepNode.step.id]: {
731
- status: "suspended",
732
- ...context.steps?.[stepNode.step.id] || {}
733
- }
734
- };
735
- },
736
- attempts: ({ context, event }) => {
737
- if (event.output.type !== "SUSPENDED") return context.attempts;
738
- return { ...context.attempts, [stepNode.step.id]: stepNode.step.retryConfig?.attempts || 0 };
739
- }
740
- })
741
- ]
742
- },
743
- {
744
- guard: ({ event }) => {
745
- return event.output.type === "WAITING";
746
- },
747
- target: "waiting",
748
- actions: [
749
- { type: "decrementAttemptCount", params: { stepId: stepNode.step.id } },
750
- assign({
751
- steps: ({ context, event }) => {
752
- if (event.output.type !== "WAITING") return context.steps;
753
- return {
754
- ...context.steps,
755
- [stepNode.step.id]: {
756
- status: "waiting"
757
- }
758
- };
759
- }
760
- })
761
- ]
762
- },
763
- {
764
- guard: ({ event }) => {
765
- return event.output.type === "CONDITIONS_MET";
766
- },
767
- target: "executing"
768
- },
769
- {
770
- guard: ({ event }) => {
771
- return event.output.type === "CONDITIONS_SKIP_TO_COMPLETED";
772
- },
773
- target: "completed"
774
- },
775
- {
776
- guard: ({ event }) => {
777
- return event.output.type === "CONDITIONS_SKIPPED";
778
- },
779
- actions: assign({
780
- steps: ({ context }) => {
781
- const newStep = {
782
- ...context.steps,
783
- [stepNode.step.id]: {
784
- status: "skipped"
785
- }
786
- };
787
- this.logger.debug(`Step ${stepNode.step.id} skipped`, {
788
- stepId: stepNode.step.id,
789
- runId: this.#runId
790
- });
791
- return newStep;
792
- }
793
- }),
794
- target: "runningSubscribers"
795
- },
796
- {
797
- guard: ({ event }) => {
798
- return event.output.type === "CONDITIONS_LIMBO";
799
- },
800
- target: "limbo",
801
- actions: assign({
802
- steps: ({ context }) => {
803
- const newStep = {
804
- ...context.steps,
805
- [stepNode.step.id]: {
806
- status: "skipped"
807
- }
808
- };
809
- this.logger.debug(`Step ${stepNode.step.id} skipped`, {
810
- stepId: stepNode.step.id,
811
- runId: this.#runId
812
- });
813
- return newStep;
814
- }
815
- })
816
- },
817
- {
818
- guard: ({ event }) => {
819
- return event.output.type === "CONDITION_FAILED";
820
- },
821
- target: "failed",
822
- actions: assign({
823
- steps: ({ context, event }) => {
824
- if (event.output.type !== "CONDITION_FAILED") return context.steps;
825
- this.logger.debug(`Workflow condition check failed`, {
826
- error: event.output.error,
827
- stepId: stepNode.step.id
828
- });
829
- return {
830
- ...context.steps,
831
- [stepNode.step.id]: {
832
- status: "failed",
833
- error: event.output.error
834
- }
835
- };
836
- }
837
- })
838
- }
839
- ]
840
- }
841
- },
842
- waiting: {
843
- entry: () => {
844
- this.logger.debug(`Step ${stepNode.step.id} waiting`, {
845
- stepId: stepNode.step.id,
846
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
847
- runId: this.#runId
848
- });
849
- },
850
- exit: () => {
851
- this.logger.debug(`Step ${stepNode.step.id} finished waiting`, {
852
- stepId: stepNode.step.id,
853
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
854
- runId: this.#runId
855
- });
856
- },
857
- after: {
858
- [stepNode.step.id]: {
859
- target: "pending"
860
- }
861
- }
862
- },
863
- limbo: {
864
- // no target, will stay in limbo indefinitely
865
- entry: () => {
866
- this.logger.debug(`Step ${stepNode.step.id} limbo`, {
867
- stepId: stepNode.step.id,
868
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
869
- runId: this.#runId
870
- });
871
- },
872
- exit: () => {
873
- this.logger.debug(`Step ${stepNode.step.id} finished limbo`, {
874
- stepId: stepNode.step.id,
875
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
876
- runId: this.#runId
877
- });
878
- }
879
- },
880
- suspended: {
881
- type: "final",
882
- entry: [
883
- () => {
884
- this.logger.debug(`Step ${stepNode.step.id} suspended`, {
885
- stepId: stepNode.step.id,
886
- runId: this.#runId
887
- });
888
- },
889
- assign({
890
- steps: ({ context, event }) => {
891
- return {
892
- ...context.steps,
893
- [stepNode.step.id]: {
894
- ...context?.steps?.[stepNode.step.id] || {},
895
- status: "suspended",
896
- suspendPayload: event.type === "SUSPENDED" ? event.suspendPayload : void 0,
897
- output: event.type === "SUSPENDED" ? event.softSuspend : void 0
898
- }
899
- };
900
- }
901
- })
902
- ]
903
- },
904
- executing: {
905
- entry: () => {
906
- this.logger.debug(`Step ${stepNode.step.id} executing`, {
907
- stepId: stepNode.step.id,
908
- runId: this.#runId
909
- });
910
- },
911
- on: {
912
- SUSPENDED: {
913
- target: "suspended",
914
- actions: [
915
- assign({
916
- steps: ({ context, event }) => {
917
- return {
918
- ...context.steps,
919
- [stepNode.step.id]: {
920
- status: "suspended",
921
- suspendPayload: event.type === "SUSPENDED" ? event.suspendPayload : void 0,
922
- output: event.type === "SUSPENDED" ? event.softSuspend : void 0
923
- }
924
- };
925
- }
926
- })
927
- ]
928
- }
929
- },
930
- invoke: {
931
- src: "resolverFunction",
932
- input: ({ context }) => ({
933
- context,
934
- stepNode
935
- }),
936
- onDone: [
937
- {
938
- guard: ({ event }) => {
939
- return event.output.type === "STEP_FAILED";
940
- },
941
- target: "failed",
942
- actions: assign({
943
- steps: ({ context, event }) => {
944
- if (event.output.type !== "STEP_FAILED") return context.steps;
945
- const newStep = {
946
- ...context.steps,
947
- [stepNode.step.id]: {
948
- status: "failed",
949
- error: event.output.error
950
- }
951
- };
952
- this.logger.debug(`Step ${stepNode.step.id} failed`, {
953
- error: event.output.error,
954
- stepId: stepNode.step.id
955
- });
956
- return newStep;
957
- }
958
- })
959
- },
960
- {
961
- guard: ({ event }) => {
962
- return event.output.type === "STEP_SUCCESS";
963
- },
964
- actions: [
965
- ({ event }) => {
966
- this.logger.debug(`Step ${stepNode.step.id} finished executing`, {
967
- stepId: stepNode.step.id,
968
- output: event.output,
969
- runId: this.#runId
970
- });
971
- },
972
- { type: "updateStepResult", params: { stepId: stepNode.step.id } },
973
- { type: "spawnSubscribers", params: { stepId: stepNode.step.id } }
974
- ],
975
- target: "runningSubscribers"
976
- },
977
- {
978
- guard: ({ event }) => {
979
- return event.output.type === "STEP_WAITING";
980
- },
981
- target: "waiting",
982
- actions: [
983
- { type: "decrementAttemptCount", params: { stepId: stepNode.step.id } },
984
- assign({
985
- steps: ({ context, event }) => {
986
- if (event.output.type !== "STEP_WAITING") return context.steps;
987
- return {
988
- ...context.steps,
989
- [stepNode.step.id]: {
990
- status: "waiting"
991
- }
992
- };
993
- }
994
- })
995
- ]
996
- }
997
- ],
998
- onError: {
999
- target: "failed",
1000
- actions: [{ type: "setStepError", params: { stepId: stepNode.step.id } }]
1001
- }
1002
- }
1003
- },
1004
- runningSubscribers: {
1005
- entry: () => {
1006
- this.logger.debug(`Step ${stepNode.step.id} running subscribers`, {
1007
- stepId: stepNode.step.id,
1008
- runId: this.#runId
1009
- });
1010
- },
1011
- exit: () => {
1012
- this.logger.debug(`Step ${stepNode.step.id} finished running subscribers`, {
1013
- stepId: stepNode.step.id,
1014
- runId: this.#runId
1015
- });
1016
- },
1017
- invoke: {
1018
- src: "spawnSubscriberFunction",
1019
- input: ({ context }) => ({
1020
- parentStepId: stepNode.step.id,
1021
- context
1022
- }),
1023
- onDone: {
1024
- target: nextStep ? nextStep.step.id : "completed",
1025
- actions: [
1026
- assign({
1027
- steps: ({ context, event }) => ({
1028
- ...context.steps,
1029
- ...event.output.steps
1030
- })
1031
- }),
1032
- () => this.logger.debug(`Subscriber execution completed`, { stepId: stepNode.step.id })
1033
- ]
1034
- },
1035
- onError: {
1036
- target: nextStep ? nextStep.step.id : "completed",
1037
- actions: ({ event }) => {
1038
- this.logger.debug(`Subscriber execution failed`, {
1039
- error: event.error,
1040
- stepId: stepNode.step.id
1041
- });
1042
- }
1043
- }
1044
- }
1045
- },
1046
- completed: {
1047
- type: "final",
1048
- entry: [
1049
- { type: "notifyStepCompletion", params: { stepId: stepNode.step.id } },
1050
- { type: "snapshotStep", params: { stepId: stepNode.step.id } },
1051
- { type: "persistSnapshot" }
1052
- ]
1053
- },
1054
- failed: {
1055
- type: "final",
1056
- entry: [
1057
- { type: "notifyStepCompletion", params: { stepId: stepNode.step.id } },
1058
- { type: "snapshotStep", params: { stepId: stepNode.step.id } },
1059
- { type: "persistSnapshot" }
1060
- ]
1061
- },
1062
- // build chain of next steps recursively
1063
- ...nextStep ? { [nextStep.step.id]: { ...this.#buildBaseState(nextStep, nextSteps) } } : {}
1064
- }
1065
- };
1066
- }
1067
- #evaluateCondition(condition, context) {
1068
- let andBranchResult = true;
1069
- let baseResult = true;
1070
- let orBranchResult = true;
1071
- const simpleCondition = Object.entries(condition).find(([key]) => key.includes("."));
1072
- if (simpleCondition) {
1073
- const [key, queryValue] = simpleCondition;
1074
- const [stepId, ...pathParts] = key.split(".");
1075
- const path = pathParts.join(".");
1076
- const sourceData = stepId === "trigger" ? context.triggerData : getStepResult(context.steps[stepId]);
1077
- this.logger.debug(`Got condition data from step ${stepId}`, {
1078
- stepId,
1079
- sourceData,
1080
- runId: this.#runId
1081
- });
1082
- if (!sourceData) {
1083
- return false;
1084
- }
1085
- let value = get(sourceData, path);
1086
- if (stepId !== "trigger" && path === "status" && !value) {
1087
- value = "success";
1088
- }
1089
- if (typeof queryValue === "object" && queryValue !== null) {
1090
- baseResult = sift(queryValue)(value);
1091
- } else {
1092
- baseResult = value === queryValue;
1093
- }
1094
- }
1095
- if ("ref" in condition) {
1096
- const { ref, query } = condition;
1097
- const sourceData = ref.step === "trigger" ? context.triggerData : getStepResult(context.steps[ref.step.id]);
1098
- this.logger.debug(`Got condition data from ${ref.step === "trigger" ? "trigger" : ref.step.id}`, {
1099
- sourceData,
1100
- runId: this.#runId
1101
- });
1102
- if (!sourceData) {
1103
- return false;
1104
- }
1105
- let value = get(sourceData, ref.path);
1106
- if (ref.step !== "trigger" && ref.path === "status" && !value) {
1107
- value = "success";
1108
- }
1109
- baseResult = sift(query)(value);
1110
- }
1111
- if ("and" in condition) {
1112
- andBranchResult = condition.and.every((cond) => this.#evaluateCondition(cond, context));
1113
- this.logger.debug(`Evaluated AND condition`, {
1114
- andBranchResult,
1115
- runId: this.#runId
1116
- });
1117
- }
1118
- if ("or" in condition) {
1119
- orBranchResult = condition.or.some((cond) => this.#evaluateCondition(cond, context));
1120
- this.logger.debug(`Evaluated OR condition`, {
1121
- orBranchResult,
1122
- runId: this.#runId
1123
- });
1124
- }
1125
- if ("not" in condition) {
1126
- baseResult = !this.#evaluateCondition(condition.not, context);
1127
- this.logger.debug(`Evaluated NOT condition`, {
1128
- baseResult,
1129
- runId: this.#runId
1130
- });
1131
- }
1132
- const finalResult = baseResult && andBranchResult && orBranchResult;
1133
- this.logger.debug(`Evaluated condition`, {
1134
- finalResult,
1135
- runId: this.#runId
1136
- });
1137
- return finalResult;
1138
- }
1139
- getSnapshot() {
1140
- const snapshot = this.#actor?.getSnapshot();
1141
- return snapshot;
1142
- }
1143
- };
1144
-
1145
- // src/workflows/workflow-instance.ts
1146
- var WorkflowInstance = class {
1147
- name;
1148
- #mastra;
1149
- #machines = {};
1150
- logger;
1151
- #steps = {};
1152
- #stepGraph;
1153
- #stepSubscriberGraph = {};
1154
- #retryConfig;
1155
- events;
1156
- #runId;
1157
- #state = null;
1158
- #executionSpan;
1159
- #onStepTransition = /* @__PURE__ */ new Set();
1160
- #onFinish;
1161
- #resultMapping;
1162
- // indexed by stepId
1163
- #suspendedMachines = {};
1164
- // {step1&&step2: {step1: true, step2: true}}
1165
- #compoundDependencies = {};
1166
- constructor({
1167
- name,
1168
- logger,
1169
- steps,
1170
- runId,
1171
- retryConfig,
1172
- mastra,
1173
- stepGraph,
1174
- stepSubscriberGraph,
1175
- onFinish,
1176
- onStepTransition,
1177
- resultMapping,
1178
- events
1179
- }) {
1180
- this.name = name;
1181
- this.logger = logger;
1182
- this.#steps = steps;
1183
- this.#stepGraph = stepGraph;
1184
- this.#stepSubscriberGraph = stepSubscriberGraph;
1185
- this.#retryConfig = retryConfig;
1186
- this.#mastra = mastra;
1187
- this.#runId = runId ?? crypto.randomUUID();
1188
- this.#onFinish = onFinish;
1189
- this.#resultMapping = resultMapping;
1190
- this.events = events;
1191
- onStepTransition?.forEach((handler) => this.#onStepTransition.add(handler));
1192
- this.#initializeCompoundDependencies();
1193
- }
1194
- setState(state) {
1195
- this.#state = state;
1196
- }
1197
- get runId() {
1198
- return this.#runId;
1199
- }
1200
- get executionSpan() {
1201
- return this.#executionSpan;
1202
- }
1203
- watch(onTransition) {
1204
- this.#onStepTransition.add(onTransition);
1205
- return () => {
1206
- this.#onStepTransition.delete(onTransition);
1207
- };
1208
- }
1209
- async start({ triggerData } = {}) {
1210
- const results = await this.execute({ triggerData });
1211
- if (this.#onFinish) {
1212
- this.#onFinish();
1213
- }
1214
- return {
1215
- ...results,
1216
- runId: this.runId
1217
- };
1218
- }
1219
- isCompoundDependencyMet(stepKey) {
1220
- if (!this.#isCompoundKey(stepKey)) return true;
1221
- const dependencies = this.#compoundDependencies[stepKey];
1222
- return dependencies ? Object.values(dependencies).every((status) => status === true) : true;
1223
- }
1224
- async execute({
1225
- triggerData,
1226
- snapshot,
1227
- stepId,
1228
- resumeData
1229
- } = {}) {
1230
- this.#executionSpan = this.#mastra?.getTelemetry()?.tracer.startSpan(`workflow.${this.name}.execute`, {
1231
- attributes: { componentName: this.name, runId: this.runId }
1232
- });
1233
- let machineInput = {
1234
- // Maintain the original step results and their output
1235
- steps: {},
1236
- triggerData: triggerData || {},
1237
- attempts: Object.keys(this.#steps).reduce(
1238
- (acc, stepKey) => {
1239
- acc[stepKey] = this.#steps[stepKey]?.retryConfig?.attempts || this.#retryConfig?.attempts || 0;
1240
- return acc;
1241
- },
1242
- {}
1243
- )
1244
- };
1245
- let stepGraph = this.#stepGraph;
1246
- let startStepId = "trigger";
1247
- if (snapshot) {
1248
- const runState = snapshot;
1249
- if (stepId && runState?.suspendedSteps?.[stepId]) {
1250
- startStepId = runState.suspendedSteps[stepId];
1251
- stepGraph = this.#stepSubscriberGraph[startStepId] ?? this.#stepGraph;
1252
- machineInput = runState.context;
1253
- }
1254
- }
1255
- const defaultMachine = new Machine({
1256
- logger: this.logger,
1257
- mastra: this.#mastra,
1258
- workflowInstance: this,
1259
- name: this.name,
1260
- runId: this.runId,
1261
- steps: this.#steps,
1262
- stepGraph,
1263
- executionSpan: this.#executionSpan,
1264
- startStepId,
1265
- retryConfig: this.#retryConfig
1266
- });
1267
- this.#machines[startStepId] = defaultMachine;
1268
- const stateUpdateHandler = (startStepId2, state, context) => {
1269
- if (startStepId2 === "trigger") {
1270
- this.#state = state;
1271
- } else {
1272
- this.#state = mergeChildValue(startStepId2, this.#state, state);
1273
- }
1274
- const now = Date.now();
1275
- if (this.#onStepTransition) {
1276
- this.#onStepTransition.forEach((onTransition) => {
1277
- void onTransition({
1278
- runId: this.#runId,
1279
- value: this.#state,
1280
- context,
1281
- activePaths: getActivePathsAndStatus(this.#state),
1282
- timestamp: now
1283
- });
1284
- });
1285
- }
1286
- };
1287
- defaultMachine.on("state-update", stateUpdateHandler);
1288
- const { results, activePaths } = await defaultMachine.execute({
1289
- snapshot,
1290
- stepId,
1291
- input: machineInput,
1292
- resumeData
1293
- });
1294
- await this.persistWorkflowSnapshot();
1295
- const result = { results, activePaths };
1296
- if (this.#resultMapping) {
1297
- result.result = resolveVariables({
1298
- runId: this.#runId,
1299
- logger: this.logger,
1300
- variables: this.#resultMapping,
1301
- context: {
1302
- steps: results,
1303
- triggerData}
1304
- });
1305
- }
1306
- return result;
1307
- }
1308
- hasSubscribers(stepId) {
1309
- return Object.keys(this.#stepSubscriberGraph).some((key) => key.split("&&").includes(stepId));
1310
- }
1311
- async runMachine(parentStepId, input) {
1312
- const stepStatus = input.steps[parentStepId]?.status;
1313
- const subscriberKeys = Object.keys(this.#stepSubscriberGraph).filter((key) => key.split("&&").includes(parentStepId));
1314
- subscriberKeys.forEach((key) => {
1315
- if (["success", "failure", "skipped"].includes(stepStatus) && this.#isCompoundKey(key)) {
1316
- this.#compoundDependencies[key][parentStepId] = true;
1317
- }
1318
- });
1319
- const stateUpdateHandler = (startStepId, state, context) => {
1320
- if (startStepId === "trigger") {
1321
- this.#state = state;
1322
- } else {
1323
- this.#state = mergeChildValue(startStepId, this.#state, state);
1324
- }
1325
- const now = Date.now();
1326
- if (this.#onStepTransition) {
1327
- this.#onStepTransition.forEach((onTransition) => {
1328
- void onTransition({
1329
- runId: this.#runId,
1330
- value: this.#state,
1331
- context,
1332
- activePaths: getActivePathsAndStatus(this.#state),
1333
- timestamp: now
1334
- });
1335
- });
1336
- }
1337
- };
1338
- const results = await Promise.all(
1339
- subscriberKeys.map(async (key) => {
1340
- if (!this.#stepSubscriberGraph[key] || !this.isCompoundDependencyMet(key)) {
1341
- return;
1342
- }
1343
- this.#initializeCompoundDependencies();
1344
- const machine = new Machine({
1345
- logger: this.logger,
1346
- mastra: this.#mastra,
1347
- workflowInstance: this,
1348
- name: parentStepId === "trigger" ? this.name : `${this.name}-${parentStepId}`,
1349
- runId: this.runId,
1350
- steps: this.#steps,
1351
- stepGraph: this.#stepSubscriberGraph[key],
1352
- executionSpan: this.#executionSpan,
1353
- startStepId: parentStepId
1354
- });
1355
- machine.on("state-update", stateUpdateHandler);
1356
- this.#machines[parentStepId] = machine;
1357
- return machine.execute({ input });
1358
- })
1359
- );
1360
- return results;
1361
- }
1362
- async suspend(stepId, machine) {
1363
- this.#suspendedMachines[stepId] = machine;
1364
- }
1365
- /**
1366
- * Persists the workflow state to the database
1367
- */
1368
- async persistWorkflowSnapshot() {
1369
- const existingSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
1370
- workflowName: this.name,
1371
- runId: this.#runId
1372
- });
1373
- const machineSnapshots = {};
1374
- for (const [stepId, machine] of Object.entries(this.#machines)) {
1375
- const machineSnapshot = machine?.getSnapshot();
1376
- if (machineSnapshot) {
1377
- machineSnapshots[stepId] = { ...machineSnapshot };
1378
- }
1379
- }
1380
- let snapshot = machineSnapshots["trigger"];
1381
- delete machineSnapshots["trigger"];
1382
- const suspendedSteps = Object.entries(this.#suspendedMachines).reduce(
1383
- (acc, [stepId, machine]) => {
1384
- acc[stepId] = machine.startStepId;
1385
- return acc;
1386
- },
1387
- {}
1388
- );
1389
- if (!snapshot && existingSnapshot) {
1390
- existingSnapshot.childStates = { ...existingSnapshot.childStates, ...machineSnapshots };
1391
- existingSnapshot.suspendedSteps = { ...existingSnapshot.suspendedSteps, ...suspendedSteps };
1392
- await this.#mastra?.storage?.persistWorkflowSnapshot({
1393
- workflowName: this.name,
1394
- runId: this.#runId,
1395
- snapshot: existingSnapshot
1396
- });
1397
- return;
1398
- } else if (snapshot && !existingSnapshot) {
1399
- snapshot.suspendedSteps = suspendedSteps;
1400
- snapshot.childStates = { ...machineSnapshots };
1401
- await this.#mastra?.storage?.persistWorkflowSnapshot({
1402
- workflowName: this.name,
1403
- runId: this.#runId,
1404
- snapshot
1405
- });
1406
- return;
1407
- } else if (!snapshot) {
1408
- this.logger.debug("Snapshot cannot be persisted. No snapshot received.", { runId: this.#runId });
1409
- return;
1410
- }
1411
- snapshot.suspendedSteps = { ...existingSnapshot.suspendedSteps, ...suspendedSteps };
1412
- if (!existingSnapshot || snapshot === existingSnapshot) {
1413
- await this.#mastra?.storage?.persistWorkflowSnapshot({
1414
- workflowName: this.name,
1415
- runId: this.#runId,
1416
- snapshot
1417
- });
1418
- return;
1419
- }
1420
- if (existingSnapshot?.childStates) {
1421
- snapshot.childStates = { ...existingSnapshot.childStates, ...machineSnapshots };
1422
- } else {
1423
- snapshot.childStates = machineSnapshots;
1424
- }
1425
- await this.#mastra?.storage?.persistWorkflowSnapshot({
1426
- workflowName: this.name,
1427
- runId: this.#runId,
1428
- snapshot
1429
- });
1430
- }
1431
- async getState() {
1432
- const storedSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
1433
- workflowName: this.name,
1434
- runId: this.runId
1435
- });
1436
- const prevSnapshot = storedSnapshot ? {
1437
- trigger: storedSnapshot,
1438
- ...Object.entries(storedSnapshot?.childStates ?? {}).reduce(
1439
- (acc, [stepId, snapshot2]) => ({ ...acc, [stepId]: snapshot2 }),
1440
- {}
1441
- )
1442
- } : {};
1443
- const currentSnapshot = Object.entries(this.#machines).reduce(
1444
- (acc, [stepId, machine]) => {
1445
- const snapshot2 = machine.getSnapshot();
1446
- if (!snapshot2) {
1447
- return acc;
1448
- }
1449
- return {
1450
- ...acc,
1451
- [stepId]: snapshot2
1452
- };
1453
- },
1454
- {}
1455
- );
1456
- Object.assign(prevSnapshot, currentSnapshot);
1457
- const trigger = prevSnapshot.trigger;
1458
- delete prevSnapshot.trigger;
1459
- const snapshot = { ...trigger};
1460
- const m = getActivePathsAndStatus(prevSnapshot.value);
1461
- return {
1462
- runId: this.runId,
1463
- value: snapshot.value,
1464
- context: snapshot.context,
1465
- activePaths: m,
1466
- timestamp: Date.now()
1467
- };
1468
- }
1469
- async resumeWithEvent(eventName, data) {
1470
- const event = this.events?.[eventName];
1471
- if (!event) {
1472
- throw new Error(`Event ${eventName} not found`);
1473
- }
1474
- const results = await this.resume({ stepId: `__${eventName}_event`, context: { resumedEvent: data } });
1475
- return results;
1476
- }
1477
- async resume({ stepId, context: resumeContext }) {
1478
- await new Promise((resolve) => setTimeout(resolve, 0));
1479
- return this._resume({ stepId, context: resumeContext });
1480
- }
1481
- async #loadWorkflowSnapshot(runId) {
1482
- if (!this.#mastra?.storage) {
1483
- this.logger.debug("Snapshot cannot be loaded. Mastra engine is not initialized", { runId });
1484
- return;
1485
- }
1486
- await this.persistWorkflowSnapshot();
1487
- return this.#mastra.getStorage()?.loadWorkflowSnapshot({ runId, workflowName: this.name });
1488
- }
1489
- async _resume({ stepId, context: resumeContext }) {
1490
- const snapshot = await this.#loadWorkflowSnapshot(this.runId);
1491
- if (!snapshot) {
1492
- throw new Error(`No snapshot found for workflow run ${this.runId}`);
1493
- }
1494
- const stepParts = stepId.split(".");
1495
- const stepPath = stepParts.join(".");
1496
- if (stepParts.length > 1) {
1497
- stepId = stepParts[0] ?? stepId;
1498
- }
1499
- let parsedSnapshot;
1500
- try {
1501
- parsedSnapshot = typeof snapshot === "string" ? JSON.parse(snapshot) : snapshot;
1502
- } catch (error) {
1503
- this.logger.debug("Failed to parse workflow snapshot for resume", { error, runId: this.runId });
1504
- throw new Error("Failed to parse workflow snapshot");
1505
- }
1506
- const startStepId = parsedSnapshot.suspendedSteps?.[stepId];
1507
- if (!startStepId) {
1508
- return;
1509
- }
1510
- parsedSnapshot = startStepId === "trigger" ? parsedSnapshot : { ...parsedSnapshot?.childStates?.[startStepId], ...{ suspendedSteps: parsedSnapshot.suspendedSteps } };
1511
- if (!parsedSnapshot) {
1512
- throw new Error(`No snapshot found for step: ${stepId} starting at ${startStepId}`);
1513
- }
1514
- if (resumeContext) {
1515
- parsedSnapshot.context.steps[stepId] = {
1516
- status: "success",
1517
- output: {
1518
- ...parsedSnapshot?.context?.steps?.[stepId]?.output || {},
1519
- ...resumeContext
1520
- }
1521
- };
1522
- }
1523
- if (parsedSnapshot.children) {
1524
- Object.entries(parsedSnapshot.children).forEach(([_childId, child]) => {
1525
- if (child.snapshot?.input?.stepNode) {
1526
- const stepDef = this.#makeStepDef(child.snapshot.input.stepNode.step.id);
1527
- child.snapshot.input.stepNode.config = {
1528
- ...child.snapshot.input.stepNode.config,
1529
- ...stepDef
1530
- };
1531
- child.snapshot.input.context = parsedSnapshot.context;
1532
- }
1533
- });
1534
- }
1535
- parsedSnapshot.value = updateStepInHierarchy(parsedSnapshot.value, stepId);
1536
- if (parsedSnapshot.context?.attempts) {
1537
- parsedSnapshot.context.attempts[stepId] = this.#steps[stepId]?.retryConfig?.attempts || this.#retryConfig?.attempts || 0;
1538
- }
1539
- this.logger.debug("Resuming workflow with updated snapshot", {
1540
- updatedSnapshot: parsedSnapshot,
1541
- runId: this.runId,
1542
- stepId
1543
- });
1544
- return this.execute({
1545
- snapshot: parsedSnapshot,
1546
- stepId: stepPath,
1547
- resumeData: resumeContext
1548
- });
1549
- }
1550
- #initializeCompoundDependencies() {
1551
- Object.keys(this.#stepSubscriberGraph).forEach((stepKey) => {
1552
- if (this.#isCompoundKey(stepKey)) {
1553
- const requiredSteps = stepKey.split("&&");
1554
- this.#compoundDependencies[stepKey] = requiredSteps.reduce(
1555
- (acc, step) => {
1556
- acc[step] = false;
1557
- return acc;
1558
- },
1559
- {}
1560
- );
1561
- }
1562
- });
1563
- }
1564
- #makeStepDef(stepId) {
1565
- const executeStep = (handler2, spanName, attributes) => {
1566
- return async (data) => {
1567
- return await context.with(trace.setSpan(context.active(), this.#executionSpan), async () => {
1568
- if (this.#mastra?.getTelemetry()) {
1569
- return this.#mastra.getTelemetry()?.traceMethod(handler2, {
1570
- spanName,
1571
- attributes
1572
- })(data);
1573
- } else {
1574
- return handler2(data);
1575
- }
1576
- });
1577
- };
1578
- };
1579
- const handler = async ({ context, ...rest }) => {
1580
- const targetStep = this.#steps[stepId];
1581
- if (!targetStep) throw new Error(`Step not found`);
1582
- const { payload = {}, execute = async () => {
1583
- } } = targetStep;
1584
- const mergedData = {
1585
- ...payload,
1586
- ...context
1587
- };
1588
- const finalAction = this.#mastra?.getTelemetry() ? executeStep(execute, `workflow.${this.name}.action.${stepId}`, {
1589
- componentName: this.name,
1590
- runId: rest.runId
1591
- }) : execute;
1592
- return finalAction ? await finalAction({ context: mergedData, ...rest }) : {};
1593
- };
1594
- const finalHandler = ({ context, ...rest }) => {
1595
- if (this.#executionSpan) {
1596
- return executeStep(handler, `workflow.${this.name}.step.${stepId}`, {
1597
- componentName: this.name,
1598
- runId: rest?.runId
1599
- })({ context, ...rest });
1600
- }
1601
- return handler({ context, ...rest });
1602
- };
1603
- return {
1604
- handler: finalHandler,
1605
- data: {}
1606
- };
1607
- }
1608
- #isCompoundKey(key) {
1609
- return key.includes("&&");
1610
- }
1611
- };
1612
-
1613
- // src/workflows/workflow.ts
1614
- var Workflow = class extends MastraBase {
1615
- name;
1616
- triggerSchema;
1617
- resultSchema;
1618
- resultMapping;
1619
- events;
1620
- #retryConfig;
1621
- #mastra;
1622
- #runs = /* @__PURE__ */ new Map();
1623
- #isNested = false;
1624
- #onStepTransition = /* @__PURE__ */ new Set();
1625
- // registers stepIds on `after` calls
1626
- #afterStepStack = [];
1627
- #lastStepStack = [];
1628
- #ifStack = [];
1629
- #stepGraph = { initial: [] };
1630
- #serializedStepGraph = { initial: [] };
1631
- #stepSubscriberGraph = {};
1632
- #serializedStepSubscriberGraph = {};
1633
- #steps = {};
1634
- /**
1635
- * Creates a new Workflow instance
1636
- * @param name - Identifier for the workflow (not necessarily unique)
1637
- * @param logger - Optional logger instance
1638
- */
1639
- constructor({
1640
- name,
1641
- triggerSchema,
1642
- result,
1643
- retryConfig,
1644
- mastra,
1645
- events
1646
- }) {
1647
- super({ component: "WORKFLOW", name });
1648
- this.name = name;
1649
- this.#retryConfig = retryConfig;
1650
- this.triggerSchema = triggerSchema;
1651
- this.resultSchema = result?.schema;
1652
- this.resultMapping = result?.mapping;
1653
- this.events = events;
1654
- if (mastra) {
1655
- this.__registerPrimitives({
1656
- telemetry: mastra.getTelemetry(),
1657
- logger: mastra.getLogger()
1658
- });
1659
- this.#mastra = mastra;
1660
- }
1661
- }
1662
- step(next, config) {
1663
- if (Array.isArray(next)) {
1664
- const nextSteps = next.map((step2) => {
1665
- if (isWorkflow(step2)) {
1666
- const asStep = step2.toStep();
1667
- return asStep;
1668
- } else {
1669
- return step2;
1670
- }
1671
- });
1672
- nextSteps.forEach((step2) => this.step(step2, config));
1673
- this.after(nextSteps);
1674
- this.step(
1675
- new Step({
1676
- id: `__after_${next.map((step2) => step2?.id ?? step2?.name).join("_")}`,
1677
- execute: async ({ context }) => {
1678
- return { success: true };
1679
- }
1680
- })
1681
- );
1682
- return this;
1683
- }
1684
- const { variables = {} } = config || {};
1685
- const requiredData = {};
1686
- for (const [key, variable] of Object.entries(variables)) {
1687
- if (variable && isVariableReference(variable)) {
1688
- requiredData[key] = variable;
1689
- }
1690
- }
1691
- const step = isWorkflow(next) ? (
1692
- // @ts-ignore
1693
- workflowToStep(next, { mastra: this.#mastra })
1694
- ) : next;
1695
- const stepKey = this.#makeStepKey(step);
1696
- const when = config?.["#internal"]?.when || config?.when;
1697
- const graphEntry = {
1698
- step,
1699
- config: {
1700
- ...this.#makeStepDef(stepKey),
1701
- ...config,
1702
- loopLabel: config?.["#internal"]?.loopLabel,
1703
- loopType: config?.["#internal"]?.loopType,
1704
- serializedWhen: typeof when === "function" ? when.toString() : when,
1705
- data: requiredData
1706
- }
1707
- };
1708
- this.#steps[stepKey] = step;
1709
- const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
1710
- const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
1711
- const serializedStepGraph = this.#serializedStepSubscriberGraph[parentStepKey || ""];
1712
- if (parentStepKey && stepGraph) {
1713
- if (!stepGraph.initial.some((step2) => step2.step.id === stepKey)) {
1714
- stepGraph.initial.push(graphEntry);
1715
- if (serializedStepGraph) serializedStepGraph.initial.push(graphEntry);
1716
- }
1717
- stepGraph[stepKey] = [];
1718
- if (serializedStepGraph) serializedStepGraph[stepKey] = [];
1719
- } else {
1720
- if (!this.#stepGraph[stepKey]) this.#stepGraph[stepKey] = [];
1721
- this.#stepGraph.initial.push(graphEntry);
1722
- this.#serializedStepGraph.initial.push(graphEntry);
1723
- }
1724
- this.#lastStepStack.push(stepKey);
1725
- return this;
1726
- }
1727
- #makeStepKey(step) {
1728
- return `${step.id ?? step.name}`;
1729
- }
1730
- then(next, config) {
1731
- if (Array.isArray(next)) {
1732
- const lastStep = this.#steps[this.#lastStepStack[this.#lastStepStack.length - 1] ?? ""];
1733
- if (!lastStep) {
1734
- throw new Error("Condition requires a step to be executed after");
1735
- }
1736
- this.after(lastStep);
1737
- const nextSteps = next.map((step2) => {
1738
- if (isWorkflow(step2)) {
1739
- return workflowToStep(step2, { mastra: this.#mastra });
1740
- }
1741
- return step2;
1742
- });
1743
- nextSteps.forEach((step2) => this.step(step2, config));
1744
- this.step(
1745
- new Step({
1746
- // @ts-ignore
1747
- id: `__after_${next.map((step2) => step2?.id ?? step2?.name).join("_")}`,
1748
- execute: async () => {
1749
- return { success: true };
1750
- }
1751
- })
1752
- );
1753
- return this;
1754
- }
1755
- const { variables = {} } = config || {};
1756
- const requiredData = {};
1757
- for (const [key, variable] of Object.entries(variables)) {
1758
- if (variable && isVariableReference(variable)) {
1759
- requiredData[key] = variable;
1760
- }
1761
- }
1762
- const lastStepKey = this.#lastStepStack[this.#lastStepStack.length - 1];
1763
- const step = isWorkflow(next) ? workflowToStep(next, { mastra: this.#mastra }) : next;
1764
- const stepKey = this.#makeStepKey(step);
1765
- const when = config?.["#internal"]?.when || config?.when;
1766
- const graphEntry = {
1767
- step,
1768
- config: {
1769
- ...this.#makeStepDef(stepKey),
1770
- ...config,
1771
- loopLabel: config?.["#internal"]?.loopLabel,
1772
- loopType: config?.["#internal"]?.loopType,
1773
- serializedWhen: typeof when === "function" ? when.toString() : when,
1774
- data: requiredData
1775
- }
1776
- };
1777
- this.#steps[stepKey] = step;
1778
- if (!lastStepKey) return this;
1779
- const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
1780
- const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
1781
- const serializedStepGraph = this.#serializedStepSubscriberGraph[parentStepKey || ""];
1782
- if (parentStepKey && stepGraph && stepGraph[lastStepKey]) {
1783
- stepGraph[lastStepKey].push(graphEntry);
1784
- if (serializedStepGraph && serializedStepGraph[lastStepKey]) serializedStepGraph[lastStepKey].push(graphEntry);
1785
- } else {
1786
- if (!this.#stepGraph[lastStepKey]) this.#stepGraph[lastStepKey] = [];
1787
- if (!this.#serializedStepGraph[lastStepKey]) this.#serializedStepGraph[lastStepKey] = [];
1788
- this.#stepGraph[lastStepKey].push(graphEntry);
1789
- this.#serializedStepGraph[lastStepKey].push(graphEntry);
1790
- }
1791
- return this;
1792
- }
1793
- loop(applyOperator, condition, fallbackStep, loopType) {
1794
- const lastStepKey = this.#lastStepStack[this.#lastStepStack.length - 1];
1795
- if (!lastStepKey) return this;
1796
- const fallbackStepKey = this.#makeStepKey(fallbackStep);
1797
- this.#steps[fallbackStepKey] = fallbackStep;
1798
- const checkStepKey = `__${fallbackStepKey}_${loopType}_loop_check`;
1799
- const checkStep = {
1800
- id: checkStepKey,
1801
- execute: async ({ context }) => {
1802
- if (typeof condition === "function") {
1803
- const result = await condition({ context });
1804
- if (loopType === "while") {
1805
- return { status: result ? "continue" : "complete" };
1806
- } else {
1807
- return { status: result ? "complete" : "continue" };
1808
- }
1809
- }
1810
- if (condition && "ref" in condition) {
1811
- const { ref, query } = condition;
1812
- const stepId = typeof ref.step === "string" ? ref.step : "id" in ref.step ? ref.step.id : null;
1813
- if (!stepId) {
1814
- return { status: "continue" };
1815
- }
1816
- const stepOutput = context.steps?.[stepId]?.output;
1817
- if (!stepOutput) {
1818
- return { status: "continue" };
1819
- }
1820
- const value = ref.path.split(".").reduce((obj, key) => obj?.[key], stepOutput);
1821
- const operator = Object.keys(query)[0];
1822
- const target = query[operator];
1823
- return applyOperator(operator, value, target);
1824
- }
1825
- return { status: "continue" };
1826
- },
1827
- outputSchema: z.object({
1828
- status: z.enum(["continue", "complete"])
1829
- })
1830
- };
1831
- this.#steps[checkStepKey] = checkStep;
1832
- const loopFinishedStepKey = `__${fallbackStepKey}_${loopType}_loop_finished`;
1833
- const loopFinishedStep = {
1834
- id: loopFinishedStepKey,
1835
- execute: async ({ context }) => {
1836
- return { success: true };
1837
- }
1838
- };
1839
- this.#steps[checkStepKey] = checkStep;
1840
- this.then(checkStep, {
1841
- "#internal": {
1842
- loopLabel: `${fallbackStepKey} ${loopType} loop check`
1843
- }
1844
- });
1845
- this.after(checkStep).step(fallbackStep, {
1846
- when: async ({ context }) => {
1847
- const checkStepResult = context.steps?.[checkStepKey];
1848
- if (checkStepResult?.status !== "success") {
1849
- return "abort" /* ABORT */;
1850
- }
1851
- const status = checkStepResult?.output?.status;
1852
- return status === "continue" ? "continue" /* CONTINUE */ : "continue_failed" /* CONTINUE_FAILED */;
1853
- },
1854
- "#internal": {
1855
- // @ts-ignore
1856
- when: condition,
1857
- loopType
1858
- }
1859
- }).then(checkStep, {
1860
- "#internal": {
1861
- loopLabel: `${fallbackStepKey} ${loopType} loop check`
1862
- }
1863
- }).step(loopFinishedStep, {
1864
- when: async ({ context }) => {
1865
- const checkStepResult = context.steps?.[checkStepKey];
1866
- if (checkStepResult?.status !== "success") {
1867
- return "continue_failed" /* CONTINUE_FAILED */;
1868
- }
1869
- const status = checkStepResult?.output?.status;
1870
- return status === "complete" ? "continue" /* CONTINUE */ : "continue_failed" /* CONTINUE_FAILED */;
1871
- },
1872
- "#internal": {
1873
- loopLabel: `${fallbackStepKey} ${loopType} loop finished`,
1874
- //@ts-ignore
1875
- loopType
1876
- }
1877
- });
1878
- return this;
1879
- }
1880
- while(condition, fallbackStep) {
1881
- const applyOperator = (operator, value, target) => {
1882
- switch (operator) {
1883
- case "$eq":
1884
- return { status: value !== target ? "complete" : "continue" };
1885
- case "$ne":
1886
- return { status: value === target ? "complete" : "continue" };
1887
- case "$gt":
1888
- return { status: value <= target ? "complete" : "continue" };
1889
- case "$gte":
1890
- return { status: value < target ? "complete" : "continue" };
1891
- case "$lt":
1892
- return { status: value >= target ? "complete" : "continue" };
1893
- case "$lte":
1894
- return { status: value > target ? "complete" : "continue" };
1895
- default:
1896
- return { status: "continue" };
1897
- }
1898
- };
1899
- return this.loop(applyOperator, condition, fallbackStep, "while");
1900
- }
1901
- until(condition, fallbackStep) {
1902
- const applyOperator = (operator, value, target) => {
1903
- switch (operator) {
1904
- case "$eq":
1905
- return { status: value === target ? "complete" : "continue" };
1906
- case "$ne":
1907
- return { status: value !== target ? "complete" : "continue" };
1908
- case "$gt":
1909
- return { status: value > target ? "complete" : "continue" };
1910
- case "$gte":
1911
- return { status: value >= target ? "complete" : "continue" };
1912
- case "$lt":
1913
- return { status: value < target ? "complete" : "continue" };
1914
- case "$lte":
1915
- return { status: value <= target ? "complete" : "continue" };
1916
- default:
1917
- return { status: "continue" };
1918
- }
1919
- };
1920
- return this.loop(applyOperator, condition, fallbackStep, "until");
1921
- }
1922
- if(condition, ifStep, elseStep) {
1923
- const lastStep = this.#steps[this.#lastStepStack[this.#lastStepStack.length - 1] ?? ""];
1924
- if (!lastStep) {
1925
- throw new Error("Condition requires a step to be executed after");
1926
- }
1927
- this.after(lastStep);
1928
- if (ifStep) {
1929
- const _ifStep = isWorkflow(ifStep) ? workflowToStep(ifStep, { mastra: this.#mastra }) : ifStep;
1930
- this.step(_ifStep, {
1931
- when: condition
1932
- });
1933
- if (elseStep) {
1934
- const _elseStep = isWorkflow(elseStep) ? workflowToStep(elseStep, { mastra: this.#mastra }) : elseStep;
1935
- this.step(_elseStep, {
1936
- when: typeof condition === "function" ? async (payload) => {
1937
- const result = await condition(payload);
1938
- return !result;
1939
- } : { not: condition }
1940
- });
1941
- this.after([_ifStep, _elseStep]);
1942
- } else {
1943
- this.after(_ifStep);
1944
- }
1945
- this.step(
1946
- new Step({
1947
- id: `${lastStep.id}_if_else`,
1948
- execute: async () => {
1949
- return { executed: true };
1950
- }
1951
- })
1952
- );
1953
- return this;
1954
- }
1955
- const ifStepKey = `__${lastStep.id}_if`;
1956
- this.step(
1957
- {
1958
- id: ifStepKey,
1959
- execute: async () => {
1960
- return { executed: true };
1961
- }
1962
- },
1963
- {
1964
- when: condition
1965
- }
1966
- );
1967
- const elseStepKey = `__${lastStep.id}_else`;
1968
- this.#ifStack.push({ condition, elseStepKey, condStep: lastStep });
1969
- return this;
1970
- }
1971
- else() {
1972
- const activeCondition = this.#ifStack.pop();
1973
- if (!activeCondition) {
1974
- throw new Error("No active condition found");
1975
- }
1976
- this.after(activeCondition.condStep).step(
1977
- {
1978
- id: activeCondition.elseStepKey,
1979
- execute: async () => {
1980
- return { executed: true };
1981
- }
1982
- },
1983
- {
1984
- when: typeof activeCondition.condition === "function" ? async (payload) => {
1985
- const result = await activeCondition.condition(payload);
1986
- return !result;
1987
- } : { not: activeCondition.condition }
1988
- }
1989
- );
1990
- return this;
1991
- }
1992
- after(steps) {
1993
- const stepsArray = Array.isArray(steps) ? steps : [steps];
1994
- const stepKeys = stepsArray.map((step) => this.#makeStepKey(step));
1995
- const compoundKey = stepKeys.join("&&");
1996
- this.#afterStepStack.push(compoundKey);
1997
- if (!this.#stepSubscriberGraph[compoundKey]) {
1998
- this.#stepSubscriberGraph[compoundKey] = { initial: [] };
1999
- this.#serializedStepSubscriberGraph[compoundKey] = { initial: [] };
2000
- }
2001
- return this;
2002
- }
2003
- afterEvent(eventName) {
2004
- const event = this.events?.[eventName];
2005
- if (!event) {
2006
- throw new Error(`Event ${eventName} not found`);
2007
- }
2008
- const lastStep = this.#steps[this.#lastStepStack[this.#lastStepStack.length - 1] ?? ""];
2009
- if (!lastStep) {
2010
- throw new Error("Condition requires a step to be executed after");
2011
- }
2012
- const eventStepKey = `__${eventName}_event`;
2013
- const eventStep = new Step({
2014
- id: eventStepKey,
2015
- execute: async ({ context, suspend }) => {
2016
- if (context.inputData?.resumedEvent) {
2017
- return { executed: true, resumedEvent: context.inputData?.resumedEvent };
2018
- }
2019
- await suspend();
2020
- return { executed: false };
2021
- }
2022
- });
2023
- this.after(lastStep).step(eventStep).after(eventStep);
2024
- return this;
2025
- }
2026
- /**
2027
- * Executes the workflow with the given trigger data
2028
- * @param triggerData - Initial data to start the workflow with
2029
- * @returns Promise resolving to workflow results or rejecting with error
2030
- * @throws Error if trigger schema validation fails
2031
- */
2032
- createRun({
2033
- runId,
2034
- events
2035
- } = {}) {
2036
- const run = new WorkflowInstance({
2037
- logger: this.logger,
2038
- name: this.name,
2039
- mastra: this.#mastra,
2040
- retryConfig: this.#retryConfig,
2041
- steps: this.#steps,
2042
- runId,
2043
- stepGraph: this.#stepGraph,
2044
- stepSubscriberGraph: this.#stepSubscriberGraph,
2045
- onStepTransition: this.#onStepTransition,
2046
- resultMapping: this.resultMapping,
2047
- onFinish: () => {
2048
- this.#runs.delete(run.runId);
2049
- },
2050
- events
2051
- });
2052
- this.#runs.set(run.runId, run);
2053
- return {
2054
- start: run.start.bind(run),
2055
- runId: run.runId,
2056
- watch: run.watch.bind(run),
2057
- resume: run.resume.bind(run),
2058
- resumeWithEvent: run.resumeWithEvent.bind(run)
2059
- };
2060
- }
2061
- /**
2062
- * Gets a workflow run instance by ID
2063
- * @param runId - ID of the run to retrieve
2064
- * @returns The workflow run instance if found, undefined otherwise
2065
- */
2066
- getRun(runId) {
2067
- return this.#runs.get(runId);
2068
- }
2069
- /**
2070
- * Rebuilds the machine with the current steps configuration and validates the workflow
2071
- *
2072
- * This is the last step of a workflow builder method chain
2073
- * @throws Error if validation fails
2074
- *
2075
- * @returns this instance for method chaining
2076
- */
2077
- commit() {
2078
- return this;
2079
- }
2080
- // record all object paths that leads to a suspended state
2081
- #getSuspendedPaths({
2082
- value,
2083
- path,
2084
- suspendedPaths
2085
- }) {
2086
- if (typeof value === "string") {
2087
- if (value === "suspended") {
2088
- suspendedPaths.add(path);
2089
- }
2090
- } else {
2091
- Object.keys(value).forEach(
2092
- (key) => this.#getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
2093
- );
2094
- }
2095
- }
2096
- async #loadWorkflowSnapshot(runId) {
2097
- if (!this.#mastra?.storage) {
2098
- this.logger.debug("Snapshot cannot be loaded. Mastra engine is not initialized", { runId });
2099
- return;
2100
- }
2101
- const activeRun = this.#runs.get(runId);
2102
- if (activeRun) {
2103
- await activeRun.persistWorkflowSnapshot();
2104
- }
2105
- return this.#mastra.storage.loadWorkflowSnapshot({ runId, workflowName: this.name });
2106
- }
2107
- getExecutionSpan(runId) {
2108
- return this.#runs.get(runId)?.executionSpan;
2109
- }
2110
- #makeStepDef(stepId) {
2111
- const executeStep = (handler2, spanName, attributes) => {
2112
- return async (data) => {
2113
- return await context.with(
2114
- trace.setSpan(context.active(), this.getExecutionSpan(attributes?.runId ?? data?.runId)),
2115
- async () => {
2116
- if (this?.telemetry) {
2117
- return this.telemetry.traceMethod(handler2, {
2118
- spanName,
2119
- attributes
2120
- })(data);
2121
- } else {
2122
- return handler2(data);
2123
- }
2124
- }
2125
- );
2126
- };
2127
- };
2128
- const handler = async ({ context, ...rest }) => {
2129
- const targetStep = this.#steps[stepId];
2130
- if (!targetStep) throw new Error(`Step not found`);
2131
- const { payload = {}, execute = async () => {
2132
- } } = targetStep;
2133
- const finalAction = this.telemetry ? executeStep(execute, `workflow.${this.name}.action.${stepId}`, {
2134
- componentName: this.name,
2135
- runId: rest.runId
2136
- }) : execute;
2137
- return finalAction ? await finalAction({
2138
- context: { ...context, inputData: { ...context?.inputData || {}, ...payload } },
2139
- ...rest
2140
- }) : {};
2141
- };
2142
- const finalHandler = ({ context, ...rest }) => {
2143
- if (this.getExecutionSpan(rest?.runId)) {
2144
- return executeStep(handler, `workflow.${this.name}.step.${stepId}`, {
2145
- componentName: this.name,
2146
- runId: rest?.runId
2147
- })({ context, ...rest });
2148
- }
2149
- return handler({ context, ...rest });
2150
- };
2151
- return {
2152
- handler: finalHandler,
2153
- data: {}
2154
- };
2155
- }
2156
- #getActivePathsAndStatus(value) {
2157
- const paths = [];
2158
- const traverse = (current, path = []) => {
2159
- for (const [key, value2] of Object.entries(current)) {
2160
- const currentPath = [...path, key];
2161
- if (typeof value2 === "string") {
2162
- paths.push({
2163
- stepPath: currentPath,
2164
- stepId: key,
2165
- status: value2
2166
- });
2167
- } else if (typeof value2 === "object" && value2 !== null) {
2168
- traverse(value2, currentPath);
2169
- }
2170
- }
2171
- };
2172
- traverse(value);
2173
- return paths;
2174
- }
2175
- async getState(runId) {
2176
- const run = this.#runs.get(runId);
2177
- if (run) {
2178
- return run.getState();
2179
- }
2180
- const storedSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
2181
- runId,
2182
- workflowName: this.name
2183
- });
2184
- if (storedSnapshot) {
2185
- const parsed = storedSnapshot;
2186
- const m = this.#getActivePathsAndStatus(parsed.value);
2187
- return {
2188
- runId,
2189
- value: parsed.value,
2190
- context: parsed.context,
2191
- activePaths: m,
2192
- timestamp: Date.now()
2193
- };
2194
- }
2195
- return null;
2196
- }
2197
- async resume({
2198
- runId,
2199
- stepId,
2200
- context: resumeContext
2201
- }) {
2202
- this.logger.warn(`Please use 'resume' on the 'createRun' call instead, resume is deprecated`);
2203
- const activeRun = this.#runs.get(runId);
2204
- if (activeRun) {
2205
- return activeRun.resume({ stepId, context: resumeContext });
2206
- }
2207
- const run = this.createRun({ runId });
2208
- return run.resume({ stepId, context: resumeContext });
2209
- }
2210
- watch(onTransition) {
2211
- this.logger.warn(`Please use 'watch' on the 'createRun' call instead, watch is deprecated`);
2212
- this.#onStepTransition.add(onTransition);
2213
- return () => {
2214
- this.#onStepTransition.delete(onTransition);
2215
- };
2216
- }
2217
- async resumeWithEvent(runId, eventName, data) {
2218
- this.logger.warn(`Please use 'resumeWithEvent' on the 'createRun' call instead, resumeWithEvent is deprecated`);
2219
- const event = this.events?.[eventName];
2220
- if (!event) {
2221
- throw new Error(`Event ${eventName} not found`);
2222
- }
2223
- const results = await this.resume({ runId, stepId: `__${eventName}_event`, context: { resumedEvent: data } });
2224
- return results;
2225
- }
2226
- __registerMastra(mastra) {
2227
- this.#mastra = mastra;
2228
- }
2229
- __registerPrimitives(p) {
2230
- if (p.telemetry) {
2231
- this.__setTelemetry(p.telemetry);
2232
- }
2233
- if (p.logger) {
2234
- this.__setLogger(p.logger);
2235
- }
2236
- }
2237
- get stepGraph() {
2238
- return this.#stepGraph;
2239
- }
2240
- get stepSubscriberGraph() {
2241
- return this.#stepSubscriberGraph;
2242
- }
2243
- get serializedStepGraph() {
2244
- return this.#serializedStepGraph;
2245
- }
2246
- get serializedStepSubscriberGraph() {
2247
- return this.#serializedStepSubscriberGraph;
2248
- }
2249
- get steps() {
2250
- return this.#steps;
2251
- }
2252
- setNested(isNested) {
2253
- this.#isNested = isNested;
2254
- }
2255
- get isNested() {
2256
- return this.#isNested;
2257
- }
2258
- toStep() {
2259
- const x = workflowToStep(this, { mastra: this.#mastra });
2260
- return new Step(x);
2261
- }
2262
- };
2263
-
2264
- export { Step, WhenConditionReturnValue, Workflow, createStep, getActivePathsAndStatus, getResultActivePaths, getStepResult, getSuspendedPaths, isErrorEvent, isFinalState, isLimboState, isTransitionEvent, isVariableReference, isWorkflow, mergeChildValue, recursivelyCheckForFinalState, resolveVariables, updateStepInHierarchy, workflowToStep };