@mastra/inngest 0.0.0-taofeeqInngest-20250603090617 → 0.0.0-tsconfig-compile-20250703214351

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/src/index.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { randomUUID } from 'crypto';
2
+ import type { ReadableStream } from 'node:stream/web';
2
3
  import { subscribe } from '@inngest/realtime';
3
- import type { Mastra, WorkflowRun, WorkflowRuns } from '@mastra/core';
4
+ import type { Agent, Mastra, ToolExecutionContext, WorkflowRun, WorkflowRuns } from '@mastra/core';
4
5
  import { RuntimeContext } from '@mastra/core/di';
5
- import { Workflow, createStep, Run, DefaultExecutionEngine, cloneStep } from '@mastra/core/workflows';
6
+ import { Tool } from '@mastra/core/tools';
7
+ import { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
6
8
  import type {
7
9
  ExecuteFunction,
8
10
  ExecutionContext,
@@ -14,22 +16,34 @@ import type {
14
16
  StepResult,
15
17
  WorkflowResult,
16
18
  SerializedStepFlowEntry,
19
+ StepFailure,
20
+ Emitter,
21
+ WatchEvent,
22
+ StreamEvent,
17
23
  } from '@mastra/core/workflows';
18
24
  import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
19
25
  import type { Span } from '@opentelemetry/api';
20
26
  import type { Inngest, BaseContext } from 'inngest';
21
27
  import { serve as inngestServe } from 'inngest/hono';
22
- import type { z } from 'zod';
28
+ import { z } from 'zod';
29
+
30
+ export type InngestEngineType = {
31
+ step: any;
32
+ };
23
33
 
24
34
  export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest }): ReturnType<typeof inngestServe> {
25
35
  const wfs = mastra.getWorkflows();
26
- const functions = Object.values(wfs).flatMap(wf => {
27
- if (wf instanceof InngestWorkflow) {
28
- wf.__registerMastra(mastra);
29
- return wf.getFunctions();
30
- }
31
- return [];
32
- });
36
+ const functions = Array.from(
37
+ new Set(
38
+ Object.values(wfs).flatMap(wf => {
39
+ if (wf instanceof InngestWorkflow) {
40
+ wf.__registerMastra(mastra);
41
+ return wf.getFunctions();
42
+ }
43
+ return [];
44
+ }),
45
+ ),
46
+ );
33
47
  return inngestServe({
34
48
  client: inngest,
35
49
  functions,
@@ -37,10 +51,11 @@ export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest })
37
51
  }
38
52
 
39
53
  export class InngestRun<
54
+ TEngineType = InngestEngineType,
40
55
  TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
41
56
  TInput extends z.ZodType<any> = z.ZodType<any>,
42
57
  TOutput extends z.ZodType<any> = z.ZodType<any>,
43
- > extends Run<TSteps, TInput, TOutput> {
58
+ > extends Run<TEngineType, TSteps, TInput, TOutput> {
44
59
  private inngest: Inngest;
45
60
  serializedStepGraph: SerializedStepFlowEntry[];
46
61
  #mastra: Mastra;
@@ -79,16 +94,55 @@ export class InngestRun<
79
94
 
80
95
  async getRunOutput(eventId: string) {
81
96
  let runs = await this.getRuns(eventId);
82
- while (runs?.[0]?.status !== 'Completed') {
97
+
98
+ while (runs?.[0]?.status !== 'Completed' || runs?.[0]?.event_id !== eventId) {
83
99
  await new Promise(resolve => setTimeout(resolve, 1000));
84
100
  runs = await this.getRuns(eventId);
85
- if (runs?.[0]?.status === 'Failed' || runs?.[0]?.status === 'Cancelled') {
101
+ if (runs?.[0]?.status === 'Failed') {
102
+ console.log('run', runs?.[0]);
86
103
  throw new Error(`Function run ${runs?.[0]?.status}`);
104
+ } else if (runs?.[0]?.status === 'Cancelled') {
105
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
106
+ workflowName: this.workflowId,
107
+ runId: this.runId,
108
+ });
109
+ return { output: { result: { steps: snapshot?.context, status: 'canceled' } } };
87
110
  }
88
111
  }
89
112
  return runs?.[0];
90
113
  }
91
114
 
115
+ async sendEvent(event: string, data: any) {
116
+ await this.inngest.send({
117
+ name: `user-event-${event}`,
118
+ data,
119
+ });
120
+ }
121
+
122
+ async cancel() {
123
+ await this.inngest.send({
124
+ name: `cancel.workflow.${this.workflowId}`,
125
+ data: {
126
+ runId: this.runId,
127
+ },
128
+ });
129
+
130
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
131
+ workflowName: this.workflowId,
132
+ runId: this.runId,
133
+ });
134
+ if (snapshot) {
135
+ await this.#mastra?.storage?.persistWorkflowSnapshot({
136
+ workflowName: this.workflowId,
137
+ runId: this.runId,
138
+ snapshot: {
139
+ ...snapshot,
140
+ status: 'canceled' as any,
141
+ },
142
+ });
143
+ }
144
+ }
145
+
92
146
  async start({
93
147
  inputData,
94
148
  }: {
@@ -106,6 +160,7 @@ export class InngestRun<
106
160
  activePaths: [],
107
161
  suspendedPaths: {},
108
162
  timestamp: Date.now(),
163
+ status: 'running',
109
164
  },
110
165
  });
111
166
 
@@ -127,7 +182,9 @@ export class InngestRun<
127
182
  result.error = new Error(result.error);
128
183
  }
129
184
 
130
- this.cleanup?.();
185
+ if (result.status !== 'suspended') {
186
+ this.cleanup?.();
187
+ }
131
188
  return result;
132
189
  }
133
190
 
@@ -139,6 +196,27 @@ export class InngestRun<
139
196
  | string
140
197
  | string[];
141
198
  runtimeContext?: RuntimeContext;
