@mastra/inngest 0.0.0-consolidate-changesets-20250904042643 → 0.0.0-cor235-20251008190353

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.js CHANGED
@@ -3,15 +3,21 @@ import { subscribe } from '@inngest/realtime';
3
3
  import { wrapMastra, AISpanType } from '@mastra/core/ai-tracing';
4
4
  import { RuntimeContext } from '@mastra/core/di';
5
5
  import { ToolStream, Tool } from '@mastra/core/tools';
6
- import { Run, Workflow, DefaultExecutionEngine } from '@mastra/core/workflows';
7
- import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
6
+ import { Run, Workflow, DefaultExecutionEngine, getStepResult, validateStepInput } from '@mastra/core/workflows';
7
+ import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
8
+ import { NonRetriableError, RetryAfterError } from 'inngest';
8
9
  import { serve as serve$1 } from 'inngest/hono';
9
10
  import { z } from 'zod';
10
11
 
11
12
  // src/index.ts
12
- function serve({ mastra, inngest }) {
13
+ function serve({
14
+ mastra,
15
+ inngest,
16
+ functions: userFunctions = [],
17
+ registerOptions
18
+ }) {
13
19
  const wfs = mastra.getWorkflows();
14
- const functions = Array.from(
20
+ const workflowFunctions = Array.from(
15
21
  new Set(
16
22
  Object.values(wfs).flatMap((wf) => {
17
23
  if (wf instanceof InngestWorkflow) {
@@ -23,8 +29,9 @@ function serve({ mastra, inngest }) {
23
29
  )
24
30
  );
25
31
  return serve$1({
32
+ ...registerOptions,
26
33
  client: inngest,
27
- functions
34
+ functions: [...workflowFunctions, ...userFunctions]
28
35
  });
29
36
  }
30
37
  var InngestRun = class extends Run {
@@ -52,9 +59,15 @@ var InngestRun = class extends Run {
52
59
  await new Promise((resolve) => setTimeout(resolve, 1e3));
53
60
  runs = await this.getRuns(eventId);
54
61
  if (runs?.[0]?.status === "Failed") {
55
- console.log("run", runs?.[0]);
56
- throw new Error(`Function run ${runs?.[0]?.status}`);
57
- } else if (runs?.[0]?.status === "Cancelled") {
62
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
63
+ workflowName: this.workflowId,
64
+ runId: this.runId
65
+ });
66
+ return {
67
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
68
+ };
69
+ }
70
+ if (runs?.[0]?.status === "Cancelled") {
58
71
  const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
59
72
  workflowName: this.workflowId,
60
73
  runId: this.runId
@@ -85,6 +98,7 @@ var InngestRun = class extends Run {
85
98
  await this.#mastra?.storage?.persistWorkflowSnapshot({
86
99
  workflowName: this.workflowId,
87
100
  runId: this.runId,
101
+ resourceId: this.resourceId,
88
102
  snapshot: {
89
103
  ...snapshot,
90
104
  status: "canceled"
@@ -93,11 +107,13 @@ var InngestRun = class extends Run {
93
107
  }
94
108
  }
95
109
  async start({
96
- inputData
110
+ inputData,
111
+ initialState
97
112
  }) {
98
113
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
99
114
  workflowName: this.workflowId,
100
115
  runId: this.runId,
116
+ resourceId: this.resourceId,
101
117
  snapshot: {
102
118
  runId: this.runId,
103
119
  serializedStepGraph: this.serializedStepGraph,
@@ -110,11 +126,15 @@ var InngestRun = class extends Run {
110
126
  status: "running"
111
127
  }
112
128
  });
129
+ const inputDataToUse = await this._validateInput(inputData);
130
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
113
131
  const eventOutput = await this.inngest.send({
114
132
  name: `workflow.${this.workflowId}`,
115
133
  data: {
116
- inputData,
117
- runId: this.runId
134
+ inputData: inputDataToUse,
135
+ initialState: initialStateToUse,
136
+ runId: this.runId,
137
+ resourceId: this.resourceId
118
138
  }
119
139
  });
120
140
  const eventId = eventOutput.ids[0];
@@ -150,17 +170,20 @@ var InngestRun = class extends Run {
150
170
  workflowName: this.workflowId,
151
171
  runId: this.runId
152
172
  });
173
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
174
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
153
175
  const eventOutput = await this.inngest.send({
154
176
  name: `workflow.${this.workflowId}`,
155
177
  data: {
156
- inputData: params.resumeData,
178
+ inputData: resumeDataToUse,
179
+ initialState: snapshot?.value ?? {},
157
180
  runId: this.runId,
158
181
  workflowId: this.workflowId,
159
182
  stepResults: snapshot?.context,
160
183
  resume: {
161
184
  steps,
162
185
  stepResults: snapshot?.context,
163
- resumePayload: params.resumeData,
186
+ resumePayload: resumeDataToUse,
164
187
  // @ts-ignore
165
188
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
166
189
  }
@@ -202,33 +225,9 @@ var InngestRun = class extends Run {
202
225
  }
203
226
  stream({ inputData, runtimeContext } = {}) {
204
227
  const { readable, writable } = new TransformStream();
205
- let currentToolData = void 0;
206
228
  const writer = writable.getWriter();
207
229
  const unwatch = this.watch(async (event) => {
208
- if (event.type === "workflow-agent-call-start") {
209
- currentToolData = {
210
- name: event.payload.name,
211
- args: event.payload.args
212
- };
213
- await writer.write({
214
- ...event.payload,
215
- type: "tool-call-streaming-start"
216
- });
217
- return;
218
- }
219
230
  try {
220
- if (event.type === "workflow-agent-call-finish") {
221
- return;
222
- } else if (!event.type.startsWith("workflow-")) {
223
- if (event.type === "text-delta") {
224
- await writer.write({
225
- type: "tool-call-delta",
226
- ...currentToolData ?? {},
227
- argsTextDelta: event.textDelta
228
- });
229
- }
230
- return;
231
- }
232
231
  const e = {
233
232
  ...event,
234
233
  type: event.type.replace("workflow-", "")
@@ -310,23 +309,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
310
309
  }
311
310
  }
312
311
  }
313
- createRun(options) {
314
- const runIdToUse = options?.runId || randomUUID();
315
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
316
- {
317
- workflowId: this.id,
318
- runId: runIdToUse,
319
- executionEngine: this.executionEngine,
320
- executionGraph: this.executionGraph,
321
- serializedStepGraph: this.serializedStepGraph,
322
- mastra: this.#mastra,
323
- retryConfig: this.retryConfig,
324
- cleanup: () => this.runs.delete(runIdToUse)
325
- },
326
- this.inngest
312
+ /**
313
+ * @deprecated Use createRunAsync() instead.
314
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
315
+ */
316
+ createRun(_options) {
317
+ throw new Error(
318
+ "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."
327
319
  );
328
- this.runs.set(runIdToUse, run);
329
- return run;
330
320
  }
331
321
  async createRunAsync(options) {
332
322
  const runIdToUse = options?.runId || randomUUID();
@@ -334,21 +324,28 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
334
324
  {
335
325
  workflowId: this.id,
336
326
  runId: runIdToUse,
327
+ resourceId: options?.resourceId,
337
328
  executionEngine: this.executionEngine,
338
329
  executionGraph: this.executionGraph,
339
330
  serializedStepGraph: this.serializedStepGraph,
340
331
  mastra: this.#mastra,
341
332
  retryConfig: this.retryConfig,
342
- cleanup: () => this.runs.delete(runIdToUse)
333
+ cleanup: () => this.runs.delete(runIdToUse),
334
+ workflowSteps: this.steps
343
335
  },
344
336
  this.inngest
345
337
  );
346
338
  this.runs.set(runIdToUse, run);
339
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
340
+ workflowStatus: run.workflowRunStatus,
341
+ stepResults: {}
342
+ });
347
343
  const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
348
- if (!workflowSnapshotInStorage) {
344
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
349
345
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
350
346
  workflowName: this.id,
351
347
  runId: runIdToUse,
348
+ resourceId: options?.resourceId,
352
349
  snapshot: {
353
350
  runId: runIdToUse,
354
351
  status: "pending",
@@ -382,7 +379,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
382
379
  },
383
380
  { event: `workflow.${this.id}` },
384
381
  async ({ event, step, attempt, publish }) => {
385
- let { inputData, runId, resume } = event.data;
382
+ let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
386
383
  if (!runId) {
387
384
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
388
385
  return randomUUID();
@@ -410,21 +407,32 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
410
407
  once: (_event, _callback) => {
411
408
  }
412
409
  };
413
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
410
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
414
411
  const result = await engine.execute({
415
412
  workflowId: this.id,
416
413
  runId,
414
+ resourceId,
417
415
  graph: this.executionGraph,
418
416
  serializedStepGraph: this.serializedStepGraph,
419
417
  input: inputData,
418
+ initialState,
420
419
  emitter,
421
420
  retryConfig: this.retryConfig,
422
421
  runtimeContext: new RuntimeContext(),
423
422
  // TODO
424
423
  resume,
425
424
  abortController: new AbortController(),
426
- currentSpan: void 0
425
+ currentSpan: void 0,
427
426
  // TODO: Pass actual parent AI span from workflow execution context
427
+ outputOptions
428
+ });
429
+ await step.run(`workflow.${this.id}.finalize`, async () => {
430
+ if (result.status === "failed") {
431
+ throw new NonRetriableError(`Workflow failed`, {
432
+ cause: result
433
+ });
434
+ }
435
+ return result;
428
436
  });
429
437
  return { result, runId };
430
438
  }
@@ -458,11 +466,10 @@ function createStep(params) {
458
466
  if (isAgent(params)) {
459
467
  return {
460
468
  id: params.name,
469
+ description: params.getDescription(),
461
470
  // @ts-ignore
462
471
  inputSchema: z.object({
463
472
  prompt: z.string()
464
- // resourceId: z.string().optional(),
465
- // threadId: z.string().optional(),
466
473
  }),
467
474
  // @ts-ignore
468
475
  outputSchema: z.object({
@@ -478,34 +485,66 @@ function createStep(params) {
478
485
  name: params.name,
479
486
  args: inputData
480
487
  };
481
- await emitter.emit("watch-v2", {
482
- type: "workflow-agent-call-start",
483
- payload: toolData
484
- });
485
- const { fullStream } = await params.stream(inputData.prompt, {
486
- // resourceId: inputData.resourceId,
487
- // threadId: inputData.threadId,
488
- runtimeContext,
489
- tracingContext,
490
- onFinish: (result) => {
491
- streamPromise.resolve(result.text);
492
- },
493
- abortSignal
494
- });
495
- if (abortSignal.aborted) {
496
- return abort();
497
- }
498
- for await (const chunk of fullStream) {
499
- await emitter.emit("watch-v2", chunk);
488
+ if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
489
+ const { fullStream } = await params.stream(inputData.prompt, {
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
+ await emitter.emit("watch-v2", {
501
+ type: "tool-call-streaming-start",
502
+ ...toolData ?? {}
503
+ });
504
+ for await (const chunk of fullStream) {
505
+ if (chunk.type === "text-delta") {
506
+ await emitter.emit("watch-v2", {
507
+ type: "tool-call-delta",
508
+ ...toolData ?? {},
509
+ argsTextDelta: chunk.payload.text
510
+ });
511
+ }
512
+ }
513
+ } else {
514
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
515
+ runtimeContext,
516
+ tracingContext,
517
+ onFinish: (result) => {
518
+ streamPromise.resolve(result.text);
519
+ },
520
+ abortSignal
521
+ });
522
+ if (abortSignal.aborted) {
523
+ return abort();
524
+ }
525
+ await emitter.emit("watch-v2", {
526
+ type: "tool-call-streaming-start",
527
+ ...toolData ?? {}
528
+ });
529
+ for await (const chunk of fullStream) {
530
+ if (chunk.type === "text-delta") {
531
+ await emitter.emit("watch-v2", {
532
+ type: "tool-call-delta",
533
+ ...toolData ?? {},
534
+ argsTextDelta: chunk.textDelta
535
+ });
536
+ }
537
+ }
500
538
  }
501
539
  await emitter.emit("watch-v2", {
502
- type: "workflow-agent-call-finish",
503
- payload: toolData
540
+ type: "tool-call-streaming-finish",
541
+ ...toolData ?? {}
504
542
  });
505
543
  return {
506
544
  text: await streamPromise.promise
507
545
  };
508
- }
546
+ },
547
+ component: params.component
509
548
  };
510
549
  }
511
550
  if (isTool(params)) {
@@ -516,16 +555,20 @@ function createStep(params) {
516
555
  // TODO: tool probably should have strong id type
517
556
  // @ts-ignore
518
557
  id: params.id,
558
+ description: params.description,
519
559
  inputSchema: params.inputSchema,
520
560
  outputSchema: params.outputSchema,
521
- execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
561
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
522
562
  return params.execute({
523
563
  context: inputData,
524
564
  mastra: wrapMastra(mastra, tracingContext),
525
565
  runtimeContext,
526
- tracingContext
566
+ tracingContext,
567
+ suspend,
568
+ resumeData
527
569
  });
528
- }
570
+ },
571
+ component: "TOOL"
529
572
  };
530
573
  }
531
574
  return {
@@ -541,7 +584,10 @@ function createStep(params) {
541
584
  function init(inngest) {
542
585
  return {
543
586
  createWorkflow(params) {
544
- return new InngestWorkflow(params, inngest);
587
+ return new InngestWorkflow(
588
+ params,
589
+ inngest
590
+ );
545
591
  },
546
592
  createStep,
547
593
  cloneStep(step, opts) {
@@ -550,7 +596,11 @@ function init(inngest) {
550
596
  description: step.description,
551
597
  inputSchema: step.inputSchema,
552
598
  outputSchema: step.outputSchema,
553
- execute: step.execute
599
+ resumeSchema: step.resumeSchema,
600
+ suspendSchema: step.suspendSchema,
601
+ stateSchema: step.stateSchema,
602
+ execute: step.execute,
603
+ component: step.component
554
604
  };
555
605
  },
556
606
  cloneWorkflow(workflow, opts) {
@@ -570,8 +620,8 @@ function init(inngest) {
570
620
  var InngestExecutionEngine = class extends DefaultExecutionEngine {
571
621
  inngestStep;
572
622
  inngestAttempts;
573
- constructor(mastra, inngestStep, inngestAttempts = 0) {
574
- super({ mastra });
623
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
624
+ super({ mastra, options });
575
625
  this.inngestStep = inngestStep;
576
626
  this.inngestAttempts = inngestAttempts;
577
627
  }
@@ -634,7 +684,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
634
684
  });
635
685
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
636
686
  if (stepResult?.status === "suspended") {
637
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
687
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
638
688
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
639
689
  }
640
690
  return [];
@@ -656,6 +706,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
656
706
  emitter,
657
707
  abortController,
658
708
  runtimeContext,
709
+ executionContext,
659
710
  writableStream,
660
711
  tracingContext
661
712
  }) {
@@ -666,7 +717,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
666
717
  attributes: {
667
718
  durationMs: duration,
668
719
  sleepType: fn ? "dynamic" : "fixed"
669
- }
720
+ },
721
+ tracingPolicy: this.options?.tracingPolicy
670
722
  });
671
723
  if (fn) {
672
724
  const stepCallId = randomUUID();
@@ -677,21 +729,16 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
677
729
  mastra: this.mastra,
678
730
  runtimeContext,
679
731
  inputData: prevOutput,
732
+ state: executionContext.state,
733
+ setState: (state) => {
734
+ executionContext.state = state;
735
+ },
680
736
  runCount: -1,
681
737
  tracingContext: {
682
738
  currentSpan: sleepSpan
683
739
  },
684
740
  getInitData: () => stepResults?.input,
685
- getStepResult: (step) => {
686
- if (!step?.id) {
687
- return null;
688
- }
689
- const result = stepResults[step.id];
690
- if (result?.status === "success") {
691
- return result.output;
692
- }
693
- return null;
694
- },
741
+ getStepResult: getStepResult.bind(this, stepResults),
695
742
  // TODO: this function shouldn't have suspend probably?
696
743
  suspend: async (_suspendPayload) => {
697
744
  },
@@ -701,6 +748,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
701
748
  abortController?.abort();
702
749
  },
703
750
  [EMITTER_SYMBOL]: emitter,
751
+ // TODO: add streamVNext support
752
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
704
753
  engine: { step: this.inngestStep },
705
754
  abortSignal: abortController?.signal,
706
755
  writer: new ToolStream(
@@ -737,6 +786,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
737
786
  emitter,
738
787
  abortController,
739
788
  runtimeContext,
789
+ executionContext,
740
790
  writableStream,
741
791
  tracingContext
742
792
  }) {
@@ -748,7 +798,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
748
798
  untilDate: date,
749
799
  durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
750
800
  sleepType: fn ? "dynamic" : "fixed"
751
- }
801
+ },
802
+ tracingPolicy: this.options?.tracingPolicy
752
803
  });
753
804
  if (fn) {
754
805
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
@@ -759,21 +810,16 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
759
810
  mastra: this.mastra,
760
811
  runtimeContext,
761
812
  inputData: prevOutput,
813
+ state: executionContext.state,
814
+ setState: (state) => {
815
+ executionContext.state = state;
816
+ },
762
817
  runCount: -1,
763
818
  tracingContext: {
764
819
  currentSpan: sleepUntilSpan
765
820
  },
766
821
  getInitData: () => stepResults?.input,
767
- getStepResult: (step) => {
768
- if (!step?.id) {
769
- return null;
770
- }
771
- const result = stepResults[step.id];
772
- if (result?.status === "success") {
773
- return result.output;
774
- }
775
- return null;
776
- },
822
+ getStepResult: getStepResult.bind(this, stepResults),
777
823
  // TODO: this function shouldn't have suspend probably?
778
824
  suspend: async (_suspendPayload) => {
779
825
  },
@@ -783,6 +829,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
783
829
  abortController?.abort();
784
830
  },
785
831
  [EMITTER_SYMBOL]: emitter,
832
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
833
+ // TODO: add streamVNext support
786
834
  engine: { step: this.inngestStep },
787
835
  abortSignal: abortController?.signal,
788
836
  writer: new ToolStream(
@@ -796,6 +844,9 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
796
844
  )
797
845
  });
798
846
  });
847
+ if (date && !(date instanceof Date)) {
848
+ date = new Date(date);
849
+ }
799
850
  const time = !date ? 0 : date.getTime() - Date.now();
800
851
  sleepUntilSpan?.update({
801
852
  attributes: {
@@ -844,7 +895,13 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
844
895
  input: prevOutput,
845
896
  attributes: {
846
897
  stepId: step.id
847
- }
898
+ },
899
+ tracingPolicy: this.options?.tracingPolicy
900
+ });
901
+ const { inputData, validationError } = await validateStepInput({
902
+ prevOutput,
903
+ step,
904
+ validateInputs: this.options?.validateInputs ?? false
848
905
  });
849
906
  const startedAt = await this.inngestStep.run(
850
907
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
@@ -876,7 +933,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
876
933
  payload: {
877
934
  id: step.id,
878
935
  status: "running",
879
- payload: prevOutput,
936
+ payload: inputData,
880
937
  startedAt: startedAt2
881
938
  }
882
939
  });
@@ -887,38 +944,60 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
887
944
  const isResume = !!resume?.steps?.length;
888
945
  let result;
889
946
  let runId;
890
- if (isResume) {
891
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? randomUUID();
892
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
893
- workflowName: step.id,
894
- runId
895
- });
896
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
897
- function: step.getFunction(),
898
- data: {
899
- inputData: prevOutput,
900
- runId,
901
- resume: {
947
+ try {
948
+ if (isResume) {
949
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
950
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
951
+ workflowName: step.id,
952
+ runId
953
+ });
954
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
955
+ function: step.getFunction(),
956
+ data: {
957
+ inputData,
958
+ initialState: executionContext.state ?? snapshot?.value ?? {},
902
959
  runId,
903
- steps: resume.steps.slice(1),
904
- stepResults: snapshot?.context,
905
- resumePayload: resume.resumePayload,
906
- // @ts-ignore
907
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
960
+ resume: {
961
+ runId,
962
+ steps: resume.steps.slice(1),
963
+ stepResults: snapshot?.context,
964
+ resumePayload: resume.resumePayload,
965
+ // @ts-ignore
966
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
967
+ },
968
+ outputOptions: { includeState: true }
908
969
  }
909
- }
910
- });
911
- result = invokeResp.result;
912
- runId = invokeResp.runId;
913
- } else {
914
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
915
- function: step.getFunction(),
916
- data: {
917
- inputData: prevOutput
918
- }
919
- });
920
- result = invokeResp.result;
921
- runId = invokeResp.runId;
970
+ });
971
+ result = invokeResp.result;
972
+ runId = invokeResp.runId;
973
+ executionContext.state = invokeResp.result.state;
974
+ } else {
975
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
976
+ function: step.getFunction(),
977
+ data: {
978
+ inputData,
979
+ initialState: executionContext.state ?? {},
980
+ outputOptions: { includeState: true }
981
+ }
982
+ });
983
+ result = invokeResp.result;
984
+ runId = invokeResp.runId;
985
+ executionContext.state = invokeResp.result.state;
986
+ }
987
+ } catch (e) {
988
+ const errorCause = e?.cause;
989
+ if (errorCause && typeof errorCause === "object") {
990
+ result = errorCause;
991
+ runId = errorCause.runId || randomUUID();
992
+ } else {
993
+ runId = randomUUID();
994
+ result = {
995
+ status: "failed",
996
+ error: e instanceof Error ? e : new Error(String(e)),
997
+ steps: {},
998
+ input: inputData
999
+ };
1000
+ }
922
1001
  }
