@mastra/inngest 0.0.0-add-save-score-validation-on-stores-20250911031242 → 0.0.0-agent-error-handling-20251023180025

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.
package/dist/index.cjs CHANGED
@@ -1,19 +1,27 @@
1
1
  'use strict';
2
2
 
3
3
  var crypto = require('crypto');
4
+ var web = require('stream/web');
4
5
  var realtime = require('@inngest/realtime');
5
6
  var aiTracing = require('@mastra/core/ai-tracing');
6
7
  var di = require('@mastra/core/di');
8
+ var stream = require('@mastra/core/stream');
7
9
  var tools = require('@mastra/core/tools');
8
10
  var workflows = require('@mastra/core/workflows');
9
11
  var _constants = require('@mastra/core/workflows/_constants');
12
+ var inngest = require('inngest');
10
13
  var hono = require('inngest/hono');
11
14
  var zod = require('zod');
12
15
 
13
16
  // src/index.ts
14
- function serve({ mastra, inngest }) {
17
+ function serve({
18
+ mastra,
19
+ inngest,
20
+ functions: userFunctions = [],
21
+ registerOptions
22
+ }) {
15
23
  const wfs = mastra.getWorkflows();
16
- const functions = Array.from(
24
+ const workflowFunctions = Array.from(
17
25
  new Set(
18
26
  Object.values(wfs).flatMap((wf) => {
19
27
  if (wf instanceof InngestWorkflow) {
@@ -25,8 +33,9 @@ function serve({ mastra, inngest }) {
25
33
  )
26
34
  );
27
35
  return hono.serve({
36
+ ...registerOptions,
28
37
  client: inngest,
29
- functions
38
+ functions: [...workflowFunctions, ...userFunctions]
30
39
  });
31
40
  }
32
41
  var InngestRun = class extends workflows.Run {
@@ -54,9 +63,15 @@ var InngestRun = class extends workflows.Run {
54
63
  await new Promise((resolve) => setTimeout(resolve, 1e3));
55
64
  runs = await this.getRuns(eventId);
56
65
  if (runs?.[0]?.status === "Failed") {
57
- console.log("run", runs?.[0]);
58
- throw new Error(`Function run ${runs?.[0]?.status}`);
59
- } else if (runs?.[0]?.status === "Cancelled") {
66
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
67
+ workflowName: this.workflowId,
68
+ runId: this.runId
69
+ });
70
+ return {
71
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
72
+ };
73
+ }
74
+ if (runs?.[0]?.status === "Cancelled") {
60
75
  const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
61
76
  workflowName: this.workflowId,
62
77
  runId: this.runId
@@ -87,6 +102,7 @@ var InngestRun = class extends workflows.Run {
87
102
  await this.#mastra?.storage?.persistWorkflowSnapshot({
88
103
  workflowName: this.workflowId,
89
104
  runId: this.runId,
105
+ resourceId: this.resourceId,
90
106
  snapshot: {
91
107
  ...snapshot,
92
108
  status: "canceled"
@@ -95,11 +111,13 @@ var InngestRun = class extends workflows.Run {
95
111
  }
96
112
  }
97
113
  async start({
98
- inputData
114
+ inputData,
115
+ initialState
99
116
  }) {
100
117
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
101
118
  workflowName: this.workflowId,
102
119
  runId: this.runId,
120
+ resourceId: this.resourceId,
103
121
  snapshot: {
104
122
  runId: this.runId,
105
123
  serializedStepGraph: this.serializedStepGraph,
@@ -107,16 +125,21 @@ var InngestRun = class extends workflows.Run {
107
125
  context: {},
108
126
  activePaths: [],
109
127
  suspendedPaths: {},
128
+ resumeLabels: {},
110
129
  waitingPaths: {},
111
130
  timestamp: Date.now(),
112
131
  status: "running"
113
132
  }
114
133
  });
134
+ const inputDataToUse = await this._validateInput(inputData);
135
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
115
136
  const eventOutput = await this.inngest.send({
116
137
  name: `workflow.${this.workflowId}`,
117
138
  data: {
118
- inputData,
119
- runId: this.runId
139
+ inputData: inputDataToUse,
140
+ initialState: initialStateToUse,
141
+ runId: this.runId,
142
+ resourceId: this.resourceId
120
143
  }
121
144
  });
122
145
  const eventId = eventOutput.ids[0];
@@ -152,17 +175,20 @@ var InngestRun = class extends workflows.Run {
152
175
  workflowName: this.workflowId,
153
176
  runId: this.runId
154
177
  });
178
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
179
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
155
180
  const eventOutput = await this.inngest.send({
156
181
  name: `workflow.${this.workflowId}`,
157
182
  data: {
158
- inputData: params.resumeData,
183
+ inputData: resumeDataToUse,
184
+ initialState: snapshot?.value ?? {},
159
185
  runId: this.runId,
160
186
  workflowId: this.workflowId,
161
187
  stepResults: snapshot?.context,
162
188
  resume: {
163
189
  steps,
164
190
  stepResults: snapshot?.context,
165
- resumePayload: params.resumeData,
191
+ resumePayload: resumeDataToUse,
166
192
  // @ts-ignore
167
193
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
168
194
  }
@@ -202,35 +228,11 @@ var InngestRun = class extends workflows.Run {
202
228
  });
203
229
  };
204
230
  }
205
- stream({ inputData, runtimeContext } = {}) {
231
+ streamLegacy({ inputData, runtimeContext } = {}) {
206
232
  const { readable, writable } = new TransformStream();
207
- let currentToolData = void 0;
208
233
  const writer = writable.getWriter();
209
234
  const unwatch = this.watch(async (event) => {
210
- if (event.type === "workflow-agent-call-start") {
211
- currentToolData = {
212
- name: event.payload.name,
213
- args: event.payload.args
214
- };
215
- await writer.write({
216
- ...event.payload,
217
- type: "tool-call-streaming-start"
218
- });
219
- return;
220
- }
221
235
  try {
222
- if (event.type === "workflow-agent-call-finish") {
223
- return;
224
- } else if (!event.type.startsWith("workflow-")) {
225
- if (event.type === "text-delta") {
226
- await writer.write({
227
- type: "tool-call-delta",
228
- ...currentToolData ?? {},
229
- argsTextDelta: event.textDelta
230
- });
231
- }
232
- return;
233
- }
234
236
  const e = {
235
237
  ...event,
236
238
  type: event.type.replace("workflow-", "")
@@ -261,6 +263,58 @@ var InngestRun = class extends workflows.Run {
261
263
  getWorkflowState: () => this.executionResults
262
264
  };
263
265
  }
266
+ stream({
267
+ inputData,
268
+ runtimeContext,
269
+ closeOnSuspend = true
270
+ } = {}) {
271
+ const self = this;
272
+ let streamOutput;
273
+ const stream$1 = new web.ReadableStream({
274
+ async start(controller) {
275
+ const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
276
+ controller.enqueue({
277
+ type,
278
+ runId: self.runId,
279
+ from,
280
+ payload: {
281
+ stepName: payload.id,
282
+ ...payload
283
+ }
284
+ });
285
+ }, "watch-v2");
286
+ self.closeStreamAction = async () => {
287
+ unwatch();
288
+ try {
289
+ await controller.close();
290
+ } catch (err) {
291
+ console.error("Error closing stream:", err);
292
+ }
293
+ };
294
+ const executionResultsPromise = self.start({
295
+ inputData,
296
+ runtimeContext
297
+ });
298
+ const executionResults = await executionResultsPromise;
299
+ if (closeOnSuspend) {
300
+ self.closeStreamAction?.().catch(() => {
301
+ });
302
+ } else if (executionResults.status !== "suspended") {
303
+ self.closeStreamAction?.().catch(() => {
304
+ });
305
+ }
306
+ if (streamOutput) {
307
+ streamOutput.updateResults(executionResults);
308
+ }
309
+ }
310
+ });
311
+ streamOutput = new stream.WorkflowRunOutput({
312
+ runId: this.runId,
313
+ workflowId: this.workflowId,
314
+ stream: stream$1
315
+ });
316
+ return streamOutput;
317
+ }
264
318
  };
265
319
  var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
266
320
  #mastra;
@@ -312,23 +366,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
312
366
  }
313
367
  }
314
368
  }
315
- createRun(options) {
316
- const runIdToUse = options?.runId || crypto.randomUUID();
317
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
318
- {
319
- workflowId: this.id,
320
- runId: runIdToUse,
321
- executionEngine: this.executionEngine,
322
- executionGraph: this.executionGraph,
323
- serializedStepGraph: this.serializedStepGraph,
324
- mastra: this.#mastra,
325
- retryConfig: this.retryConfig,
326
- cleanup: () => this.runs.delete(runIdToUse)
327
- },
328
- this.inngest
369
+ /**
370
+ * @deprecated Use createRunAsync() instead.
371
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
372
+ */
373
+ createRun(_options) {
374
+ throw new Error(
375
+ "createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
329
376
  );
330
- this.runs.set(runIdToUse, run);
331
- return run;
332
377
  }
333
378
  async createRunAsync(options) {
334
379
  const runIdToUse = options?.runId || crypto.randomUUID();
@@ -336,21 +381,28 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
336
381
  {
337
382
  workflowId: this.id,
338
383
  runId: runIdToUse,
384
+ resourceId: options?.resourceId,
339
385
  executionEngine: this.executionEngine,
340
386
  executionGraph: this.executionGraph,
341
387
  serializedStepGraph: this.serializedStepGraph,
342
388
  mastra: this.#mastra,
343
389
  retryConfig: this.retryConfig,
344
- cleanup: () => this.runs.delete(runIdToUse)
390
+ cleanup: () => this.runs.delete(runIdToUse),
391
+ workflowSteps: this.steps
345
392
  },
346
393
  this.inngest
347
394
  );
348
395
  this.runs.set(runIdToUse, run);
396
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
397
+ workflowStatus: run.workflowRunStatus,
398
+ stepResults: {}
399
+ });
349
400
  const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
350
- if (!workflowSnapshotInStorage) {
401
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
351
402
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
352
403
  workflowName: this.id,
353
404
  runId: runIdToUse,
405
+ resourceId: options?.resourceId,
354
406
  snapshot: {
355
407
  runId: runIdToUse,
356
408
  status: "pending",
@@ -360,6 +412,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
360
412
  waitingPaths: {},
361
413
  serializedStepGraph: this.serializedStepGraph,
362
414
  suspendedPaths: {},
415
+ resumeLabels: {},
363
416
  result: void 0,
364
417
  error: void 0,
365
418
  // @ts-ignore
@@ -384,7 +437,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
384
437
  },
385
438
  { event: `workflow.${this.id}` },
386
439
  async ({ event, step, attempt, publish }) => {
387
- let { inputData, runId, resume } = event.data;
440
+ let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
388
441
  if (!runId) {
389
442
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
390
443
  return crypto.randomUUID();
@@ -412,21 +465,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
412
465
  once: (_event, _callback) => {
413
466
  }
414
467
  };
415
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
468
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
416
469
  const result = await engine.execute({
417
470
  workflowId: this.id,
418
471
  runId,
472
+ resourceId,
419
473
  graph: this.executionGraph,
420
474
  serializedStepGraph: this.serializedStepGraph,
421
475
  input: inputData,
476
+ initialState,
422
477
  emitter,
423
478
  retryConfig: this.retryConfig,
424
479
  runtimeContext: new di.RuntimeContext(),
425
480
  // TODO
426
481
  resume,
427
482
  abortController: new AbortController(),
428
- currentSpan: void 0
483
+ currentSpan: void 0,
429
484
  // TODO: Pass actual parent AI span from workflow execution context
485
+ outputOptions
486
+ });
487
+ await step.run(`workflow.${this.id}.finalize`, async () => {
488
+ if (result.status === "failed") {
489
+ throw new inngest.NonRetriableError(`Workflow failed`, {
490
+ cause: result
491
+ });
492
+ }
493
+ return result;
430
494
  });
431
495
  return { result, runId };
432
496
  }
@@ -460,11 +524,10 @@ function createStep(params) {
460
524
  if (isAgent(params)) {
461
525
  return {
462
526
  id: params.name,
527
+ description: params.getDescription(),
463
528
  // @ts-ignore
464
529
  inputSchema: zod.z.object({
465
530
  prompt: zod.z.string()
466
- // resourceId: z.string().optional(),
467
- // threadId: z.string().optional(),
468
531
  }),
469
532
  // @ts-ignore
470
533
  outputSchema: zod.z.object({
@@ -480,34 +543,66 @@ function createStep(params) {
480
543
  name: params.name,
481
544
  args: inputData
482
545
  };
483
- await emitter.emit("watch-v2", {
484
- type: "workflow-agent-call-start",
485
- payload: toolData
486
- });
487
- const { fullStream } = await params.stream(inputData.prompt, {
488
- // resourceId: inputData.resourceId,
489
- // threadId: inputData.threadId,
490
- runtimeContext,
491
- tracingContext,
492
- onFinish: (result) => {
493
- streamPromise.resolve(result.text);
494
- },
495
- abortSignal
496
- });
497
- if (abortSignal.aborted) {
498
- return abort();
499
- }
500
- for await (const chunk of fullStream) {
501
- await emitter.emit("watch-v2", chunk);
546
+ if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
547
+ const { fullStream } = await params.stream(inputData.prompt, {
548
+ runtimeContext,
549
+ tracingContext,
550
+ onFinish: (result) => {
551
+ streamPromise.resolve(result.text);
552
+ },
553
+ abortSignal
554
+ });
555
+ if (abortSignal.aborted) {
556
+ return abort();
557
+ }
558
+ await emitter.emit("watch-v2", {
559
+ type: "tool-call-streaming-start",
560
+ ...toolData ?? {}
561
+ });
562
+ for await (const chunk of fullStream) {
563
+ if (chunk.type === "text-delta") {
564
+ await emitter.emit("watch-v2", {
565
+ type: "tool-call-delta",
566
+ ...toolData ?? {},
567
+ argsTextDelta: chunk.payload.text
568
+ });
569
+ }
570
+ }
571
+ } else {
572
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
573
+ runtimeContext,
574
+ tracingContext,
575
+ onFinish: (result) => {
576
+ streamPromise.resolve(result.text);
577
+ },
578
+ abortSignal
579
+ });
580
+ if (abortSignal.aborted) {
581
+ return abort();
582
+ }
583
+ await emitter.emit("watch-v2", {
584
+ type: "tool-call-streaming-start",
585
+ ...toolData ?? {}
586
+ });
587
+ for await (const chunk of fullStream) {
588
+ if (chunk.type === "text-delta") {
589
+ await emitter.emit("watch-v2", {
590
+ type: "tool-call-delta",
591
+ ...toolData ?? {},
592
+ argsTextDelta: chunk.textDelta
593
+ });
594
+ }
595
+ }
502
596
  }
503
597
  await emitter.emit("watch-v2", {
504
- type: "workflow-agent-call-finish",
505
- payload: toolData
598
+ type: "tool-call-streaming-finish",
599
+ ...toolData ?? {}
506
600
  });
507
601
  return {
508
602
  text: await streamPromise.promise
509
603
  };
510
- }
604
+ },
605
+ component: params.component
511
606
  };
512
607
  }
513
608
  if (isTool(params)) {
@@ -518,16 +613,20 @@ function createStep(params) {
518
613
  // TODO: tool probably should have strong id type
519
614
  // @ts-ignore
520
615
  id: params.id,
616
+ description: params.description,
521
617
  inputSchema: params.inputSchema,
522
618
  outputSchema: params.outputSchema,
523
- execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
619
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
524
620
  return params.execute({
525
621
  context: inputData,
526
622
  mastra: aiTracing.wrapMastra(mastra, tracingContext),
527
623
  runtimeContext,
528
- tracingContext
624
+ tracingContext,
625
+ suspend,
626
+ resumeData
529
627
  });
530
- }
628
+ },
629
+ component: "TOOL"
531
630
  };
532
631
  }
533
632
  return {
@@ -543,7 +642,10 @@ function createStep(params) {
543
642
  function init(inngest) {
544
643
  return {
545
644
  createWorkflow(params) {
546
- return new InngestWorkflow(params, inngest);
645
+ return new InngestWorkflow(
646
+ params,
647
+ inngest
648
+ );
547
649
  },
548
650
  createStep,
549
651
  cloneStep(step, opts) {
@@ -552,7 +654,11 @@ function init(inngest) {
552
654
  description: step.description,
553
655
  inputSchema: step.inputSchema,
554
656
  outputSchema: step.outputSchema,
555
- execute: step.execute
657
+ resumeSchema: step.resumeSchema,
658
+ suspendSchema: step.suspendSchema,
659
+ stateSchema: step.stateSchema,
660
+ execute: step.execute,
661
+ component: step.component
556
662
  };
557
663
  },
558
664
  cloneWorkflow(workflow, opts) {
@@ -572,8 +678,8 @@ function init(inngest) {
572
678
  var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
573
679
  inngestStep;
574
680
  inngestAttempts;
575
- constructor(mastra, inngestStep, inngestAttempts = 0) {
576
- super({ mastra });
681
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
682
+ super({ mastra, options });
577
683
  this.inngestStep = inngestStep;
578
684
  this.inngestAttempts = inngestAttempts;
579
685
  }
@@ -636,7 +742,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
636
742
  });
637
743
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
638
744
  if (stepResult?.status === "suspended") {
639
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
745
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
640
746
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
641
747
  }
642
748
  return [];
@@ -669,7 +775,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
669
775
  attributes: {
670
776
  durationMs: duration,
671
777
  sleepType: fn ? "dynamic" : "fixed"
672
- }
778
+ },
779
+ tracingPolicy: this.options?.tracingPolicy
673
780
  });
674
781
  if (fn) {
675
782
  const stepCallId = crypto.randomUUID();
@@ -680,21 +787,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
680
787
  mastra: this.mastra,
681
788
  runtimeContext,
682
789
  inputData: prevOutput,
790
+ state: executionContext.state,
791
+ setState: (state) => {
792
+ executionContext.state = state;
793
+ },
683
794
  runCount: -1,
684
795
  tracingContext: {
685
796
  currentSpan: sleepSpan
686
797
  },
687
798
  getInitData: () => stepResults?.input,
688
- getStepResult: (step) => {
689
- if (!step?.id) {
690
- return null;
691
- }
692
- const result = stepResults[step.id];
693
- if (result?.status === "success") {
694
- return result.output;
695
- }
696
- return null;
697
- },
799
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
698
800
  // TODO: this function shouldn't have suspend probably?
699
801
  suspend: async (_suspendPayload) => {
700
802
  },
@@ -754,7 +856,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
754
856
  untilDate: date,
755
857
  durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
756
858
  sleepType: fn ? "dynamic" : "fixed"
757
- }
859
+ },
860
+ tracingPolicy: this.options?.tracingPolicy
758
861
  });
759
862
  if (fn) {
760
863
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
@@ -765,21 +868,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
765
868
  mastra: this.mastra,
766
869
  runtimeContext,
767
870
  inputData: prevOutput,
871
+ state: executionContext.state,
872
+ setState: (state) => {
873
+ executionContext.state = state;
874
+ },
768
875
  runCount: -1,
769
876
  tracingContext: {
770
877
  currentSpan: sleepUntilSpan
771
878
  },
772
879
  getInitData: () => stepResults?.input,
773
- getStepResult: (step) => {
774
- if (!step?.id) {
775
- return null;
776
- }
777
- const result = stepResults[step.id];
778
- if (result?.status === "success") {
779
- return result.output;
780
- }
781
- return null;
782
- },
880
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
783
881
  // TODO: this function shouldn't have suspend probably?
784
882
  suspend: async (_suspendPayload) => {
785
883
  },
@@ -804,6 +902,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
804
902
  )
805
903
  });