199
+ }): Promise<WorkflowResult<TOutput, TSteps>> {
200
+ const p = this._resume(params).then(result => {
201
+ if (result.status !== 'suspended') {
202
+ this.closeStreamAction?.().catch(() => {});
203
+ }
204
+
205
+ return result;
206
+ });
207
+
208
+ this.executionResults = p;
209
+ return p;
210
+ }
211
+
212
+ async _resume<TResumeSchema extends z.ZodType<any>>(params: {
213
+ resumeData?: z.infer<TResumeSchema>;
214
+ step:
215
+ | Step<string, any, any, TResumeSchema, any>
216
+ | [...Step<string, any, any, any, any>[], Step<string, any, any, TResumeSchema, any>]
217
+ | string
218
+ | string[];
219
+ runtimeContext?: RuntimeContext;
142
220
  }): Promise<WorkflowResult<TOutput, TSteps>> {
143
221
  const steps: string[] = (Array.isArray(params.step) ? params.step : [params.step]).map(step =>
144
222
  typeof step === 'string' ? step : step?.id,
@@ -176,37 +254,82 @@ export class InngestRun<
176
254
  return result;
177
255
  }
178
256
 
179
- watch(cb: (event: any) => void): () => void {
257
+ watch(cb: (event: WatchEvent) => void, type: 'watch' | 'watch-v2' = 'watch'): () => void {
258
+ let active = true;
180
259
  const streamPromise = subscribe(
181
260
  {
182
261
  channel: `workflow:${this.workflowId}:${this.runId}`,
183
- topics: ['watch'],
262
+ topics: [type],
184
263
  app: this.inngest,
185
264
  },
186
265
  (message: any) => {
187
- cb(message.data);
266
+ if (active) {
267
+ cb(message.data);
268
+ }
188
269
  },
189
270
  );
190
271
 
191
272
  return () => {
273
+ active = false;
192
274
  streamPromise
193
- .then((stream: any) => {
194
- stream.cancel();
275
+ .then(async (stream: Awaited<typeof streamPromise>) => {
276
+ return stream.cancel();
195
277
  })
196
278
  .catch(err => {
197
279
  console.error(err);
198
280
  });
199
281
  };
200
282
  }
283
+
284
+ stream({ inputData, runtimeContext }: { inputData?: z.infer<TInput>; runtimeContext?: RuntimeContext } = {}): {
285
+ stream: ReadableStream<StreamEvent>;
286
+ getWorkflowState: () => Promise<WorkflowResult<TOutput, TSteps>>;
287
+ } {
288
+ const { readable, writable } = new TransformStream<StreamEvent, StreamEvent>();
289
+
290
+ const writer = writable.getWriter();
291
+ const unwatch = this.watch(async event => {
292
+ try {
293
+ // watch-v2 events are data stream events, so we need to cast them to the correct type
294
+ await writer.write(event as any);
295
+ } catch {}
296
+ }, 'watch-v2');
297
+
298
+ this.closeStreamAction = async () => {
299
+ unwatch();
300
+
301
+ try {
302
+ await writer.close();
303
+ } catch (err) {
304
+ console.error('Error closing stream:', err);
305
+ } finally {
306
+ writer.releaseLock();
307
+ }
308
+ };
309
+
310
+ this.executionResults = this.start({ inputData, runtimeContext }).then(result => {
311
+ if (result.status !== 'suspended') {
312
+ this.closeStreamAction?.().catch(() => {});
313
+ }
314
+
315
+ return result;
316
+ });
317
+
318
+ return {
319
+ stream: readable as ReadableStream<StreamEvent>,
320
+ getWorkflowState: () => this.executionResults!,
321
+ };
322
+ }
201
323
  }
202
324
 
203
325
  export class InngestWorkflow<
326
+ TEngineType = InngestEngineType,
204
327
  TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
205
328
  TWorkflowId extends string = string,
206
329
  TInput extends z.ZodType<any> = z.ZodType<any>,
207
330
  TOutput extends z.ZodType<any> = z.ZodType<any>,
208
331
  TPrevSchema extends z.ZodType<any> = TInput,
209
- > extends Workflow<TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
332
+ > extends Workflow<TEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
210
333
  #mastra: Mastra;
211
334
  public inngest: Inngest;
212
335
 
@@ -238,7 +361,10 @@ export class InngestWorkflow<
238
361
  const storage = this.#mastra?.getStorage();
239
362
  if (!storage) {
240
363
  this.logger.debug('Cannot get workflow runs. Mastra engine is not initialized');
241
- return null;
364
+ //returning in memory run if no storage is initialized
365
+ return this.runs.get(runId)
366
+ ? ({ ...this.runs.get(runId), workflowName: this.id } as unknown as WorkflowRun)
367
+ : null;
242
368
  }
243
369
  const run = (await storage.getWorkflowRunById({ runId, workflowName: this.id })) as unknown as WorkflowRun;
244
370
 
@@ -248,6 +374,32 @@ export class InngestWorkflow<
248
374
  );
249
375
  }
250
376
 
377
+ async getWorkflowRunExecutionResult(runId: string): Promise<WatchEvent['payload']['workflowState'] | null> {
378
+ const storage = this.#mastra?.getStorage();
379
+ if (!storage) {
380
+ this.logger.debug('Cannot get workflow run execution result. Mastra storage is not initialized');
381
+ return null;
382
+ }
383
+
384
+ const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
385
+
386
+ if (!run?.snapshot) {
387
+ return null;
388
+ }
389
+
390
+ if (typeof run.snapshot === 'string') {
391
+ return null;
392
+ }
393
+
394
+ return {
395
+ status: run.snapshot.status,
396
+ result: run.snapshot.result,
397
+ error: run.snapshot.error,
398
+ payload: run.snapshot.context?.input,
399
+ steps: run.snapshot.context as any,
400
+ };
401
+ }
402
+
251
403
  __registerMastra(mastra: Mastra) {
252
404
  this.#mastra = mastra;
253
405
  this.executionEngine.__registerMastra(mastra);
@@ -271,11 +423,11 @@ export class InngestWorkflow<
271
423
  }
272
424
  }