923
1002
  const res = await this.inngestStep.run(
924
1003
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -957,7 +1036,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
957
1036
  return stepRes2?.status === "suspended";
958
1037
  });
959
1038
  for (const [stepName, stepResult] of suspendedSteps) {
960
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1039
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
961
1040
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
962
1041
  await emitter.emit("watch", {
963
1042
  type: "watch",
@@ -965,7 +1044,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
965
1044
  currentStep: {
966
1045
  id: step.id,
967
1046
  status: "suspended",
968
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1047
+ payload: stepResult.payload,
1048
+ suspendPayload: {
1049
+ ...stepResult?.suspendPayload,
1050
+ __workflow_meta: { runId, path: suspendPath }
1051
+ }
969
1052
  },
970
1053
  workflowState: {
971
1054
  status: "running",
@@ -987,7 +1070,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
987
1070
  executionContext,
988
1071
  result: {
989
1072
  status: "suspended",
990
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1073
+ payload: stepResult.payload,
1074
+ suspendPayload: {
1075
+ ...stepResult?.suspendPayload,
1076
+ __workflow_meta: { runId, path: suspendPath }
1077
+ }
991
1078
  }
992
1079
  };
993
1080
  }
@@ -1052,158 +1139,193 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1052
1139
  }
1053
1140
  );
