@mastra/inngest 0.0.0-break-rename-vnext-legacy-20250926163953 → 0.0.0-bundle-recursion-20251030002519

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
@@ -1,10 +1,13 @@
1
1
  import { randomUUID } from 'crypto';
2
+ import { ReadableStream } from 'stream/web';
2
3
  import { subscribe } from '@inngest/realtime';
3
4
  import { wrapMastra, AISpanType } from '@mastra/core/ai-tracing';
4
5
  import { RuntimeContext } from '@mastra/core/di';
6
+ import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
5
7
  import { ToolStream, Tool } from '@mastra/core/tools';
6
- import { Run, Workflow, DefaultExecutionEngine, getStepResult, validateStepInput } from '@mastra/core/workflows';
8
+ import { Run, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput } from '@mastra/core/workflows';
7
9
  import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
10
+ import { NonRetriableError, RetryAfterError } from 'inngest';
8
11
  import { serve as serve$1 } from 'inngest/hono';
9
12
  import { z } from 'zod';
10
13
 
@@ -58,8 +61,15 @@ var InngestRun = class extends Run {
58
61
  await new Promise((resolve) => setTimeout(resolve, 1e3));
59
62
  runs = await this.getRuns(eventId);
60
63
  if (runs?.[0]?.status === "Failed") {
61
- throw new Error(`Function run ${runs?.[0]?.status}`);
62
- } 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") {
63
73
  const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
64
74
  workflowName: this.workflowId,
65
75
  runId: this.runId
@@ -98,8 +108,15 @@ var InngestRun = class extends Run {
98
108
  });
99
109
  }
100
110
  }
101
- async start({
102
- inputData
111
+ async start(params) {
112
+ return this._start(params);
113
+ }
114
+ async _start({
115
+ inputData,
116
+ initialState,
117
+ outputOptions,
118
+ tracingOptions,
119
+ format
103
120
  }) {
104
121
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
105
122
  workflowName: this.workflowId,
@@ -112,18 +129,24 @@ var InngestRun = class extends Run {
112
129
  context: {},
113
130
  activePaths: [],
114
131
  suspendedPaths: {},
132
+ resumeLabels: {},
115
133
  waitingPaths: {},
116
134
  timestamp: Date.now(),
117
135
  status: "running"
118
136
  }
119
137
  });
120
138
  const inputDataToUse = await this._validateInput(inputData);
139
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
121
140
  const eventOutput = await this.inngest.send({
122
141
  name: `workflow.${this.workflowId}`,
123
142
  data: {
124
143
  inputData: inputDataToUse,
144
+ initialState: initialStateToUse,
125
145
  runId: this.runId,
126
- resourceId: this.resourceId
146
+ resourceId: this.resourceId,
147
+ outputOptions,
148
+ tracingOptions,
149
+ format
127
150
  }
128
151
  });
129
152
  const eventId = eventOutput.ids[0];
@@ -165,6 +188,7 @@ var InngestRun = class extends Run {
165
188
  name: `workflow.${this.workflowId}`,
166
189
  data: {
167
190
  inputData: resumeDataToUse,
191
+ initialState: snapshot?.value ?? {},
168
192
  runId: this.runId,
169
193
  workflowId: this.workflowId,
170
194
  stepResults: snapshot?.context,
@@ -211,20 +235,35 @@ var InngestRun = class extends Run {
211
235
  });
212
236
  };
213
237
  }