273
425
 
274
- createRun(options?: { runId?: string }): Run<TSteps, TInput, TOutput> {
426
+ createRun(options?: { runId?: string }): Run<TEngineType, TSteps, TInput, TOutput> {
275
427
  const runIdToUse = options?.runId || randomUUID();
276
428
 
277
429
  // Return a new Run instance with object parameters
278
- const run: Run<TSteps, TInput, TOutput> =
430
+ const run: Run<TEngineType, TSteps, TInput, TOutput> =
279
431
  this.runs.get(runIdToUse) ??
280
432
  new InngestRun(
281
433
  {
@@ -295,13 +447,64 @@ export class InngestWorkflow<
295
447
  return run;
296
448
  }
297
449
 
450
+ async createRunAsync(options?: { runId?: string }): Promise<Run<TEngineType, TSteps, TInput, TOutput>> {
451
+ const runIdToUse = options?.runId || randomUUID();
452
+
453
+ // Return a new Run instance with object parameters
454
+ const run: Run<TEngineType, TSteps, TInput, TOutput> =
455
+ this.runs.get(runIdToUse) ??
456
+ new InngestRun(
457
+ {
458
+ workflowId: this.id,
459
+ runId: runIdToUse,
460
+ executionEngine: this.executionEngine,
461
+ executionGraph: this.executionGraph,
462
+ serializedStepGraph: this.serializedStepGraph,
463
+ mastra: this.#mastra,
464
+ retryConfig: this.retryConfig,
465
+ cleanup: () => this.runs.delete(runIdToUse),
466
+ },
467
+ this.inngest,
468
+ );
469
+
470
+ this.runs.set(runIdToUse, run);
471
+
472
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
473
+
474
+ if (!workflowSnapshotInStorage) {
475
+ await this.mastra?.getStorage()?.persistWorkflowSnapshot({
476
+ workflowName: this.id,
477
+ runId: runIdToUse,
478
+ snapshot: {
479
+ runId: runIdToUse,
480
+ status: 'pending',
481
+ value: {},
482
+ context: {},
483
+ activePaths: [],
484
+ serializedStepGraph: this.serializedStepGraph,
485
+ suspendedPaths: {},
486
+ result: undefined,
487
+ error: undefined,
488
+ // @ts-ignore
489
+ timestamp: Date.now(),
490
+ },
491
+ });
492
+ }
493
+
494
+ return run;
495
+ }
496
+
298
497
  getFunction() {
299
498
  if (this.function) {
300
499
  return this.function;
301
500
  }
302
501
  this.function = this.inngest.createFunction(
303
- // @ts-ignore
304
- { id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
502
+ {
503
+ id: `workflow.${this.id}`,
504
+ // @ts-ignore
505
+ retries: this.retryConfig?.attempts ?? 0,
506
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
507
+ },
305
508
  { event: `workflow.${this.id}` },
306
509
  async ({ event, step, attempt, publish }) => {
307
510
  let { inputData, runId, resume } = event.data;
@@ -321,13 +524,22 @@ export class InngestWorkflow<
321
524
  try {
322
525
  await publish({
323
526
  channel: `workflow:${this.id}:${runId}`,
324
- topic: 'watch',
527
+ topic: event,
325
528
  data,
326
529
  });
327
530
  } catch (err: any) {
328
531
  this.logger.error('Error emitting event: ' + (err?.stack ?? err?.message ?? err));
329
532
  }
330
533
  },
534
+ on: (_event: string, _callback: (data: any) => void) => {
535
+ // no-op
536
+ },
537
+ off: (_event: string, _callback: (data: any) => void) => {
538
+ // no-op
539
+ },
540
+ once: (_event: string, _callback: (data: any) => void) => {
541
+ // no-op
542
+ },
331
543
  };
332
544
 
333
545
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
@@ -341,6 +553,7 @@ export class InngestWorkflow<
341
553
  retryConfig: this.retryConfig,
342
554
  runtimeContext: new RuntimeContext(), // TODO
343
555
  resume,
556
+ abortController: new AbortController(),
344
557
  });
345
558
 
346
559
  return { result, runId };
@@ -369,29 +582,197 @@ export class InngestWorkflow<
369
582
  }
370
583
  }
371
584
 
372
- function cloneWorkflow<
373
- TWorkflowId extends string = string,
374
- TInput extends z.ZodType<any> = z.ZodType<any>,
375
- TOutput extends z.ZodType<any> = z.ZodType<any>,
376
- TSteps extends Step<string, any, any, any, any>[] = Step<string, any, any, any, any>[],
585
+ function isAgent(params: any): params is Agent<any, any, any> {
586
+ return params?.component === 'AGENT';
587
+ }
588
+
589
+ function isTool(params: any): params is Tool<any, any, any> {
590
+ return params instanceof Tool;
591
+ }
592
+
593
+ export function createStep<
594
+ TStepId extends string,
595
+ TStepInput extends z.ZodType<any>,
596
+ TStepOutput extends z.ZodType<any>,
597
+ TResumeSchema extends z.ZodType<any>,
598
+ TSuspendSchema extends z.ZodType<any>,
599
+ >(params: {
600
+ id: TStepId;
601
+ description?: string;
602
+ inputSchema: TStepInput;
603
+ outputSchema: TStepOutput;
604
+ resumeSchema?: TResumeSchema;
605
+ suspendSchema?: TSuspendSchema;
606
+ execute: ExecuteFunction<
607
+ z.infer<TStepInput>,
608
+ z.infer<TStepOutput>,
609
+ z.infer<TResumeSchema>,
610
+ z.infer<TSuspendSchema>,
611
+ InngestEngineType
612
+ >;
613
+ }): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
614
+
615
+ export function createStep<
616
+ TStepId extends string,
617
+ TStepInput extends z.ZodObject<{ prompt: z.ZodString }>,
618
+ TStepOutput extends z.ZodObject<{ text: z.ZodString }>,
619
+ TResumeSchema extends z.ZodType<any>,
620
+ TSuspendSchema extends z.ZodType<any>,
377
621
  >(
378
- workflow: InngestWorkflow<TSteps, string, TInput, TOutput>,
379
- opts: { id: TWorkflowId },
380
- ): InngestWorkflow<TSteps, TWorkflowId, TInput, TOutput> {
381
- const wf = new InngestWorkflow(
382
- {
383
- id: opts.id,
384
- inputSchema: workflow.inputSchema,
385
- outputSchema: workflow.outputSchema,
386
- steps: workflow.stepDefs,
387
- mastra: workflow.mastra,
388
- },
389
- workflow.inngest,
390
- );
622
+ agent: Agent<TStepId, any, any>,
623
+ ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
624
+
625
+ export function createStep<
626
+ TSchemaIn extends z.ZodType<any>,
627
+ TSchemaOut extends z.ZodType<any>,
628
+ TContext extends ToolExecutionContext<TSchemaIn>,
629
+ >(
630
+ tool: Tool<TSchemaIn, TSchemaOut, TContext> & {
631
+ inputSchema: TSchemaIn;
632
+ outputSchema: TSchemaOut;
633
+ execute: (context: TContext) => Promise<any>;
634
+ },
635
+ ): Step<string, TSchemaIn, TSchemaOut, z.ZodType<any>, z.ZodType<any>, InngestEngineType>;
636
+ export function createStep<
637
+ TStepId extends string,
638
+ TStepInput extends z.ZodType<any>,
639
+ TStepOutput extends z.ZodType<any>,
640
+ TResumeSchema extends z.ZodType<any>,
641
+ TSuspendSchema extends z.ZodType<any>,
642
+ >(
643
+ params:
644
+ | {
645
+ id: TStepId;
646
+ description?: string;
647
+ inputSchema: TStepInput;
648
+ outputSchema: TStepOutput;
649
+ resumeSchema?: TResumeSchema;
650
+ suspendSchema?: TSuspendSchema;
651
+ execute: ExecuteFunction<
652
+ z.infer<TStepInput>,
653
+ z.infer<TStepOutput>,
654
+ z.infer<TResumeSchema>,
655
+ z.infer<TSuspendSchema>,
656
+ InngestEngineType
657
+ >;
658
+ }
659
+ | Agent<any, any, any>
660
+ | (Tool<TStepInput, TStepOutput, any> & {
661
+ inputSchema: TStepInput;
662
+ outputSchema: TStepOutput;
663
+ execute: (context: ToolExecutionContext<TStepInput>) => Promise<any>;
664
+ }),
665
+ ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType> {
666
+ if (isAgent(params)) {
667
+ return {
668
+ id: params.name,
669
+ // @ts-ignore
670
+ inputSchema: z.object({
671
+ prompt: z.string(),
672
+ // resourceId: z.string().optional(),
673
+ // threadId: z.string().optional(),
674
+ }),
675
+ // @ts-ignore
676
+ outputSchema: z.object({
677
+ text: z.string(),
678
+ }),
679
+ execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
680
+ let streamPromise = {} as {
681
+ promise: Promise<string>;
682
+ resolve: (value: string) => void;
683
+ reject: (reason?: any) => void;
684
+ };
391
685
 
392
- wf.setStepFlow(workflow.stepGraph);
393
- wf.commit();
394
- return wf;
686
+ streamPromise.promise = new Promise((resolve, reject) => {
687
+ streamPromise.resolve = resolve;
688
+ streamPromise.reject = reject;
689
+ });
690
+ const toolData = {
691
+ name: params.name,
692
+ args: inputData,
693
+ };
694
+ await emitter.emit('watch-v2', {
695
+ type: 'tool-call-streaming-start',
696
+ ...toolData,
697
+ });
698
+ const { fullStream } = await params.stream(inputData.prompt, {
699
+ // resourceId: inputData.resourceId,
700
+ // threadId: inputData.threadId,
701
+ runtimeContext,
702
+ onFinish: result => {
703
+ streamPromise.resolve(result.text);
704
+ },
705
+ abortSignal,
706
+ });
707
+
708
+ if (abortSignal.aborted) {
709
+ return abort();
710
+ }
711
+
712
+ for await (const chunk of fullStream) {
713
+ switch (chunk.type) {
714
+ case 'text-delta':
715
+ await emitter.emit('watch-v2', {
716
+ type: 'tool-call-delta',
717
+ ...toolData,
718
+ argsTextDelta: chunk.textDelta,
719
+ });
720
+ break;
721
+
722
+ case 'step-start':
723
+ case 'step-finish':
724
+ case 'finish':
725
+ break;
726
+
727
+ case 'tool-call':
728
+ case 'tool-result':
729
+ case 'tool-call-streaming-start':
730
+ case 'tool-call-delta':
731
+ case 'source':
732
+ case 'file':
733
+ default:
734
+ await emitter.emit('watch-v2', chunk);
735
+ break;
736
+ }
737
+ }
738
+
739
+ return {
740
+ text: await streamPromise.promise,
741
+ };
742
+ },
743
+ };
744
+ }
745
+
746
+ if (isTool(params)) {
747
+ if (!params.inputSchema || !params.outputSchema) {
748
+ throw new Error('Tool must have input and output schemas defined');
749
+ }
750
+
751
+ return {
752
+ // TODO: tool probably should have strong id type
753
+ // @ts-ignore
754
+ id: params.id,
755
+ inputSchema: params.inputSchema,
756
+ outputSchema: params.outputSchema,
757
+ execute: async ({ inputData, mastra, runtimeContext }) => {
758
+ return params.execute({
759
+ context: inputData,
760
+ mastra,
761
+ runtimeContext,
762
+ });
763
+ },
764
+ };
765
+ }
766
+
767
+ return {
768
+ id: params.id,
769
+ description: params.description,
770
+ inputSchema: params.inputSchema,
771
+ outputSchema: params.outputSchema,
772
+ resumeSchema: params.resumeSchema,
773
+ suspendSchema: params.suspendSchema,
774
+ execute: params.execute,
775
+ };
395
776
  }
396
777
 
397
778
  export function init(inngest: Inngest) {
@@ -400,13 +781,59 @@ export function init(inngest: Inngest) {
400
781
  TWorkflowId extends string = string,
401
782
  TInput extends z.ZodType<any> = z.ZodType<any>,
402
783
  TOutput extends z.ZodType<any> = z.ZodType<any>,
403
- TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
784
+ TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
785
+ string,
786
+ any,
787
+ any,
788
+ any,
789
+ any,
790
+ InngestEngineType
791
+ >[],
404
792
  >(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>) {
405
- return new InngestWorkflow(params, inngest);
793
+ return new InngestWorkflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TInput>(params, inngest);
406
794
  },
407
795
  createStep,
408
- cloneStep,
409
- cloneWorkflow,
796
+ cloneStep<TStepId extends string>(
797
+ step: Step<string, any, any, any, any, InngestEngineType>,
798
+ opts: { id: TStepId },
799
+ ): Step<TStepId, any, any, any, any, InngestEngineType> {
800
+ return {
801
+ id: opts.id,
802
+ description: step.description,
803
+ inputSchema: step.inputSchema,
804
+ outputSchema: step.outputSchema,
805
+ execute: step.execute,
806
+ };
807
+ },
808
+ cloneWorkflow<
809
+ TWorkflowId extends string = string,
810
+ TInput extends z.ZodType<any> = z.ZodType<any>,
811
+ TOutput extends z.ZodType<any> = z.ZodType<any>,
812
+ TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
813
+ string,
814
+ any,
815
+ any,
816
+ any,
817
+ any,
818
+ InngestEngineType
819
+ >[],
820
+ TPrevSchema extends z.ZodType<any> = TInput,
821
+ >(
822
+ workflow: Workflow<InngestEngineType, TSteps, string, TInput, TOutput, TPrevSchema>,
823
+ opts: { id: TWorkflowId },
824
+ ): Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
825
+ const wf: Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> = new Workflow({
826
+ id: opts.id,
827
+ inputSchema: workflow.inputSchema,
828
+ outputSchema: workflow.outputSchema,
829
+ steps: workflow.stepDefs,
830
+ mastra: workflow.mastra,
831
+ });
832
+
833
+ wf.setStepFlow(workflow.stepGraph);
834
+ wf.commit();
835
+ return wf;
836
+ },
410
837
  };
411
838
  }
412
839
 
@@ -420,9 +847,45 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
420
847
  this.inngestAttempts = inngestAttempts;
421
848
  }