1054
1141
  Object.assign(executionContext, res.executionContext);
1055
- return res.result;
1142
+ return {
1143
+ ...res.result,
1144
+ startedAt,
1145
+ endedAt: Date.now(),
1146
+ payload: inputData,
1147
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1148
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1149
+ };
1056
1150
  }
1057
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1058
- let execResults;
1059
- let suspended;
1060
- let bailed;
1061
- try {
1062
- const result = await step.execute({
1063
- runId: executionContext.runId,
1064
- mastra: this.mastra,
1065
- runtimeContext,
1066
- writableStream,
1067
- inputData: prevOutput,
1068
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1069
- tracingContext: {
1070
- currentSpan: stepAISpan
1071
- },
1072
- getInitData: () => stepResults?.input,
1073
- getStepResult: (step2) => {
1074
- const result2 = stepResults[step2.id];
1075
- if (result2?.status === "success") {
1076
- return result2.output;
1151
+ let stepRes;
1152
+ try {
1153
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1154
+ let execResults;
1155
+ let suspended;
1156
+ let bailed;
1157
+ try {
1158
+ if (validationError) {
1159
+ throw validationError;
1160
+ }
1161
+ const result = await step.execute({
1162
+ runId: executionContext.runId,
1163
+ mastra: this.mastra,
1164
+ runtimeContext,
1165
+ writableStream,
1166
+ state: executionContext?.state ?? {},
1167
+ setState: (state) => {
1168
+ executionContext.state = state;
1169
+ },
1170
+ inputData,
1171
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1172
+ tracingContext: {
1173
+ currentSpan: stepAISpan
1174
+ },
1175
+ getInitData: () => stepResults?.input,
1176
+ getStepResult: getStepResult.bind(this, stepResults),
1177
+ suspend: async (suspendPayload) => {
1178
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1179
+ suspended = { payload: suspendPayload };
1180
+ },
1181
+ bail: (result2) => {
1182
+ bailed = { payload: result2 };
1183
+ },
1184
+ resume: {
1185
+ steps: resume?.steps?.slice(1) || [],
1186
+ resumePayload: resume?.resumePayload,
1187
+ // @ts-ignore
1188
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1189
+ },
1190
+ [EMITTER_SYMBOL]: emitter,
1191
+ engine: {
1192
+ step: this.inngestStep
1193
+ },
1194
+ abortSignal: abortController.signal
1195
+ });
1196
+ const endedAt = Date.now();
1197
+ execResults = {
1198
+ status: "success",
1199
+ output: result,
1200
+ startedAt,
1201
+ endedAt,
1202
+ payload: inputData,
1203
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1204
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1205
+ };
1206
+ } catch (e) {
1207
+ const stepFailure = {
1208
+ status: "failed",
1209
+ payload: inputData,
1210
+ error: e instanceof Error ? e.message : String(e),
1211
+ endedAt: Date.now(),
1212
+ startedAt,
1213
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1214
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1215
+ };
1216
+ execResults = stepFailure;
1217
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1218
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1219
+ throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1220
+ cause: execResults
1221
+ });
1222
+ }
1223
+ if (suspended) {
1224
+ execResults = {
1225
+ status: "suspended",
1226
+ suspendPayload: suspended.payload,
1227
+ payload: inputData,
1228
+ suspendedAt: Date.now(),
1229
+ startedAt,
1230
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1231
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1232
+ };
1233
+ } else if (bailed) {
1234
+ execResults = {
1235
+ status: "bailed",
1236
+ output: bailed.payload,
1237
+ payload: inputData,
1238
+ endedAt: Date.now(),
1239
+ startedAt
1240
+ };
1241
+ }
1242
+ await emitter.emit("watch", {
1243
+ type: "watch",
1244
+ payload: {
1245
+ currentStep: {
1246
+ id: step.id,
1247
+ ...execResults
1248
+ },
1249
+ workflowState: {
1250
+ status: "running",
1251
+ steps: { ...stepResults, [step.id]: execResults },
1252
+ result: null,
1253
+ error: null
1077
1254
  }
1078
- return null;
1079
- },
1080
- suspend: async (suspendPayload) => {
1081
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1082
- suspended = { payload: suspendPayload };
1083
1255
  },
1084
- bail: (result2) => {
1085
- bailed = { payload: result2 };
1086
- },
1087
- resume: {
1088
- steps: resume?.steps?.slice(1) || [],
1089
- resumePayload: resume?.resumePayload,
1090
- // @ts-ignore
1091
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1092
- },
1093
- [EMITTER_SYMBOL]: emitter,
1094
- engine: {
1095
- step: this.inngestStep
1096
- },
1097
- abortSignal: abortController.signal
1256
+ eventTimestamp: Date.now()
1098
1257
  });
1099
- const endedAt = Date.now();
1100
- execResults = {
1101
- status: "success",
1102
- output: result,
1103
- startedAt,
1104
- endedAt,
1105
- payload: prevOutput,
1106
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1107
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1108
- };
1109
- } catch (e) {
1110
- execResults = {
1111
- status: "failed",
1112
- payload: prevOutput,
1113
- error: e instanceof Error ? e.message : String(e),
1114
- endedAt: Date.now(),
1115
- startedAt,
1116
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1117
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1118
- };
1119
- }
1120
- if (suspended) {
1121
- execResults = {
1122
- status: "suspended",
1123
- suspendedPayload: suspended.payload,
1124
- payload: prevOutput,
1125
- suspendedAt: Date.now(),
1126
- startedAt,
1127
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1128
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1129
- };
1130
- } else if (bailed) {
1131
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1132
- }
1133
- if (execResults.status === "failed") {
1134
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1135
- const error = new Error(execResults.error);
1136
- stepAISpan?.error({ error });
1137
- throw error;
1258
+ if (execResults.status === "suspended") {
1259
+ await emitter.emit("watch-v2", {
1260
+ type: "workflow-step-suspended",
1261
+ payload: {
1262
+ id: step.id,
1263
+ ...execResults
1264
+ }
1265
+ });
1266
+ } else {
1267
+ await emitter.emit("watch-v2", {
1268
+ type: "workflow-step-result",
1269
+ payload: {
1270
+ id: step.id,
1271
+ ...execResults
1272
+ }
1273
+ });
1274
+ await emitter.emit("watch-v2", {
1275
+ type: "workflow-step-finish",
1276
+ payload: {
1277
+ id: step.id,
1278
+ metadata: {}
1279
+ }
1280
+ });
1138
1281
  }
1139
- }
1140
- await emitter.emit("watch", {
1141
- type: "watch",
1142
- payload: {
1143
- currentStep: {
1144
- id: step.id,
1145
- ...execResults
1146
- },
1147
- workflowState: {
1148
- status: "running",
1149
- steps: { ...stepResults, [step.id]: execResults },
1150
- result: null,
1151
- error: null
1152
- }
1153
- },
1154
- eventTimestamp: Date.now()
1282
+ stepAISpan?.end({ output: execResults });
1283
+ return { result: execResults, executionContext, stepResults };
1155
1284
  });
1156
- if (execResults.status === "suspended") {
1157
- await emitter.emit("watch-v2", {
1158
- type: "workflow-step-suspended",
1159
- payload: {
1160
- id: step.id,
1161
- ...execResults
1162
- }
1163
- });
1164
- } else {
1165
- await emitter.emit("watch-v2", {
1166
- type: "workflow-step-result",
1167
- payload: {
1168
- id: step.id,
1169
- ...execResults
1170
- }
1171
- });
1172
- await emitter.emit("watch-v2", {
1173
- type: "workflow-step-finish",
1174
- payload: {
1175
- id: step.id,
1176
- metadata: {}
1177
- }
1178
- });
1179
- }
1180
- stepAISpan?.end({ output: execResults });
1181
- return { result: execResults, executionContext, stepResults };
1182
- });
1183
- if (disableScorers !== false) {
1285
+ } catch (e) {
1286
+ const stepFailure = e instanceof Error ? e?.cause : {
1287
+ status: "failed",
1288
+ error: e instanceof Error ? e.message : String(e),
1289
+ payload: inputData,
1290
+ startedAt,
1291
+ endedAt: Date.now()
1292
+ };
1293
+ stepRes = {
1294
+ result: stepFailure,
1295
+ executionContext,
1296
+ stepResults: {
1297
+ ...stepResults,
1298
+ [step.id]: stepFailure
1299
+ }
1300
+ };
1301
+ }
1302
+ if (disableScorers !== false && stepRes.result.status === "success") {
1184
1303
  await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1185
1304
  if (step.scorers) {
1186
1305
  await this.runScorers({
1187
1306
  scorers: step.scorers,
1188
1307
  runId: executionContext.runId,
1189
- input: prevOutput,
1308
+ input: inputData,
1190
1309
  output: stepRes.result,
1191
1310
  workflowId: executionContext.workflowId,
1192
1311
  stepId: step.id,
1193
1312
  runtimeContext,
1194
- disableScorers
1313
+ disableScorers,
1314
+ tracingContext: { currentSpan: stepAISpan }
1195
1315
  });
1196
1316
  }
1197
1317
  });