806
904
  });
905
+ if (date && !(date instanceof Date)) {
906
+ date = new Date(date);
907
+ }
807
908
  const time = !date ? 0 : date.getTime() - Date.now();
808
909
  sleepUntilSpan?.update({
809
910
  attributes: {
@@ -852,7 +953,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
852
953
  input: prevOutput,
853
954
  attributes: {
854
955
  stepId: step.id
855
- }
956
+ },
957
+ tracingPolicy: this.options?.tracingPolicy
958
+ });
959
+ const { inputData, validationError } = await workflows.validateStepInput({
960
+ prevOutput,
961
+ step,
962
+ validateInputs: this.options?.validateInputs ?? false
856
963
  });
857
964
  const startedAt = await this.inngestStep.run(
858
965
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
@@ -884,7 +991,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
884
991
  payload: {
885
992
  id: step.id,
886
993
  status: "running",
887
- payload: prevOutput,
994
+ payload: inputData,
888
995
  startedAt: startedAt2
889
996
  }
890
997
  });
@@ -895,38 +1002,60 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
895
1002
  const isResume = !!resume?.steps?.length;
896
1003
  let result;
897
1004
  let runId;
898
- if (isResume) {
899
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
900
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
901
- workflowName: step.id,
902
- runId
903
- });
904
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
905
- function: step.getFunction(),
906
- data: {
907
- inputData: prevOutput,
908
- runId,
909
- resume: {
1005
+ try {
1006
+ if (isResume) {
1007
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
1008
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1009
+ workflowName: step.id,
1010
+ runId
1011
+ });
1012
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1013
+ function: step.getFunction(),
1014
+ data: {
1015
+ inputData,
1016
+ initialState: executionContext.state ?? snapshot?.value ?? {},
910
1017
  runId,
911
- steps: resume.steps.slice(1),
912
- stepResults: snapshot?.context,
913
- resumePayload: resume.resumePayload,
914
- // @ts-ignore
915
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1018
+ resume: {
1019
+ runId,
1020
+ steps: resume.steps.slice(1),
1021
+ stepResults: snapshot?.context,
1022
+ resumePayload: resume.resumePayload,
1023
+ // @ts-ignore
1024
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1025
+ },
1026
+ outputOptions: { includeState: true }
916
1027
  }
917
- }
918
- });
919
- result = invokeResp.result;
920
- runId = invokeResp.runId;
921
- } else {
922
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
923
- function: step.getFunction(),
924
- data: {
925
- inputData: prevOutput
926
- }
927
- });
928
- result = invokeResp.result;
929
- runId = invokeResp.runId;
1028
+ });
1029
+ result = invokeResp.result;
1030
+ runId = invokeResp.runId;
1031
+ executionContext.state = invokeResp.result.state;
1032
+ } else {
1033
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1034
+ function: step.getFunction(),
1035
+ data: {
1036
+ inputData,
1037
+ initialState: executionContext.state ?? {},
1038
+ outputOptions: { includeState: true }
1039
+ }
1040
+ });
1041
+ result = invokeResp.result;
1042
+ runId = invokeResp.runId;
1043
+ executionContext.state = invokeResp.result.state;
1044
+ }
1045
+ } catch (e) {
1046
+ const errorCause = e?.cause;
1047
+ if (errorCause && typeof errorCause === "object") {
1048
+ result = errorCause;
1049
+ runId = errorCause.runId || crypto.randomUUID();
1050
+ } else {
1051
+ runId = crypto.randomUUID();
1052
+ result = {
1053
+ status: "failed",
1054
+ error: e instanceof Error ? e : new Error(String(e)),
1055
+ steps: {},
1056
+ input: inputData
1057
+ };
1058
+ }
930
1059
  }