214
- stream({ inputData, runtimeContext } = {}) {
238
+ streamLegacy({ inputData, runtimeContext } = {}) {
215
239
  const { readable, writable } = new TransformStream();
216
240
  const writer = writable.getWriter();
217
241
  const unwatch = this.watch(async (event) => {
218
242
  try {
243
+ await writer.write({
244
+ // @ts-ignore
245
+ type: "start",
246
+ // @ts-ignore
247
+ payload: { runId: this.runId }
248
+ });
219
249
  const e = {
220
250
  ...event,
221
251
  type: event.type.replace("workflow-", "")
222
252
  };
253
+ if (e.type === "step-output") {
254
+ e.type = e.payload.output.type;
255
+ e.payload = e.payload.output.payload;
256
+ }
223
257
  await writer.write(e);
224
258
  } catch {
225
259
  }
226
260
  }, "watch-v2");
227
261
  this.closeStreamAction = async () => {
262
+ await writer.write({
263
+ type: "finish",
264
+ // @ts-ignore
265
+ payload: { runId: this.runId }
266
+ });
228
267
  unwatch();
229
268
  try {
230
269
  await writer.close();
@@ -234,7 +273,7 @@ var InngestRun = class extends Run {
234
273
  writer.releaseLock();
235
274
  }
236
275
  };
237
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
276
+ this.executionResults = this._start({ inputData, runtimeContext, format: "legacy" }).then((result) => {
238
277
  if (result.status !== "suspended") {
239
278
  this.closeStreamAction?.().catch(() => {
240
279
  });
@@ -246,6 +285,82 @@ var InngestRun = class extends Run {
246
285
  getWorkflowState: () => this.executionResults
247
286
  };
248
287
  }
288
+ stream({
289
+ inputData,
290
+ runtimeContext,
291
+ tracingOptions,
292
+ closeOnSuspend = true,
293
+ initialState,
294
+ outputOptions
295
+ } = {}) {
296
+ if (this.closeStreamAction && this.streamOutput) {
297
+ return this.streamOutput;
298
+ }
299
+ this.closeStreamAction = async () => {
300
+ };
301
+ const self = this;
302
+ const stream = new ReadableStream({
303
+ async start(controller) {
304
+ const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
305
+ controller.enqueue({
306
+ type,
307
+ runId: self.runId,
308
+ from,
309
+ payload: {
310
+ stepName: payload?.id,
311
+ ...payload
312
+ }
313
+ });
314
+ }, "watch-v2");
315
+ self.closeStreamAction = async () => {
316
+ unwatch();
317
+ try {
318
+ await controller.close();
319
+ } catch (err) {
320
+ console.error("Error closing stream:", err);
321
+ }
322
+ };
323
+ const executionResultsPromise = self._start({
324
+ inputData,
325
+ runtimeContext,
326
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
327
+ initialState,
328
+ tracingOptions,
329
+ outputOptions,
330
+ format: "vnext"
331
+ });
332
+ let executionResults;
333
+ try {
334
+ executionResults = await executionResultsPromise;
335
+ if (closeOnSuspend) {
336
+ self.closeStreamAction?.().catch(() => {
337
+ });
338
+ } else if (executionResults.status !== "suspended") {
339
+ self.closeStreamAction?.().catch(() => {
340
+ });
341
+ }
342
+ if (self.streamOutput) {
343
+ self.streamOutput.updateResults(
344
+ executionResults
345
+ );
346
+ }
347
+ } catch (err) {
348
+ self.streamOutput?.rejectResults(err);
349
+ self.closeStreamAction?.().catch(() => {
350
+ });
351
+ }
352
+ }
353
+ });
354
+ this.streamOutput = new WorkflowRunOutput({
355
+ runId: this.runId,
356
+ workflowId: this.workflowId,
357
+ stream
358
+ });
359
+ return this.streamOutput;
360
+ }
361
+ streamVNext(args = {}) {
362
+ return this.stream(args);
363
+ }
249
364
  };
250
365
  var InngestWorkflow = class _InngestWorkflow extends Workflow {
251
366
  #mastra;
@@ -324,8 +439,12 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
324
439
  this.inngest
325
440
  );
326
441
  this.runs.set(runIdToUse, run);
442
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
443
+ workflowStatus: run.workflowRunStatus,
444
+ stepResults: {}
445
+ });
327
446
  const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
328
- if (!workflowSnapshotInStorage) {
447
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
329
448
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
330
449
  workflowName: this.id,
331
450
  runId: runIdToUse,
@@ -339,6 +458,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
339
458
  waitingPaths: {},
340
459
  serializedStepGraph: this.serializedStepGraph,
341
460
  suspendedPaths: {},
461
+ resumeLabels: {},
342
462
  result: void 0,
343
463
  error: void 0,
344
464
  // @ts-ignore
@@ -363,7 +483,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
363
483
  },
364
484
  { event: `workflow.${this.id}` },
365
485
  async ({ event, step, attempt, publish }) => {
366
- let { inputData, runId, resourceId, resume } = event.data;
486
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
367
487
  if (!runId) {
368
488
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
369
489
  return randomUUID();
@@ -391,7 +511,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
391
511
  once: (_event, _callback) => {
392
512
  }
393
513
  };
394
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
514
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
395
515
  const result = await engine.execute({
396
516
  workflowId: this.id,
397
517
  runId,
@@ -399,14 +519,30 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
399
519
  graph: this.executionGraph,
400
520
  serializedStepGraph: this.serializedStepGraph,
401
521
  input: inputData,
522
+ initialState,
402
523
  emitter,
403
524
  retryConfig: this.retryConfig,
404
525
  runtimeContext: new RuntimeContext(),
405
526
  // TODO
406
527
  resume,
528
+ format,
407
529
  abortController: new AbortController(),
408
- currentSpan: void 0
409
- // TODO: Pass actual parent AI span from workflow execution context
530
+ // currentSpan: undefined, // TODO: Pass actual parent AI span from workflow execution context
531
+ outputOptions,
532
+ writableStream: new WritableStream({
533
+ write(chunk) {
534
+ void emitter.emit("watch-v2", chunk).catch(() => {
535
+ });
536
+ }
537
+ })
538
+ });
539
+ await step.run(`workflow.${this.id}.finalize`, async () => {
540
+ if (result.status === "failed") {
541
+ throw new NonRetriableError(`Workflow failed`, {
542
+ cause: result
543
+ });
544
+ }
545
+ return result;
410
546
  });
411
547
  return { result, runId };
412
548
  }