1198
1318
  }
1199
1319
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1200
1320
  Object.assign(stepResults, stepRes.stepResults);
1321
+ executionContext.state = stepRes.executionContext.state;
1201
1322
  return stepRes.result;
1202
1323
  }
1203
1324
  async persistStepUpdate({
1204
1325
  workflowId,
1205
1326
  runId,
1206
1327
  stepResults,
1328
+ resourceId,
1207
1329
  executionContext,
1208
1330
  serializedStepGraph,
1209
1331
  workflowStatus,
@@ -1213,12 +1335,17 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1213
1335
  await this.inngestStep.run(
1214
1336
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1215
1337
  async () => {
1338
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1339
+ if (!shouldPersistSnapshot) {
1340
+ return;
1341
+ }
1216
1342
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1217
1343
  workflowName: workflowId,
1218
1344
  runId,
1345
+ resourceId,
1219
1346
  snapshot: {
1220
1347
  runId,
1221
- value: {},
1348
+ value: executionContext.state,
1222
1349
  context: stepResults,
1223
1350
  activePaths: [],
1224
1351
  suspendedPaths: executionContext.suspendedPaths,
@@ -1253,11 +1380,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1253
1380
  }) {
1254
1381
  const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1255
1382
  type: AISpanType.WORKFLOW_CONDITIONAL,
1256
- name: `conditional: ${entry.conditions.length} conditions`,
1383
+ name: `conditional: '${entry.conditions.length} conditions'`,
1257
1384
  input: prevOutput,
1258
1385
  attributes: {
1259
1386
  conditionCount: entry.conditions.length
1260
- }
1387
+ },
1388
+ tracingPolicy: this.options?.tracingPolicy
1261
1389
  });
1262
1390
  let execResults;
1263
1391
  const truthyIndexes = (await Promise.all(
@@ -1265,11 +1393,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1265
1393
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1266
1394
  const evalSpan = conditionalSpan?.createChildSpan({
1267
1395
  type: AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1268
- name: `condition ${index}`,
1396
+ name: `condition: '${index}'`,
1269
1397
  input: prevOutput,
1270
1398
  attributes: {
1271
1399
  conditionIndex: index
1272
- }
1400
+ },
1401
+ tracingPolicy: this.options?.tracingPolicy
1273
1402
  });
1274
1403
  try {
1275
1404
  const result = await cond({
@@ -1279,20 +1408,15 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1279
1408
  runtimeContext,
1280
1409
  runCount: -1,
1281
1410
  inputData: prevOutput,
1411
+ state: executionContext.state,
1412
+ setState: (state) => {
1413
+ executionContext.state = state;
1414
+ },
1282
1415
  tracingContext: {
1283
1416
  currentSpan: evalSpan
1284
1417
  },
1285
1418
  getInitData: () => stepResults?.input,
1286
- getStepResult: (step) => {
1287
- if (!step?.id) {
1288
- return null;
1289
- }
1290
- const result2 = stepResults[step.id];
1291
- if (result2?.status === "success") {
1292
- return result2.output;
1293
- }
1294
- return null;
1295
- },
1419
+ getStepResult: getStepResult.bind(this, stepResults),
1296
1420
  // TODO: this function shouldn't have suspend probably?
1297
1421
  suspend: async (_suspendPayload) => {
1298
1422
  },
@@ -1302,6 +1426,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1302
1426
  abortController.abort();
1303
1427
  },
1304
1428
  [EMITTER_SYMBOL]: emitter,
1429
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1430
+ // TODO: add streamVNext support
1305
1431
  engine: {
1306
1432
  step: this.inngestStep
1307
1433
  },
@@ -1358,7 +1484,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1358
1484
  executionPath: [...executionContext.executionPath, index],
1359
1485
  suspendedPaths: executionContext.suspendedPaths,
1360
1486
  retryConfig: executionContext.retryConfig,
1361
- executionSpan: executionContext.executionSpan
1487
+ executionSpan: executionContext.executionSpan,
1488
+ state: executionContext.state
1362
1489
  },
1363
1490
  emitter,
1364
1491
  abortController,
@@ -1376,7 +1503,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1376
1503
  if (hasFailed) {
1377
1504
  execResults = { status: "failed", error: hasFailed.result.error };
1378
1505
  } else if (hasSuspended) {
1379
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1506
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1380
1507
  } else {
1381
1508
  execResults = {
1382
1509
  status: "success",