422
849
 
850
+ async execute<TInput, TOutput>(params: {
851
+ workflowId: string;
852
+ runId: string;
853
+ graph: ExecutionGraph;
854
+ serializedStepGraph: SerializedStepFlowEntry[];
855
+ input?: TInput;
856
+ resume?: {
857
+ // TODO: add execute path
858
+ steps: string[];
859
+ stepResults: Record<string, StepResult<any, any, any, any>>;
860
+ resumePayload: any;
861
+ resumePath: number[];
862
+ };
863
+ emitter: Emitter;
864
+ retryConfig?: {
865
+ attempts?: number;
866
+ delay?: number;
867
+ };
868
+ runtimeContext: RuntimeContext;
869
+ abortController: AbortController;
870
+ }): Promise<TOutput> {
871
+ await params.emitter.emit('watch-v2', {
872
+ type: 'start',
873
+ payload: { runId: params.runId },
874
+ });
875
+
876
+ const result = await super.execute<TInput, TOutput>(params);
877
+
878
+ await params.emitter.emit('watch-v2', {
879
+ type: 'finish',
880
+ payload: { runId: params.runId },
881
+ });
882
+
883
+ return result;
884
+ }
885
+
423
886
  protected async fmtReturnValue<TOutput>(
424
887
  executionSpan: Span | undefined,
425
- emitter: { emit: (event: string, data: any) => Promise<void> },
888
+ emitter: Emitter,
426
889
  stepResults: Record<string, StepResult<any, any, any, any>>,
427
890
  lastOutput: StepResult<any, any, any, any>,
428
891
  error?: Error | string,
@@ -503,6 +966,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
503
966
  resume,
504
967
  prevOutput,
505
968
  emitter,
969
+ abortController,
506
970
  runtimeContext,
507
971
  }: {
508
972
  workflowId: string;
@@ -515,7 +979,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
515
979
  resumePayload: any;
516
980
  };