931
1060
  const res = await this.inngestStep.run(
932
1061
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -965,7 +1094,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
965
1094
  return stepRes2?.status === "suspended";
966
1095
  });
967
1096
  for (const [stepName, stepResult] of suspendedSteps) {
968
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1097
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
969
1098
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
970
1099
  await emitter.emit("watch", {
971
1100
  type: "watch",
@@ -973,7 +1102,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
973
1102
  currentStep: {
974
1103
  id: step.id,
975
1104
  status: "suspended",
976
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1105
+ payload: stepResult.payload,
1106
+ suspendPayload: {
1107
+ ...stepResult?.suspendPayload,
1108
+ __workflow_meta: { runId, path: suspendPath }
1109
+ }
977
1110
  },
978
1111
  workflowState: {
979
1112
  status: "running",
@@ -995,7 +1128,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
995
1128
  executionContext,
996
1129
  result: {
997
1130
  status: "suspended",
998
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1131
+ payload: stepResult.payload,
1132
+ suspendPayload: {
1133
+ ...stepResult?.suspendPayload,
1134
+ __workflow_meta: { runId, path: suspendPath }
1135
+ }
999
1136
  }
1000
1137
  };
1001
1138
  }
@@ -1060,141 +1197,182 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1060
1197
  }
1061
1198
  );