@@ -436,7 +572,7 @@ function isAgent(params) {
436
572
  function isTool(params) {
437
573
  return params instanceof Tool;
438
574
  }
439
- function createStep(params) {
575
+ function createStep(params, agentOptions) {
440
576
  if (isAgent(params)) {
441
577
  return {
442
578
  id: params.name,
@@ -444,12 +580,23 @@ function createStep(params) {
444
580
  // @ts-ignore
445
581
  inputSchema: z.object({
446
582
  prompt: z.string()
583
+ // resourceId: z.string().optional(),
584
+ // threadId: z.string().optional(),
447
585
  }),
448
586
  // @ts-ignore
449
587
  outputSchema: z.object({
450
588
  text: z.string()
451
589
  }),
452
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
590
+ execute: async ({
591
+ inputData,
592
+ [EMITTER_SYMBOL]: emitter,
593
+ [STREAM_FORMAT_SYMBOL]: streamFormat,
594
+ runtimeContext,
595
+ tracingContext,
596
+ abortSignal,
597
+ abort,
598
+ writer
599
+ }) => {
453
600
  let streamPromise = {};
454
601
  streamPromise.promise = new Promise((resolve, reject) => {
455
602
  streamPromise.resolve = resolve;
@@ -459,34 +606,60 @@ function createStep(params) {
459
606
  name: params.name,
460
607
  args: inputData
461
608
  };
462
- const { fullStream } = await params.stream(inputData.prompt, {
463
- runtimeContext,
464
- tracingContext,
465
- onFinish: (result) => {
466
- streamPromise.resolve(result.text);
467
- },
468
- abortSignal
469
- });
470
- if (abortSignal.aborted) {
471
- return abort();
609
+ let stream;
610
+ if ((await params.getModel()).specificationVersion === "v1") {
611
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
612
+ ...agentOptions ?? {},
613
+ // resourceId: inputData.resourceId,
614
+ // threadId: inputData.threadId,
615
+ runtimeContext,
616
+ tracingContext,
617
+ onFinish: (result) => {
618
+ streamPromise.resolve(result.text);
619
+ void agentOptions?.onFinish?.(result);
620
+ },
621
+ abortSignal
622
+ });
623
+ stream = fullStream;
624
+ } else {
625
+ const modelOutput = await params.stream(inputData.prompt, {
626
+ ...agentOptions ?? {},
627
+ runtimeContext,
628
+ tracingContext,
629
+ onFinish: (result) => {
630
+ streamPromise.resolve(result.text);
631
+ void agentOptions?.onFinish?.(result);
632
+ },
633
+ abortSignal
634
+ });
635
+ stream = modelOutput.fullStream;
472
636
  }
473
- await emitter.emit("watch-v2", {
474
- type: "tool-call-streaming-start",
475
- ...toolData ?? {}
476
- });
477
- for await (const chunk of fullStream) {
478
- if (chunk.type === "text-delta") {
479
- await emitter.emit("watch-v2", {
480
- type: "tool-call-delta",
481
- ...toolData ?? {},
482
- argsTextDelta: chunk.payload.text
483
- });
637
+ if (streamFormat === "legacy") {
638
+ await emitter.emit("watch-v2", {
639
+ type: "tool-call-streaming-start",
640
+ ...toolData ?? {}
641
+ });
642
+ for await (const chunk of stream) {
643
+ if (chunk.type === "text-delta") {
644
+ await emitter.emit("watch-v2", {
645
+ type: "tool-call-delta",
646
+ ...toolData ?? {},
647
+ argsTextDelta: chunk.textDelta
648
+ });
649
+ }
650
+ }
651
+ await emitter.emit("watch-v2", {
652
+ type: "tool-call-streaming-finish",
653
+ ...toolData ?? {}
654
+ });
655
+ } else {
656
+ for await (const chunk of stream) {
657
+ await writer.write(chunk);
484
658
  }
485
659
  }
486
- await emitter.emit("watch-v2", {
487
- type: "tool-call-streaming-finish",
488
- ...toolData ?? {}
489
- });
660
+ if (abortSignal.aborted) {
661
+ return abort();
662
+ }
490
663
  return {
491
664
  text: await streamPromise.promise
492
665
  };
@@ -531,7 +704,10 @@ function createStep(params) {
531
704
  function init(inngest) {
532
705
  return {
533
706
  createWorkflow(params) {
534
- return new InngestWorkflow(params, inngest);
707
+ return new InngestWorkflow(
708
+ params,
709
+ inngest
710
+ );
535
711
  },
536
712
  createStep,
537
713
  cloneStep(step, opts) {
@@ -540,6 +716,9 @@ function init(inngest) {
540
716
  description: step.description,
541
717
  inputSchema: step.inputSchema,
542
718
  outputSchema: step.outputSchema,
719
+ resumeSchema: step.resumeSchema,
720
+ suspendSchema: step.suspendSchema,
721
+ stateSchema: step.stateSchema,
543
722
  execute: step.execute,
544
723
  component: step.component
545
724
  };
@@ -566,19 +745,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
566
745
  this.inngestStep = inngestStep;
567
746
  this.inngestAttempts = inngestAttempts;
568
747
  }
569
- async execute(params) {
570
- await params.emitter.emit("watch-v2", {
571
- type: "workflow-start",
572
- payload: { runId: params.runId }
573
- });
574
- const result = await super.execute(params);
575
- await params.emitter.emit("watch-v2", {
576
- type: "workflow-finish",
577
- payload: { runId: params.runId }
578
- });
579
- return result;
580
- }
581
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
748
+ async fmtReturnValue(emitter, stepResults, lastOutput, error) {
582
749
  const base = {
583
750
  status: lastOutput.status,
584
751
  steps: stepResults
@@ -625,14 +792,13 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
625
792
  });
626
793
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
627
794
  if (stepResult?.status === "suspended") {
628
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
795
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
629
796
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
630
797
  }
631
798
  return [];
632
799
  });
633
800
  base.suspended = suspendedStepIds;
634
801
  }
635
- executionSpan?.end();
636
802
  return base;
637
803
  }
638
804
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
@@ -664,41 +830,54 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
664
830
  if (fn) {
665
831
  const stepCallId = randomUUID();
666
832
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
667
- return await fn({
668
- runId,
669
- workflowId,
670
- mastra: this.mastra,
671
- runtimeContext,
672
- inputData: prevOutput,
673
- runCount: -1,
674
- tracingContext: {
675
- currentSpan: sleepSpan
676
- },
677
- getInitData: () => stepResults?.input,
678
- getStepResult: getStepResult.bind(this, stepResults),
679
- // TODO: this function shouldn't have suspend probably?
680
- suspend: async (_suspendPayload) => {
681
- },
682
- bail: () => {
683
- },
684
- abort: () => {
685
- abortController?.abort();
686
- },
687
- [EMITTER_SYMBOL]: emitter,
688
- // TODO: add streamVNext support
689
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
690
- engine: { step: this.inngestStep },
691
- abortSignal: abortController?.signal,
692
- writer: new ToolStream(
833
+ return await fn(
834
+ createDeprecationProxy(
693
835
  {
694
- prefix: "workflow-step",
695
- callId: stepCallId,
696
- name: "sleep",
697
- runId
836
+ runId,
837
+ workflowId,
838
+ mastra: this.mastra,
839
+ runtimeContext,
840
+ inputData: prevOutput,
841
+ state: executionContext.state,
842
+ setState: (state) => {
843
+ executionContext.state = state;
844
+ },
845
+ runCount: -1,
846
+ retryCount: -1,
847
+ tracingContext: {
848
+ currentSpan: sleepSpan
849
+ },
850
+ getInitData: () => stepResults?.input,
851
+ getStepResult: getStepResult.bind(this, stepResults),
852
+ // TODO: this function shouldn't have suspend probably?
853
+ suspend: async (_suspendPayload) => {
854
+ },
855
+ bail: () => {
856
+ },
857
+ abort: () => {
858
+ abortController?.abort();
859
+ },
860
+ [EMITTER_SYMBOL]: emitter,
861
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
862
+ engine: { step: this.inngestStep },
863
+ abortSignal: abortController?.signal,
864
+ writer: new ToolStream(
865
+ {
866
+ prefix: "workflow-step",
867
+ callId: stepCallId,
868
+ name: "sleep",
869
+ runId
870
+ },
871
+ writableStream
872
+ )
698
873
  },
699
- writableStream
874
+ {
875
+ paramName: "runCount",
876
+ deprecationMessage: runCountDeprecationMessage,
877
+ logger: this.logger
878
+ }
700
879
  )
701
- });
880
+ );
702
881
  });
703
882
  sleepSpan?.update({
704
883
  attributes: {
@@ -741,41 +920,54 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
741
920
  if (fn) {
742
921
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
743
922
  const stepCallId = randomUUID();
744
- return await fn({
745
- runId,
746
- workflowId,
747
- mastra: this.mastra,
748
- runtimeContext,
749
- inputData: prevOutput,
750
- runCount: -1,
751
- tracingContext: {
752
- currentSpan: sleepUntilSpan
753
- },
754
- getInitData: () => stepResults?.input,
755
- getStepResult: getStepResult.bind(this, stepResults),
756
- // TODO: this function shouldn't have suspend probably?
757
- suspend: async (_suspendPayload) => {
758
- },
759
- bail: () => {
760
- },
761
- abort: () => {
762
- abortController?.abort();
763
- },
764
- [EMITTER_SYMBOL]: emitter,
765
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
766
- // TODO: add streamVNext support
767
- engine: { step: this.inngestStep },
768
- abortSignal: abortController?.signal,
769
- writer: new ToolStream(
923
+ return await fn(
924
+ createDeprecationProxy(
770
925
  {
771
- prefix: "workflow-step",
772
- callId: stepCallId,
773
- name: "sleep",
774
- runId
926
+ runId,
927
+ workflowId,
928
+ mastra: this.mastra,
929
+ runtimeContext,
930
+ inputData: prevOutput,
931
+ state: executionContext.state,
932
+ setState: (state) => {
933
+ executionContext.state = state;
934
+ },
935
+ runCount: -1,
936
+ retryCount: -1,
937
+ tracingContext: {
938
+ currentSpan: sleepUntilSpan
939
+ },
940
+ getInitData: () => stepResults?.input,
941
+ getStepResult: getStepResult.bind(this, stepResults),
942
+ // TODO: this function shouldn't have suspend probably?
943
+ suspend: async (_suspendPayload) => {
944
+ },
945
+ bail: () => {
946
+ },
947
+ abort: () => {
948
+ abortController?.abort();
949
+ },
950
+ [EMITTER_SYMBOL]: emitter,
951
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
952
+ engine: { step: this.inngestStep },
953
+ abortSignal: abortController?.signal,
954
+ writer: new ToolStream(
955
+ {
956
+ prefix: "workflow-step",
957
+ callId: stepCallId,
958
+ name: "sleep",
959
+ runId
960
+ },
961
+ writableStream
962
+ )
775
963
  },
776
- writableStream
964
+ {
965
+ paramName: "runCount",
966
+ deprecationMessage: runCountDeprecationMessage,
967
+ logger: this.logger
968
+ }
777
969
  )
778
- });
970
+ );
779
971
  });
780
972
  if (date && !(date instanceof Date)) {
781
973
  date = new Date(date);
@@ -877,38 +1069,60 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
877
1069
  const isResume = !!resume?.steps?.length;
878
1070
  let result;
879
1071
  let runId;
880
- if (isResume) {
881
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? randomUUID();
882
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
883
- workflowName: step.id,
884
- runId
885
- });
886
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
887
- function: step.getFunction(),
888
- data: {
889
- inputData,
890
- runId,
891
- resume: {
1072
+ try {
1073
+ if (isResume) {
1074
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
1075
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1076
+ workflowName: step.id,
1077
+ runId
1078
+ });
1079
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1080
+ function: step.getFunction(),
1081
+ data: {
1082
+ inputData,
1083
+ initialState: executionContext.state ?? snapshot?.value ?? {},
892
1084
  runId,
893
- steps: resume.steps.slice(1),
894
- stepResults: snapshot?.context,
895
- resumePayload: resume.resumePayload,
896
- // @ts-ignore
897
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1085
+ resume: {
1086
+ runId,
1087
+ steps: resume.steps.slice(1),
1088
+ stepResults: snapshot?.context,
1089
+ resumePayload: resume.resumePayload,
1090
+ // @ts-ignore
1091
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1092
+ },
1093
+ outputOptions: { includeState: true }
898
1094
  }
899
- }
900
- });
901
- result = invokeResp.result;
902
- runId = invokeResp.runId;
903
- } else {
904
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
905
- function: step.getFunction(),
906
- data: {
907
- inputData
908
- }
909
- });
910
- result = invokeResp.result;
911
- runId = invokeResp.runId;
1095
+ });
1096
+ result = invokeResp.result;
1097
+ runId = invokeResp.runId;
1098
+ executionContext.state = invokeResp.result.state;
1099
+ } else {
1100
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1101
+ function: step.getFunction(),
1102
+ data: {
1103
+ inputData,
1104
+ initialState: executionContext.state ?? {},
1105
+ outputOptions: { includeState: true }
1106
+ }
1107
+ });
1108
+ result = invokeResp.result;
1109
+ runId = invokeResp.runId;
1110
+ executionContext.state = invokeResp.result.state;
1111
+ }
1112
+ } catch (e) {
1113
+ const errorCause = e?.cause;
1114
+ if (errorCause && typeof errorCause === "object") {
1115
+ result = errorCause;
1116
+ runId = errorCause.runId || randomUUID();
1117
+ } else {
1118
+ runId = randomUUID();
1119
+ result = {
1120
+ status: "failed",
1121
+ error: e instanceof Error ? e : new Error(String(e)),
1122
+ steps: {},
1123
+ input: inputData
1124
+ };
1125
+ }
912
1126
  }
913
1127
  const res = await this.inngestStep.run(
914
1128
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -947,7 +1161,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
947
1161
  return stepRes2?.status === "suspended";
948
1162
  });
949
1163
  for (const [stepName, stepResult] of suspendedSteps) {
950
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1164
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
951
1165
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
952
1166
  await emitter.emit("watch", {
953
1167
  type: "watch",
@@ -955,7 +1169,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
955
1169
  currentStep: {
956
1170
  id: step.id,
957
1171
  status: "suspended",
958
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1172
+ payload: stepResult.payload,
1173
+ suspendPayload: {
1174
+ ...stepResult?.suspendPayload,
1175
+ __workflow_meta: { runId, path: suspendPath }
1176
+ }
959
1177
  },
960
1178
  workflowState: {
961
1179
  status: "running",
@@ -977,7 +1195,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
977
1195
  executionContext,
978
1196
  result: {
979
1197
  status: "suspended",
980
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1198
+ payload: stepResult.payload,
1199
+ suspendPayload: {
1200
+ ...stepResult?.suspendPayload,
1201
+ __workflow_meta: { runId, path: suspendPath }
1202
+ }
981
1203
  }
982
1204
  };
983
1205
  }
@@ -1042,132 +1264,186 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1042
1264
  }
1043
1265
  );
1044
1266
  Object.assign(executionContext, res.executionContext);
1045
- return res.result;
1267
+ return {
1268
+ ...res.result,
1269
+ startedAt,
1270
+ endedAt: Date.now(),
1271
+ payload: inputData,
1272
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1273
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1274
+ };
1046
1275
  }
1047
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1048
- let execResults;
1049
- let suspended;
1050
- let bailed;
1051
- try {
1052
- if (validationError) {
1053
- throw validationError;
1276
+ const stepCallId = randomUUID();
1277
+ let stepRes;
1278
+ try {
1279
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1280
+ let execResults;
1281
+ let suspended;
1282
+ let bailed;
1283
+ try {
1284
+ if (validationError) {
1285
+ throw validationError;
1286
+ }
1287
+ const result = await step.execute({
1288
+ runId: executionContext.runId,
1289
+ mastra: this.mastra,
1290
+ runtimeContext,
1291
+ writer: new ToolStream(
1292
+ {
1293
+ prefix: "workflow-step",
1294
+ callId: stepCallId,
1295
+ name: step.id,
1296
+ runId: executionContext.runId
1297
+ },
1298
+ writableStream
1299
+ ),
1300
+ state: executionContext?.state ?? {},
1301
+ setState: (state) => {
1302
+ executionContext.state = state;
1303
+ },
1304
+ inputData,
1305
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1306
+ tracingContext: {
1307
+ currentSpan: stepAISpan
1308
+ },
1309
+ getInitData: () => stepResults?.input,
1310
+ getStepResult: getStepResult.bind(this, stepResults),
1311
+ suspend: async (suspendPayload, suspendOptions) => {
1312
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1313
+ if (suspendOptions?.resumeLabel) {
1314
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1315
+ for (const label of resumeLabel) {
1316
+ executionContext.resumeLabels[label] = {
1317
+ stepId: step.id,
1318
+ foreachIndex: executionContext.foreachIndex
1319
+ };
1320
+ }
1321
+ }
1322
+ suspended = { payload: suspendPayload };
1323
+ },
1324
+ bail: (result2) => {
1325
+ bailed = { payload: result2 };
1326
+ },
1327
+ resume: {
1328
+ steps: resume?.steps?.slice(1) || [],
1329
+ resumePayload: resume?.resumePayload,
1330
+ // @ts-ignore
1331
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1332
+ },
1333
+ [EMITTER_SYMBOL]: emitter,
1334
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1335
+ engine: {
1336
+ step: this.inngestStep
1337
+ },
1338
+ abortSignal: abortController.signal
1339
+ });
1340
+ const endedAt = Date.now();
1341
+ execResults = {
1342
+ status: "success",
1343
+ output: result,
1344
+ startedAt,
1345
+ endedAt,
1346
+ payload: inputData,
1347
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1348
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1349
+ };
1350
+ } catch (e) {
1351
+ const stepFailure = {
1352
+ status: "failed",
1353
+ payload: inputData,
1354
+ error: e instanceof Error ? e.message : String(e),
1355
+ endedAt: Date.now(),
1356
+ startedAt,
1357
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1358
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1359
+ };
1360
+ execResults = stepFailure;
1361
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1362
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1363
+ throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1364
+ cause: execResults
1365
+ });
1054
1366
  }
1055
- const result = await step.execute({
1056
- runId: executionContext.runId,
1057
- mastra: this.mastra,
1058
- runtimeContext,
1059
- writableStream,
1060
- inputData,
1061
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1062
- tracingContext: {
1063
- currentSpan: stepAISpan
1064
- },
1065
- getInitData: () => stepResults?.input,
1066
- getStepResult: getStepResult.bind(this, stepResults),
1067
- suspend: async (suspendPayload) => {
1068
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1069
- suspended = { payload: suspendPayload };
1070
- },
1071
- bail: (result2) => {
1072
- bailed = { payload: result2 };
1073
- },
1074
- resume: {
1075
- steps: resume?.steps?.slice(1) || [],
1076
- resumePayload: resume?.resumePayload,
1077
- // @ts-ignore
1078
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1079
- },
1080
- [EMITTER_SYMBOL]: emitter,
1081
- engine: {
1082
- step: this.inngestStep
1367
+ if (suspended) {
1368
+ execResults = {
1369
+ status: "suspended",
1370
+ suspendPayload: suspended.payload,
1371
+ payload: inputData,
1372
+ suspendedAt: Date.now(),
1373
+ startedAt,
1374
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1375
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1376
+ };
1377
+ } else if (bailed) {
1378
+ execResults = {
1379
+ status: "bailed",
1380
+ output: bailed.payload,
1381
+ payload: inputData,
1382
+ endedAt: Date.now(),
1383
+ startedAt
1384
+ };
1385
+ }
1386
+ await emitter.emit("watch", {
1387
+ type: "watch",
1388
+ payload: {
1389
+ currentStep: {
1390
+ id: step.id,
1391
+ ...execResults
1392
+ },
1393
+ workflowState: {
1394
+ status: "running",
1395
+ steps: { ...stepResults, [step.id]: execResults },
1396
+ result: null,
1397
+ error: null
1398
+ }
1083
1399
  },
1084
- abortSignal: abortController.signal
1400
+ eventTimestamp: Date.now()
1085
1401
  });
1086
- const endedAt = Date.now();
1087
- execResults = {
1088
- status: "success",
1089
- output: result,
1090
- startedAt,
1091
- endedAt,
1092
- payload: inputData,
1093
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1094
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1095
- };
1096
- } catch (e) {
1097
- execResults = {
1098
- status: "failed",
1099
- payload: inputData,
1100
- error: e instanceof Error ? e.message : String(e),
1101
- endedAt: Date.now(),
1102
- startedAt,
1103
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1104
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1105
- };
1106
- }
1107
- if (suspended) {
1108
- execResults = {
1109
- status: "suspended",
1110
- suspendedPayload: suspended.payload,
1111
- payload: inputData,
1112
- suspendedAt: Date.now(),
1113
- startedAt,
1114
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1115
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1116
- };
1117
- } else if (bailed) {
1118
- execResults = { status: "bailed", output: bailed.payload, payload: inputData, endedAt: Date.now(), startedAt };
1119
- }
1120
- if (execResults.status === "failed") {
1121
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1122
- const error = new Error(execResults.error);
1123
- stepAISpan?.error({ error });
1124
- throw error;
1402
+ if (execResults.status === "suspended") {
1403
+ await emitter.emit("watch-v2", {
1404
+ type: "workflow-step-suspended",
1405
+ payload: {
1406
+ id: step.id,
1407
+ ...execResults
1408
+ }
1409
+ });
1410
+ } else {
1411
+ await emitter.emit("watch-v2", {
1412
+ type: "workflow-step-result",
1413
+ payload: {
1414
+ id: step.id,
1415
+ ...execResults
1416
+ }
1417
+ });
1418
+ await emitter.emit("watch-v2", {
1419
+ type: "workflow-step-finish",
1420
+ payload: {
1421
+ id: step.id,
1422
+ metadata: {}
1423
+ }
1424
+ });
1125
1425
  }
1126
- }
1127
- await emitter.emit("watch", {
1128
- type: "watch",
1129
- payload: {
1130
- currentStep: {
1131
- id: step.id,
1132
- ...execResults
1133
- },
1134
- workflowState: {
1135
- status: "running",
1136
- steps: { ...stepResults, [step.id]: execResults },
1137
- result: null,
1138
- error: null
1139
- }
1140
- },
1141
- eventTimestamp: Date.now()
1426
+ stepAISpan?.end({ output: execResults });
1427
+ return { result: execResults, executionContext, stepResults };
1142
1428
  });
1143
- if (execResults.status === "suspended") {
1144
- await emitter.emit("watch-v2", {
1145
- type: "workflow-step-suspended",
1146
- payload: {
1147
- id: step.id,
1148
- ...execResults
1149
- }
1150
- });
1151
- } else {
1152
- await emitter.emit("watch-v2", {
1153
- type: "workflow-step-result",
1154
- payload: {
1155
- id: step.id,
1156
- ...execResults
1157
- }
1158
- });
1159
- await emitter.emit("watch-v2", {
1160
- type: "workflow-step-finish",
1161
- payload: {
1162
- id: step.id,
1163
- metadata: {}
1164
- }
1165
- });
1166
- }
1167
- stepAISpan?.end({ output: execResults });
1168
- return { result: execResults, executionContext, stepResults };
1169
- });
1170
- if (disableScorers !== false) {
1429
+ } catch (e) {
1430
+ const stepFailure = e instanceof Error ? e?.cause : {
1431
+ status: "failed",
1432
+ error: e instanceof Error ? e.message : String(e),
1433
+ payload: inputData,
1434
+ startedAt,
1435
+ endedAt: Date.now()
1436
+ };
1437
+ stepRes = {
1438
+ result: stepFailure,
1439
+ executionContext,
1440
+ stepResults: {
1441
+ ...stepResults,
1442
+ [step.id]: stepFailure
1443
+ }
1444
+ };
1445
+ }
1446
+ if (disableScorers !== false && stepRes.result.status === "success") {
1171
1447
  await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1172
1448
  if (step.scorers) {
1173
1449
  await this.runScorers({
@@ -1186,6 +1462,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1186
1462
  }
1187
1463
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1188
1464
  Object.assign(stepResults, stepRes.stepResults);
1465
+ executionContext.state = stepRes.executionContext.state;
1189
1466
  return stepRes.result;
1190
1467
  }
1191
1468
  async persistStepUpdate({
@@ -1202,16 +1479,21 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1202
1479
  await this.inngestStep.run(
1203
1480
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1204
1481
  async () => {
1482
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1483
+ if (!shouldPersistSnapshot) {
1484
+ return;
1485
+ }
1205
1486
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1206
1487
  workflowName: workflowId,
1207
1488
  runId,
1208
1489
  resourceId,
1209
1490
  snapshot: {
1210
1491
  runId,
1211
- value: {},
1492
+ value: executionContext.state,
1212
1493
  context: stepResults,
1213
1494
  activePaths: [],
1214
1495
  suspendedPaths: executionContext.suspendedPaths,
1496
+ resumeLabels: executionContext.resumeLabels,
1215
1497
  waitingPaths: {},
1216
1498
  serializedStepGraph,
1217
1499
  status: workflowStatus,
@@ -1229,9 +1511,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1229
1511
  runId,
1230
1512
  entry,
1231
1513
  prevOutput,
1232
- prevStep,
1233
1514
  stepResults,
1234
- serializedStepGraph,
1235
1515
  resume,
1236
1516
  executionContext,
1237
1517
  emitter,
@@ -1264,43 +1544,56 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1264
1544
  tracingPolicy: this.options?.tracingPolicy
1265
1545
  });
1266
1546
  try {
1267
- const result = await cond({
1268
- runId,
1269
- workflowId,
1270
- mastra: this.mastra,
1271
- runtimeContext,
1272
- runCount: -1,
1273
- inputData: prevOutput,
1274
- tracingContext: {
1275
- currentSpan: evalSpan
1276
- },
1277
- getInitData: () => stepResults?.input,
1278
- getStepResult: getStepResult.bind(this, stepResults),
1279
- // TODO: this function shouldn't have suspend probably?
1280
- suspend: async (_suspendPayload) => {
1281
- },
1282
- bail: () => {
1283
- },
1284
- abort: () => {
1285
- abortController.abort();
1286
- },
1287
- [EMITTER_SYMBOL]: emitter,
1288
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
1289
- // TODO: add streamVNext support
1290
- engine: {
1291
- step: this.inngestStep
1292
- },
1293
- abortSignal: abortController.signal,
1294
- writer: new ToolStream(
1547
+ const result = await cond(
1548
+ createDeprecationProxy(
1295
1549
  {
1296
- prefix: "workflow-step",
1297
- callId: randomUUID(),
1298
- name: "conditional",
1299
- runId
1550
+ runId,
1551
+ workflowId,
1552
+ mastra: this.mastra,
1553
+ runtimeContext,
1554
+ runCount: -1,
1555
+ retryCount: -1,
1556
+ inputData: prevOutput,
1557
+ state: executionContext.state,
1558
+ setState: (state) => {
1559
+ executionContext.state = state;
1560
+ },
1561
+ tracingContext: {
1562
+ currentSpan: evalSpan
1563
+ },
1564
+ getInitData: () => stepResults?.input,
1565
+ getStepResult: getStepResult.bind(this, stepResults),
1566
+ // TODO: this function shouldn't have suspend probably?
1567
+ suspend: async (_suspendPayload) => {
1568
+ },
1569
+ bail: () => {
1570
+ },
1571
+ abort: () => {
1572
+ abortController.abort();
1573
+ },
1574
+ [EMITTER_SYMBOL]: emitter,
1575
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1576
+ engine: {
1577
+ step: this.inngestStep
1578
+ },
1579
+ abortSignal: abortController.signal,
1580
+ writer: new ToolStream(
1581
+ {
1582
+ prefix: "workflow-step",
1583
+ callId: randomUUID(),
1584
+ name: "conditional",
1585
+ runId
1586
+ },
1587
+ writableStream
1588
+ )
1300
1589
  },
1301
- writableStream
1590
+ {
1591
+ paramName: "runCount",
1592
+ deprecationMessage: runCountDeprecationMessage,
1593
+ logger: this.logger
1594
+ }
1302
1595
  )
1303
- });
1596
+ );
1304
1597
  evalSpan?.end({
1305
1598
  output: result,
1306
1599
  attributes: {
@@ -1328,13 +1621,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1328
1621
  }
1329
1622
  });
1330
1623
  const results = await Promise.all(
1331
- stepsToRun.map(
1332
- (step, index) => this.executeEntry({
1333
- workflowId,
1334
- runId,
1335
- entry: step,
1336
- serializedStepGraph,
1337
- prevStep,
1624
+ stepsToRun.map(async (step, index) => {
1625
+ const currStepResult = stepResults[step.step.id];
1626
+ if (currStepResult && currStepResult.status === "success") {
1627
+ return currStepResult;
1628
+ }
1629
+ const result = await this.executeStep({
1630
+ step: step.step,
1631
+ prevOutput,
1338
1632
  stepResults,
1339
1633
  resume,
1340
1634
  executionContext: {
@@ -1342,8 +1636,9 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1342
1636
  runId,
1343
1637
  executionPath: [...executionContext.executionPath, index],
1344
1638
  suspendedPaths: executionContext.suspendedPaths,
1639
+ resumeLabels: executionContext.resumeLabels,
1345
1640
  retryConfig: executionContext.retryConfig,
1346
- executionSpan: executionContext.executionSpan
1641
+ state: executionContext.state
1347
1642
  },
1348
1643
  emitter,
1349
1644
  abortController,
@@ -1353,20 +1648,22 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1353
1648
  tracingContext: {
1354
1649
  currentSpan: conditionalSpan
1355
1650
  }
1356
- })
1357
- )
1651
+ });
1652
+ stepResults[step.step.id] = result;
1653
+ return result;
1654
+ })
1358
1655
  );
1359
- const hasFailed = results.find((result) => result.result.status === "failed");
1360
- const hasSuspended = results.find((result) => result.result.status === "suspended");
1656
+ const hasFailed = results.find((result) => result.status === "failed");
1657
+ const hasSuspended = results.find((result) => result.status === "suspended");
1361
1658
  if (hasFailed) {
1362
- execResults = { status: "failed", error: hasFailed.result.error };
1659
+ execResults = { status: "failed", error: hasFailed.error };
1363
1660
  } else if (hasSuspended) {
1364
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1661
+ execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
1365
1662
  } else {
1366
1663
  execResults = {
1367
1664
  status: "success",
1368
1665
  output: results.reduce((acc, result, index) => {
1369
- if (result.result.status === "success") {
1666
+ if (result.status === "success") {
1370
1667
  acc[stepsToRun[index].step.id] = result.output;
1371
1668
  }
1372
1669
  return acc;