517
981
  prevOutput: any;
518
- emitter: { emit: (event: string, data: any) => Promise<void> };
982
+ emitter: Emitter;
983
+ abortController: AbortController;
519
984
  runtimeContext: RuntimeContext;
520
985
  }): Promise<StepResult<any, any, any, any>> {
521
986
  return super.executeStep({
@@ -527,10 +992,178 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
527
992
  resume,
528
993
  prevOutput,
529
994
  emitter,
995
+ abortController,
530
996
  runtimeContext,
531
997
  });
532
998
  }
533
999
 
1000
+ // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
1001
+ // await this.inngestStep.sleep(id, duration);
1002
+ // }
1003
+
1004
+ async executeSleep({
1005
+ workflowId,
1006
+ runId,
1007
+ entry,
1008
+ prevOutput,
1009
+ stepResults,
1010
+ emitter,
1011
+ abortController,
1012
+ runtimeContext,
1013
+ }: {
1014
+ workflowId: string;
1015
+ runId: string;
1016
+ serializedStepGraph: SerializedStepFlowEntry[];
1017
+ entry: {
1018
+ type: 'sleep';
1019
+ id: string;
1020
+ duration?: number;
1021
+ fn?: ExecuteFunction<any, any, any, any, InngestEngineType>;
1022
+ };
1023
+ prevStep: StepFlowEntry;
1024
+ prevOutput: any;
1025
+ stepResults: Record<string, StepResult<any, any, any, any>>;
1026
+ resume?: {
1027
+ steps: string[];
1028
+ stepResults: Record<string, StepResult<any, any, any, any>>;
1029
+ resumePayload: any;
1030
+ resumePath: number[];
1031
+ };
1032
+ executionContext: ExecutionContext;
1033
+ emitter: Emitter;
1034
+ abortController: AbortController;
1035
+ runtimeContext: RuntimeContext;
1036
+ }): Promise<void> {
1037
+ let { duration, fn } = entry;
1038
+
1039
+ if (fn) {
1040
+ duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
1041
+ return await fn({
1042
+ runId,
1043
+ mastra: this.mastra!,
1044
+ runtimeContext,
1045
+ inputData: prevOutput,
1046
+ runCount: -1,
1047
+ getInitData: () => stepResults?.input as any,
1048
+ getStepResult: (step: any) => {
1049
+ if (!step?.id) {
1050
+ return null;
1051
+ }
1052
+
1053
+ const result = stepResults[step.id];
1054
+ if (result?.status === 'success') {
1055
+ return result.output;
1056
+ }
1057
+
1058
+ return null;
1059
+ },
1060
+
1061
+ // TODO: this function shouldn't have suspend probably?
1062
+ suspend: async (_suspendPayload: any): Promise<any> => {},
1063
+ bail: () => {},
1064
+ abort: () => {
1065
+ abortController?.abort();
1066
+ },
1067
+ [EMITTER_SYMBOL]: emitter,
1068
+ engine: { step: this.inngestStep },
1069
+ abortSignal: abortController?.signal,
1070
+ });
1071
+ });
1072
+ }
1073
+
1074
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
1075
+ }
1076
+
1077
+ async executeSleepUntil({
1078
+ workflowId,
1079
+ runId,
1080
+ entry,
1081
+ prevOutput,
1082
+ stepResults,
1083
+ emitter,
1084
+ abortController,
1085
+ runtimeContext,
1086
+ }: {
1087
+ workflowId: string;
1088
+ runId: string;
1089
+ serializedStepGraph: SerializedStepFlowEntry[];
1090
+ entry: {
1091
+ type: 'sleepUntil';
1092
+ id: string;
1093
+ date?: Date;
1094
+ fn?: ExecuteFunction<any, any, any, any, InngestEngineType>;
1095
+ };
1096
+ prevStep: StepFlowEntry;
1097
+ prevOutput: any;
1098
+ stepResults: Record<string, StepResult<any, any, any, any>>;
1099
+ resume?: {
1100
+ steps: string[];
1101
+ stepResults: Record<string, StepResult<any, any, any, any>>;
1102
+ resumePayload: any;
1103
+ resumePath: number[];
1104
+ };
1105
+ executionContext: ExecutionContext;
1106
+ emitter: Emitter;
1107
+ abortController: AbortController;
1108
+ runtimeContext: RuntimeContext;
1109
+ }): Promise<void> {
1110
+ let { date, fn } = entry;
1111
+
1112
+ if (fn) {
1113
+ date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
1114
+ return await fn({
1115
+ runId,
1116
+ mastra: this.mastra!,
1117
+ runtimeContext,
1118
+ inputData: prevOutput,
1119
+ runCount: -1,
1120
+ getInitData: () => stepResults?.input as any,
1121
+ getStepResult: (step: any) => {
1122
+ if (!step?.id) {
1123
+ return null;
1124
+ }
1125
+
1126
+ const result = stepResults[step.id];
1127
+ if (result?.status === 'success') {
1128
+ return result.output;
1129
+ }
1130
+
1131
+ return null;
1132
+ },
1133
+
1134
+ // TODO: this function shouldn't have suspend probably?
1135
+ suspend: async (_suspendPayload: any): Promise<any> => {},
1136
+ bail: () => {},
1137
+ abort: () => {
1138
+ abortController?.abort();
1139
+ },
1140
+ [EMITTER_SYMBOL]: emitter,
1141
+ engine: { step: this.inngestStep },
1142
+ abortSignal: abortController?.signal,
1143
+ });
1144
+ });
1145
+ }
1146
+
1147
+ if (!(date instanceof Date)) {
1148
+ return;
1149
+ }
1150
+
1151
+ await this.inngestStep.sleepUntil(entry.id, date);
1152
+ }
1153
+
1154
+ async executeWaitForEvent({ event, timeout }: { event: string; timeout?: number }): Promise<any> {
1155
+ const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
1156
+ event: `user-event-${event}`,
1157
+ timeout: timeout ?? 5e3,
1158
+ });
1159
+
1160
+ if (eventData === null) {
1161
+ throw 'Timeout waiting for event';
1162
+ }
1163
+
1164
+ return eventData?.data;
1165
+ }
1166
+
534
1167
  async executeStep({
535
1168
  step,
536
1169
  stepResults,
@@ -538,29 +1171,26 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
538
1171
  resume,
539
1172
  prevOutput,
540
1173
  emitter,
1174
+ abortController,
541
1175
  runtimeContext,
542
1176
  }: {
543
1177
  step: Step<string, any, any>;
544
1178
  stepResults: Record<string, StepResult<any, any, any, any>>;
545
- executionContext: {
546
- workflowId: string;
547
- runId: string;
548
- executionPath: number[];
549
- suspendedPaths: Record<string, number[]>;
550
- retryConfig: { attempts: number; delay: number };
551
- };
1179
+ executionContext: ExecutionContext;
552
1180
  resume?: {
553
1181
  steps: string[];
554
1182
  resumePayload: any;
555
1183
  runId?: string;
556
1184
  };
557
1185
  prevOutput: any;
558
- emitter: { emit: (event: string, data: any) => Promise<void> };
1186
+ emitter: Emitter;
1187
+ abortController: AbortController;
559
1188
  runtimeContext: RuntimeContext;
560
1189
  }): Promise<StepResult<any, any, any, any>> {
561
- await this.inngestStep.run(
1190
+ const startedAt = await this.inngestStep.run(
562
1191
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
563
1192
  async () => {
1193
+ const startedAt = Date.now();
564
1194
  await emitter.emit('watch', {
565
1195
  type: 'watch',
566
1196
  payload: {
@@ -582,6 +1212,18 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
582
1212
  },
583
1213
  eventTimestamp: Date.now(),
584
1214
  });
1215
+
1216
+ await emitter.emit('watch-v2', {
1217
+ type: 'step-start',
1218
+ payload: {
1219
+ id: step.id,
1220
+ status: 'running',
1221
+ payload: prevOutput,
1222
+ startedAt,
1223
+ },
1224
+ });
1225
+
1226
+ return startedAt;
585
1227
  },
586
1228
  );
587
1229
 
@@ -648,6 +1290,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
648
1290
  eventTimestamp: Date.now(),
649
1291
  });
