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