1062
1199
  Object.assign(executionContext, res.executionContext);
1063
- return res.result;
1200
+ return {
1201
+ ...res.result,
1202
+ startedAt,
1203
+ endedAt: Date.now(),
1204
+ payload: inputData,
1205
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1206
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1207
+ };
1064
1208
  }
1065
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1066
- let execResults;
1067
- let suspended;
1068
- let bailed;
1069
- try {
1070
- const result = await step.execute({
1071
- runId: executionContext.runId,
1072
- mastra: this.mastra,
1073
- runtimeContext,
1074
- writableStream,
1075
- inputData: prevOutput,
1076
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1077
- tracingContext: {
1078
- currentSpan: stepAISpan
1079
- },
1080
- getInitData: () => stepResults?.input,
1081
- getStepResult: (step2) => {
1082
- const result2 = stepResults[step2.id];
1083
- if (result2?.status === "success") {
1084
- return result2.output;
1209
+ let stepRes;
1210
+ try {
1211
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1212
+ let execResults;
1213
+ let suspended;
1214
+ let bailed;
1215
+ try {
1216
+ if (validationError) {
1217
+ throw validationError;
1218
+ }
1219
+ const result = await step.execute({
1220
+ runId: executionContext.runId,
1221
+ mastra: this.mastra,
1222
+ runtimeContext,
1223
+ writableStream,
1224
+ state: executionContext?.state ?? {},
1225
+ setState: (state) => {
1226
+ executionContext.state = state;
1227
+ },
1228
+ inputData,
1229
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1230
+ tracingContext: {
1231
+ currentSpan: stepAISpan
1232
+ },
1233
+ getInitData: () => stepResults?.input,
1234
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1235
+ suspend: async (suspendPayload, suspendOptions) => {
1236
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1237
+ if (suspendOptions?.resumeLabel) {
1238
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1239
+ for (const label of resumeLabel) {
1240
+ executionContext.resumeLabels[label] = {
1241
+ stepId: step.id,
1242
+ foreachIndex: executionContext.foreachIndex
1243
+ };
1244
+ }
1245
+ }
1246
+ suspended = { payload: suspendPayload };
1247
+ },
1248
+ bail: (result2) => {
1249
+ bailed = { payload: result2 };
1250
+ },
1251
+ resume: {
1252
+ steps: resume?.steps?.slice(1) || [],
1253
+ resumePayload: resume?.resumePayload,
1254
+ // @ts-ignore
1255
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1256
+ },
1257
+ [_constants.EMITTER_SYMBOL]: emitter,
1258
+ engine: {
1259
+ step: this.inngestStep
1260
+ },
1261
+ abortSignal: abortController.signal
1262
+ });
1263
+ const endedAt = Date.now();
1264
+ execResults = {
1265
+ status: "success",
1266
+ output: result,
1267
+ startedAt,
1268
+ endedAt,
1269
+ payload: inputData,
1270
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1271
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1272
+ };
1273
+ } catch (e) {
1274
+ const stepFailure = {
1275
+ status: "failed",
1276
+ payload: inputData,
1277
+ error: e instanceof Error ? e.message : String(e),
1278
+ endedAt: Date.now(),
1279
+ startedAt,
1280
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1281
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1282
+ };
1283
+ execResults = stepFailure;
1284
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1285
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1286
+ throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1287
+ cause: execResults
1288
+ });
1289
+ }
1290
+ if (suspended) {
1291
+ execResults = {
1292
+ status: "suspended",
1293
+ suspendPayload: suspended.payload,
1294
+ payload: inputData,
1295
+ suspendedAt: Date.now(),
1296
+ startedAt,
1297
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1298
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1299
+ };
1300
+ } else if (bailed) {
1301
+ execResults = {
1302
+ status: "bailed",
1303
+ output: bailed.payload,
1304
+ payload: inputData,
1305
+ endedAt: Date.now(),
1306
+ startedAt
1307
+ };
1308
+ }
1309
+ await emitter.emit("watch", {
1310
+ type: "watch",
1311
+ payload: {
1312
+ currentStep: {
1313
+ id: step.id,
1314
+ ...execResults
1315
+ },
1316
+ workflowState: {
1317
+ status: "running",
1318
+ steps: { ...stepResults, [step.id]: execResults },
1319
+ result: null,
1320
+ error: null
1085
1321
  }
1086
- return null;
1087
- },
1088
- suspend: async (suspendPayload) => {
1089
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1090
- suspended = { payload: suspendPayload };
1091
- },
1092
- bail: (result2) => {
1093
- bailed = { payload: result2 };
1094
- },
1095
- resume: {
1096
- steps: resume?.steps?.slice(1) || [],
1097
- resumePayload: resume?.resumePayload,
1098
- // @ts-ignore
1099
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1100
- },
1101
- [_constants.EMITTER_SYMBOL]: emitter,
1102
- engine: {
1103
- step: this.inngestStep
1104
1322
  },
1105
- abortSignal: abortController.signal
1323
+ eventTimestamp: Date.now()
1106
1324
  });
1107
- const endedAt = Date.now();
1108
- execResults = {
1109
- status: "success",
1110
- output: result,
1111
- startedAt,
1112
- endedAt,
1113
- payload: prevOutput,
1114
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1115
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1116
- };
1117
- } catch (e) {
1118
- execResults = {
1119
- status: "failed",
1120
- payload: prevOutput,
1121
- error: e instanceof Error ? e.message : String(e),
1122
- endedAt: Date.now(),
1123
- startedAt,
1124
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1125
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1126
- };
1127
- }
1128
- if (suspended) {
1129
- execResults = {
1130
- status: "suspended",
1131
- suspendedPayload: suspended.payload,
1132
- payload: prevOutput,
1133
- suspendedAt: Date.now(),
1134
- startedAt,
1135
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1136
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1137
- };
1138
- } else if (bailed) {
1139
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1140
- }
1141
- if (execResults.status === "failed") {
1142
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1143
- const error = new Error(execResults.error);
1144
- stepAISpan?.error({ error });
1145
- throw error;
1325
+ if (execResults.status === "suspended") {
1326
+ await emitter.emit("watch-v2", {
1327
+ type: "workflow-step-suspended",
1328
+ payload: {
1329
+ id: step.id,
1330
+ ...execResults
1331
+ }
1332
+ });
1333
+ } else {
1334
+ await emitter.emit("watch-v2", {
1335
+ type: "workflow-step-result",
1336
+ payload: {
1337
+ id: step.id,
1338
+ ...execResults
1339
+ }
1340
+ });
1341
+ await emitter.emit("watch-v2", {
1342
+ type: "workflow-step-finish",
1343
+ payload: {
1344
+ id: step.id,
1345
+ metadata: {}
1346
+ }
1347
+ });
1146
1348
  }
1147
- }
1148
- await emitter.emit("watch", {
1149
- type: "watch",
1150
- payload: {
1151
- currentStep: {
1152
- id: step.id,
1153
- ...execResults
1154
- },
1155
- workflowState: {
1156
- status: "running",
1157
- steps: { ...stepResults, [step.id]: execResults },
1158
- result: null,
1159
- error: null
1160
- }
1161
- },
1162
- eventTimestamp: Date.now()
1349
+ stepAISpan?.end({ output: execResults });
1350
+ return { result: execResults, executionContext, stepResults };
1163
1351
  });
1164
- if (execResults.status === "suspended") {
1165
- await emitter.emit("watch-v2", {
1166
- type: "workflow-step-suspended",
1167
- payload: {
1168
- id: step.id,
1169
- ...execResults
1170
- }
1171
- });
1172
- } else {
1173
- await emitter.emit("watch-v2", {
1174
- type: "workflow-step-result",
1175
- payload: {
1176
- id: step.id,
1177
- ...execResults
1178
- }
1179
- });
1180
- await emitter.emit("watch-v2", {
1181
- type: "workflow-step-finish",
1182
- payload: {
1183
- id: step.id,
1184
- metadata: {}
1185
- }
1186
- });
1187
- }
1188
- stepAISpan?.end({ output: execResults });
1189
- return { result: execResults, executionContext, stepResults };
1190
- });
1191
- if (disableScorers !== false) {
1352
+ } catch (e) {
1353
+ const stepFailure = e instanceof Error ? e?.cause : {
1354
+ status: "failed",
1355
+ error: e instanceof Error ? e.message : String(e),
1356
+ payload: inputData,
1357
+ startedAt,
1358
+ endedAt: Date.now()
1359
+ };
1360
+ stepRes = {
1361
+ result: stepFailure,
1362
+ executionContext,
1363
+ stepResults: {
1364
+ ...stepResults,
1365
+ [step.id]: stepFailure
1366
+ }
1367
+ };
1368
+ }
1369
+ if (disableScorers !== false && stepRes.result.status === "success") {
1192
1370
  await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1193
1371
  if (step.scorers) {
1194
1372
  await this.runScorers({
1195
1373
  scorers: step.scorers,
1196
1374
  runId: executionContext.runId,
1197
- input: prevOutput,
1375
+ input: inputData,
1198
1376
  output: stepRes.result,
1199
1377
  workflowId: executionContext.workflowId,
1200
1378
  stepId: step.id,
@@ -1207,12 +1385,14 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1207
1385
  }
1208
1386
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1209
1387
  Object.assign(stepResults, stepRes.stepResults);
1388
+ executionContext.state = stepRes.executionContext.state;
1210
1389
  return stepRes.result;
1211
1390
  }
1212
1391
  async persistStepUpdate({
1213
1392
  workflowId,
1214
1393
  runId,
1215
1394
  stepResults,
1395
+ resourceId,
1216
1396
  executionContext,
1217
1397
  serializedStepGraph,
1218
1398
  workflowStatus,
@@ -1222,15 +1402,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1222
1402
  await this.inngestStep.run(
1223
1403
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1224
1404
  async () => {
1405
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1406
+ if (!shouldPersistSnapshot) {
1407
+ return;
1408
+ }
1225
1409
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1226
1410
  workflowName: workflowId,
1227
1411
  runId,
1412
+ resourceId,
1228
1413
  snapshot: {
1229
1414
  runId,
1230
- value: {},
1415
+ value: executionContext.state,
1231
1416
  context: stepResults,
1232
1417
  activePaths: [],
1233
1418
  suspendedPaths: executionContext.suspendedPaths,
1419
+ resumeLabels: executionContext.resumeLabels,
1234
1420
  waitingPaths: {},
1235
1421
  serializedStepGraph,
1236
1422
  status: workflowStatus,
@@ -1266,7 +1452,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1266
1452
  input: prevOutput,
1267
1453
  attributes: {
1268
1454
  conditionCount: entry.conditions.length
1269
- }
1455
+ },
1456
+ tracingPolicy: this.options?.tracingPolicy
1270
1457
  });
1271
1458
  let execResults;
1272
1459
  const truthyIndexes = (await Promise.all(
@@ -1278,7 +1465,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1278
1465
  input: prevOutput,
1279
1466
  attributes: {
1280
1467
  conditionIndex: index
1281
- }
1468
+ },
1469
+ tracingPolicy: this.options?.tracingPolicy
1282
1470
  });
1283
1471
  try {
1284
1472
  const result = await cond({
@@ -1288,20 +1476,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1288
1476
  runtimeContext,
1289
1477
  runCount: -1,
1290
1478
  inputData: prevOutput,
1479
+ state: executionContext.state,
1480
+ setState: (state) => {
1481
+ executionContext.state = state;
1482
+ },
1291
1483
  tracingContext: {
1292
1484
  currentSpan: evalSpan
1293
1485
  },
1294
1486
  getInitData: () => stepResults?.input,
1295
- getStepResult: (step) => {
1296
- if (!step?.id) {
1297
- return null;
1298
- }
1299
- const result2 = stepResults[step.id];
1300
- if (result2?.status === "success") {
1301
- return result2.output;
1302
- }
1303
- return null;
1304
- },
1487
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1305
1488
  // TODO: this function shouldn't have suspend probably?
1306
1489
  suspend: async (_suspendPayload) => {
1307
1490
  },
@@ -1368,8 +1551,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1368
1551
  runId,
1369
1552
  executionPath: [...executionContext.executionPath, index],
1370
1553
  suspendedPaths: executionContext.suspendedPaths,
1554
+ resumeLabels: executionContext.resumeLabels,
1371
1555
  retryConfig: executionContext.retryConfig,
1372
- executionSpan: executionContext.executionSpan
1556
+ executionSpan: executionContext.executionSpan,
1557
+ state: executionContext.state
1373
1558
  },
1374
1559
  emitter,
1375
1560
  abortController,
@@ -1387,7 +1572,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1387
1572
  if (hasFailed) {
1388
1573
  execResults = { status: "failed", error: hasFailed.result.error };
1389
1574
  } else if (hasSuspended) {
1390
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1575
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1391
1576
  } else {
1392
1577
  execResults = {
1393
1578
  status: "success",