650
1292
 
1293
+ await emitter.emit('watch-v2', {
1294
+ type: 'step-result',
1295
+ payload: {
1296
+ id: step.id,
1297
+ status: 'failed',
1298
+ error: result?.error,
1299
+ payload: prevOutput,
1300
+ },
1301
+ });
1302
+
651
1303
  return { executionContext, result: { status: 'failed', error: result?.error } };
652
1304
  } else if (result.status === 'suspended') {
653
1305
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
@@ -678,6 +1330,14 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
678
1330
  eventTimestamp: Date.now(),
679
1331
  });
680
1332
 
1333
+ await emitter.emit('watch-v2', {
1334
+ type: 'step-suspended',
1335
+ payload: {
1336
+ id: step.id,
1337
+ status: 'suspended',
1338
+ },
1339
+ });
1340
+
681
1341
  return {
682
1342
  executionContext,
683
1343
  result: {
@@ -734,6 +1394,23 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
734
1394
  eventTimestamp: Date.now(),
735
1395
  });
736
1396
 
1397
+ await emitter.emit('watch-v2', {
1398
+ type: 'step-result',
1399
+ payload: {
1400
+ id: step.id,
1401
+ status: 'success',
1402
+ output: result?.result,
1403
+ },
1404
+ });
1405
+
1406
+ await emitter.emit('watch-v2', {
1407
+ type: 'step-finish',
1408
+ payload: {
1409
+ id: step.id,
1410
+ metadata: {},
1411
+ },
1412
+ });
1413
+
737
1414
  return { executionContext, result: { status: 'success', output: result?.result } };
