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