738
1415
  },
739
1416
  );
@@ -745,6 +1422,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
745
1422
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
746
1423
  let execResults: any;
747
1424
  let suspended: { payload: any } | undefined;
1425
+ let bailed: { payload: any } | undefined;
1426
+
748
1427
  try {
749
1428
  const result = await step.execute({
750
1429
  runId: executionContext.runId,
@@ -765,22 +1444,56 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
765
1444
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
766
1445
  suspended = { payload: suspendPayload };
767
1446
  },
1447
+ bail: (result: any) => {
1448
+ bailed = { payload: result };
1449
+ },
768
1450
  resume: {
769
1451
  steps: resume?.steps?.slice(1) || [],
770
1452
  resumePayload: resume?.resumePayload,
771
1453
  // @ts-ignore
772
1454
  runId: stepResults[step.id]?.payload?.__workflow_meta?.runId,
773
1455
  },
774
- emitter,
1456
+ [EMITTER_SYMBOL]: emitter,
1457
+ engine: {
1458
+ step: this.inngestStep,
1459
+ },
1460
+ abortSignal: abortController.signal,
775
1461
  });
776
-
777
- execResults = { status: 'success', output: result };
1462
+ const endedAt = Date.now();
1463
+
1464
+ execResults = {
1465
+ status: 'success',
1466
+ output: result,
1467
+ startedAt,
1468
+ endedAt,
1469
+ payload: prevOutput,
1470
+ resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1471
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1472
+ };
778
1473
  } catch (e) {
779
- execResults = { status: 'failed', error: e instanceof Error ? e.message : String(e) };
1474
+ execResults = {
1475
+ status: 'failed',
1476
+ payload: prevOutput,
1477
+ error: e instanceof Error ? e.message : String(e),
1478
+ endedAt: Date.now(),
1479
+ startedAt,
1480
+ resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1481
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1482
+ };
780
1483
  }
781
1484
 
782
1485
  if (suspended) {
783
- execResults = { status: 'suspended', payload: suspended.payload };
1486
+ execResults = {
1487
+ status: 'suspended',
1488
+ suspendedPayload: suspended.payload,
1489
+ payload: prevOutput,
1490
+ suspendedAt: Date.now(),
1491
+ startedAt,
1492
+ resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1493
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1494
+ };
1495
+ } else if (bailed) {
1496
+ execResults = { status: 'bailed', output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
784
1497
  }
785
1498
 
786
1499
  if (execResults.status === 'failed') {
@@ -794,12 +1507,11 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
794
1507
  payload: {
795
1508
  currentStep: {
796
1509
  id: step.id,
797
- status: execResults.status,
798
- output: execResults.output,
1510
+ ...execResults,
799
1511
  },
800
1512
  workflowState: {
801
1513
  status: 'running',
802
- steps: stepResults,
1514
+ steps: { ...stepResults, [step.id]: execResults },
803
1515
  result: null,
804
1516
  error: null,
805
1517
  },
@@ -807,6 +1519,32 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
807
1519
  eventTimestamp: Date.now(),
808
1520
  });
809
1521
 
1522
+ if (execResults.status === 'suspended') {
1523
+ await emitter.emit('watch-v2', {
1524
+ type: 'step-suspended',
1525
+ payload: {
1526
+ id: step.id,
1527
+ ...execResults,
1528
+ },
1529
+ });
1530
+ } else {
1531
+ await emitter.emit('watch-v2', {
1532
+ type: 'step-result',
1533
+ payload: {
1534
+ id: step.id,
1535
+ ...execResults,
1536
+ },
1537
+ });
1538
+
1539
+ await emitter.emit('watch-v2', {
1540
+ type: 'step-finish',
1541
+ payload: {
1542
+ id: step.id,
1543
+ metadata: {},
1544
+ },
1545
+ });
1546
+ }
1547
+
810
1548
  return { result: execResults, executionContext, stepResults };
811
1549
  });
812
1550
 
@@ -825,12 +1563,18 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
825
1563
  stepResults,
826
1564
  executionContext,
827
1565
  serializedStepGraph,
1566
+ workflowStatus,
1567
+ result,
1568
+ error,
828
1569
  }: {
829
1570
  workflowId: string;
830
1571
  runId: string;
831
1572
  stepResults: Record<string, StepResult<any, any, any, any>>;
832
1573
  serializedStepGraph: SerializedStepFlowEntry[];
833
1574
  executionContext: ExecutionContext;
1575
+ workflowStatus: 'success' | 'failed' | 'suspended' | 'running';
1576
+ result?: Record<string, any>;
1577
+ error?: string | Error;
834
1578
  }) {
835
1579
  await this.inngestStep.run(
836
1580
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -845,6 +1589,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
845
1589
  activePaths: [],
846
1590
  suspendedPaths: executionContext.suspendedPaths,
847
1591
  serializedStepGraph,
1592
+ status: workflowStatus,
1593
+ result,
1594
+ error,
848
1595
  // @ts-ignore
849
1596
  timestamp: Date.now(),
850
1597
  },
@@ -864,11 +1611,16 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
864
1611
  resume,
865
1612
  executionContext,
866
1613
  emitter,
1614
+ abortController,
867
1615
  runtimeContext,
868
1616
  }: {
869
1617
  workflowId: string;
870
1618
  runId: string;
871
- entry: { type: 'conditional'; steps: StepFlowEntry[]; conditions: ExecuteFunction<any, any, any, any>[] };
1619
+ entry: {
1620
+ type: 'conditional';
1621
+ steps: StepFlowEntry[];
1622
+ conditions: ExecuteFunction<any, any, any, any, InngestEngineType>[];
1623
+ };
872
1624
  prevStep: StepFlowEntry;
873
1625
  serializedStepGraph: SerializedStepFlowEntry[];
874
1626
  prevOutput: any;
@@ -880,7 +1632,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
880
1632
  resumePath: number[];
881
1633
  };
882
1634
  executionContext: ExecutionContext;
883
- emitter: { emit: (event: string, data: any) => Promise<void> };
1635
+ emitter: Emitter;
1636
+ abortController: AbortController;
884
1637
  runtimeContext: RuntimeContext;
885
1638
  }): Promise<StepResult<any, any, any, any>> {
886
1639
  let execResults: any;
@@ -893,6 +1646,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
893
1646
  runId,
894
1647
  mastra: this.mastra!,
895
1648
  runtimeContext,
1649
+ runCount: -1,
896
1650
  inputData: prevOutput,
897
1651
  getInitData: () => stepResults?.input as any,
898
1652
  getStepResult: (step: any) => {
@@ -910,7 +1664,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
910
1664
 
911
1665
  // TODO: this function shouldn't have suspend probably?
912
1666
  suspend: async (_suspendPayload: any) => {},
1667
+ bail: () => {},
1668
+ abort: () => {
1669
+ abortController.abort();
1670
+ },
913
1671
  [EMITTER_SYMBOL]: emitter,
1672
+ engine: {
1673
+ step: this.inngestStep,
1674
+ },
1675
+ abortSignal: abortController.signal,
914
1676
  });
915
1677
  return result ? index : null;
916
1678
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -923,7 +1685,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
923
1685
  ).filter((index: any): index is number => index !== null);
924
1686
 
925
1687
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
926
- const results: StepResult<any, any, any, any>[] = await Promise.all(
1688
+ const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
927
1689
  stepsToRun.map((step, index) =>
928
1690
  this.executeEntry({
929
1691
  workflowId,
@@ -942,21 +1704,24 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
942
1704
  executionSpan: executionContext.executionSpan,
943
1705
  },
944
1706
  emitter,
1707
+ abortController,
945
1708
  runtimeContext,
946
1709
  }),
947
1710
  ),
948
1711
  );
949
- const hasFailed = results.find(result => result.status === 'failed');
950
- const hasSuspended = results.find(result => result.status === 'suspended');
1712
+ const hasFailed = results.find(result => result.result.status === 'failed') as {
1713
+ result: StepFailure<any, any, any>;
1714
+ };
1715
+ const hasSuspended = results.find(result => result.result.status === 'suspended');
951
1716
  if (hasFailed) {
952
- execResults = { status: 'failed', error: hasFailed.error };
1717
+ execResults = { status: 'failed', error: hasFailed.result.error };
953
1718
  } else if (hasSuspended) {
954
- execResults = { status: 'suspended', payload: hasSuspended.payload };
1719
+ execResults = { status: 'suspended', payload: hasSuspended.result.suspendPayload };
955
1720
  } else {
956
1721
  execResults = {
957
1722
  status: 'success',
958
1723
  output: results.reduce((acc: Record<string, any>, result, index) => {
959
- if (result.status === 'success') {
1724
+ if (result.result.status === 'success') {
960
1725
  // @ts-ignore
961
1726
  acc[stepsToRun[index]!.step.id] = result.output;
962
1727
  }