@mastra/inngest 0.0.0-support-d1-client-20250701191943 → 0.0.0-suspendRuntimeContextTypeFix-20250930142630

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 DELETED
@@ -1,1583 +0,0 @@
1
- import { randomUUID } from 'crypto';
2
- import type { ReadableStream } from 'node:stream/web';
3
- import { subscribe } from '@inngest/realtime';
4
- import type { Agent, Mastra, ToolExecutionContext, WorkflowRun, WorkflowRuns } from '@mastra/core';
5
- import { RuntimeContext } from '@mastra/core/di';
6
- import { Tool } from '@mastra/core/tools';
7
- import { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
8
- import type {
9
- ExecuteFunction,
10
- ExecutionContext,
11
- ExecutionEngine,
12
- ExecutionGraph,
13
- Step,
14
- WorkflowConfig,
15
- StepFlowEntry,
16
- StepResult,
17
- WorkflowResult,
18
- SerializedStepFlowEntry,
19
- StepFailure,
20
- Emitter,
21
- WatchEvent,
22
- StreamEvent,
23
- } from '@mastra/core/workflows';
24
- import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
25
- import type { Span } from '@opentelemetry/api';
26
- import type { Inngest, BaseContext } from 'inngest';
27
- import { serve as inngestServe } from 'inngest/hono';
28
- import { z } from 'zod';
29
-
30
- export type InngestEngineType = {
31
- step: any;
32
- };
33
-
34
- export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest }): ReturnType<typeof inngestServe> {
35
- const wfs = mastra.getWorkflows();
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
- );
47
- return inngestServe({
48
- client: inngest,
49
- functions,
50
- });
51
- }
52
-
53
- export class InngestRun<
54
- TEngineType = InngestEngineType,
55
- TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
56
- TInput extends z.ZodType<any> = z.ZodType<any>,
57
- TOutput extends z.ZodType<any> = z.ZodType<any>,
58
- > extends Run<TEngineType, TSteps, TInput, TOutput> {
59
- private inngest: Inngest;
60
- serializedStepGraph: SerializedStepFlowEntry[];
61
- #mastra: Mastra;
62
-
63
- constructor(
64
- params: {
65
- workflowId: string;
66
- runId: string;
67
- executionEngine: ExecutionEngine;
68
- executionGraph: ExecutionGraph;
69
- serializedStepGraph: SerializedStepFlowEntry[];
70
- mastra?: Mastra;
71
- retryConfig?: {
72
- attempts?: number;
73
- delay?: number;
74
- };
75
- cleanup?: () => void;
76
- },
77
- inngest: Inngest,
78
- ) {
79
- super(params);
80
- this.inngest = inngest;
81
- this.serializedStepGraph = params.serializedStepGraph;
82
- this.#mastra = params.mastra!;
83
- }
84
-
85
- async getRuns(eventId: string) {
86
- const response = await fetch(`${this.inngest.apiBaseUrl ?? 'https://api.inngest.com'}/v1/events/${eventId}/runs`, {
87
- headers: {
88
- Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`,
89
- },
90
- });
91
- const json = await response.json();
92
- return (json as any).data;
93
- }
94
-
95
- async getRunOutput(eventId: string) {
96
- let runs = await this.getRuns(eventId);
97
-
98
- while (runs?.[0]?.status !== 'Completed' || runs?.[0]?.event_id !== eventId) {
99
- await new Promise(resolve => setTimeout(resolve, 1000));
100
- runs = await this.getRuns(eventId);
101
- if (runs?.[0]?.status === 'Failed') {
102
- throw new Error(`Function run ${runs?.[0]?.status}`);
103
- } else if (runs?.[0]?.status === 'Cancelled') {
104
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
105
- workflowName: this.workflowId,
106
- runId: this.runId,
107
- });
108
- return { output: { result: { steps: snapshot?.context, status: 'canceled' } } };
109
- }
110
- }
111
- return runs?.[0];
112
- }
113
-
114
- async sendEvent(event: string, data: any) {
115
- await this.inngest.send({
116
- name: `user-event-${event}`,
117
- data,
118
- });
119
- }
120
-
121
- async cancel() {
122
- await this.inngest.send({
123
- name: `cancel.workflow.${this.workflowId}`,
124
- data: {
125
- runId: this.runId,
126
- },
127
- });
128
-
129
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
130
- workflowName: this.workflowId,
131
- runId: this.runId,
132
- });
133
- if (snapshot) {
134
- await this.#mastra?.storage?.persistWorkflowSnapshot({
135
- workflowName: this.workflowId,
136
- runId: this.runId,
137
- snapshot: {
138
- ...snapshot,
139
- status: 'canceled' as any,
140
- },
141
- });
142
- }
143
- }
144
-
145
- async start({
146
- inputData,
147
- }: {
148
- inputData?: z.infer<TInput>;
149
- runtimeContext?: RuntimeContext;
150
- }): Promise<WorkflowResult<TOutput, TSteps>> {
151
- await this.#mastra.getStorage()?.persistWorkflowSnapshot({
152
- workflowName: this.workflowId,
153
- runId: this.runId,
154
- snapshot: {
155
- runId: this.runId,
156
- serializedStepGraph: this.serializedStepGraph,
157
- value: {},
158
- context: {} as any,
159
- activePaths: [],
160
- suspendedPaths: {},
161
- timestamp: Date.now(),
162
- status: 'running',
163
- },
164
- });
165
-
166
- const eventOutput = await this.inngest.send({
167
- name: `workflow.${this.workflowId}`,
168
- data: {
169
- inputData,
170
- runId: this.runId,
171
- },
172
- });
173
-
174
- const eventId = eventOutput.ids[0];
175
- if (!eventId) {
176
- throw new Error('Event ID is not set');
177
- }
178
- const runOutput = await this.getRunOutput(eventId);
179
- const result = runOutput?.output?.result;
180
- if (result.status === 'failed') {
181
- result.error = new Error(result.error);
182
- }
183
-
184
- if (result.status !== 'suspended') {
185
- this.cleanup?.();
186
- }
187
- return result;
188
- }
189
-
190
- async resume<TResumeSchema extends z.ZodType<any>>(params: {
191
- resumeData?: z.infer<TResumeSchema>;
192
- step:
193
- | Step<string, any, any, TResumeSchema, any>
194
- | [...Step<string, any, any, any, any>[], Step<string, any, any, TResumeSchema, any>]
195
- | string
196
- | string[];
197
- runtimeContext?: RuntimeContext;
198
- }): Promise<WorkflowResult<TOutput, TSteps>> {
199
- const p = this._resume(params).then(result => {
200
- if (result.status !== 'suspended') {
201
- this.closeStreamAction?.().catch(() => {});
202
- }
203
-
204
- return result;
205
- });
206
-
207
- this.executionResults = p;
208
- return p;
209
- }
210
-
211
- async _resume<TResumeSchema extends z.ZodType<any>>(params: {
212
- resumeData?: z.infer<TResumeSchema>;
213
- step:
214
- | Step<string, any, any, TResumeSchema, any>
215
- | [...Step<string, any, any, any, any>[], Step<string, any, any, TResumeSchema, any>]
216
- | string
217
- | string[];
218
- runtimeContext?: RuntimeContext;
219
- }): Promise<WorkflowResult<TOutput, TSteps>> {
220
- const steps: string[] = (Array.isArray(params.step) ? params.step : [params.step]).map(step =>
221
- typeof step === 'string' ? step : step?.id,
222
- );
223
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
224
- workflowName: this.workflowId,
225
- runId: this.runId,
226
- });
227
-
228
- const eventOutput = await this.inngest.send({
229
- name: `workflow.${this.workflowId}`,
230
- data: {
231
- inputData: params.resumeData,
232
- runId: this.runId,
233
- stepResults: snapshot?.context as any,
234
- resume: {
235
- steps,
236
- stepResults: snapshot?.context as any,
237
- resumePayload: params.resumeData,
238
- // @ts-ignore
239
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]] as any,
240
- },
241
- },
242
- });
243
-
244
- const eventId = eventOutput.ids[0];
245
- if (!eventId) {
246
- throw new Error('Event ID is not set');
247
- }
248
- const runOutput = await this.getRunOutput(eventId);
249
- const result = runOutput?.output?.result;
250
- if (result.status === 'failed') {
251
- result.error = new Error(result.error);
252
- }
253
- return result;
254
- }
255
-
256
- watch(cb: (event: WatchEvent) => void, type: 'watch' | 'watch-v2' = 'watch'): () => void {
257
- let active = true;
258
- const streamPromise = subscribe(
259
- {
260
- channel: `workflow:${this.workflowId}:${this.runId}`,
261
- topics: [type],
262
- app: this.inngest,
263
- },
264
- (message: any) => {
265
- if (active) {
266
- cb(message.data);
267
- }
268
- },
269
- );
270
-
271
- return () => {
272
- active = false;
273
- streamPromise
274
- .then(async (stream: Awaited<typeof streamPromise>) => {
275
- return stream.cancel();
276
- })
277
- .catch(err => {
278
- console.error(err);
279
- });
280
- };
281
- }
282
-
283
- stream({ inputData, runtimeContext }: { inputData?: z.infer<TInput>; runtimeContext?: RuntimeContext } = {}): {
284
- stream: ReadableStream<StreamEvent>;
285
- getWorkflowState: () => Promise<WorkflowResult<TOutput, TSteps>>;
286
- } {
287
- const { readable, writable } = new TransformStream<StreamEvent, StreamEvent>();
288
-
289
- const writer = writable.getWriter();
290
- const unwatch = this.watch(async event => {
291
- try {
292
- // watch-v2 events are data stream events, so we need to cast them to the correct type
293
- await writer.write(event as any);
294
- } catch {}
295
- }, 'watch-v2');
296
-
297
- this.closeStreamAction = async () => {
298
- unwatch();
299
-
300
- try {
301
- await writer.close();
302
- } catch (err) {
303
- console.error('Error closing stream:', err);
304
- } finally {
305
- writer.releaseLock();
306
- }
307
- };
308
-
309
- this.executionResults = this.start({ inputData, runtimeContext }).then(result => {
310
- if (result.status !== 'suspended') {
311
- this.closeStreamAction?.().catch(() => {});
312
- }
313
-
314
- return result;
315
- });
316
-
317
- return {
318
- stream: readable as ReadableStream<StreamEvent>,
319
- getWorkflowState: () => this.executionResults!,
320
- };
321
- }
322
- }
323
-
324
- export class InngestWorkflow<
325
- TEngineType = InngestEngineType,
326
- TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
327
- TWorkflowId extends string = string,
328
- TInput extends z.ZodType<any> = z.ZodType<any>,
329
- TOutput extends z.ZodType<any> = z.ZodType<any>,
330
- TPrevSchema extends z.ZodType<any> = TInput,
331
- > extends Workflow<TEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
332
- #mastra: Mastra;
333
- public inngest: Inngest;
334
-
335
- private function: ReturnType<Inngest['createFunction']> | undefined;
336
-
337
- constructor(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>, inngest: Inngest) {
338
- super(params);
339
- this.#mastra = params.mastra!;
340
- this.inngest = inngest;
341
- }
342
-
343
- async getWorkflowRuns(args?: {
344
- fromDate?: Date;
345
- toDate?: Date;
346
- limit?: number;
347
- offset?: number;
348
- resourceId?: string;
349
- }) {
350
- const storage = this.#mastra?.getStorage();
351
- if (!storage) {
352
- this.logger.debug('Cannot get workflow runs. Mastra engine is not initialized');
353
- return { runs: [], total: 0 };
354
- }
355
-
356
- return storage.getWorkflowRuns({ workflowName: this.id, ...(args ?? {}) }) as unknown as WorkflowRuns;
357
- }
358
-
359
- async getWorkflowRunById(runId: string): Promise<WorkflowRun | null> {
360
- const storage = this.#mastra?.getStorage();
361
- if (!storage) {
362
- this.logger.debug('Cannot get workflow runs. Mastra engine is not initialized');
363
- //returning in memory run if no storage is initialized
364
- return this.runs.get(runId)
365
- ? ({ ...this.runs.get(runId), workflowName: this.id } as unknown as WorkflowRun)
366
- : null;
367
- }
368
- const run = (await storage.getWorkflowRunById({ runId, workflowName: this.id })) as unknown as WorkflowRun;
369
-
370
- return (
371
- run ??
372
- (this.runs.get(runId) ? ({ ...this.runs.get(runId), workflowName: this.id } as unknown as WorkflowRun) : null)
373
- );
374
- }
375
-
376
- async getWorkflowRunExecutionResult(runId: string): Promise<WatchEvent['payload']['workflowState'] | null> {
377
- const storage = this.#mastra?.getStorage();
378
- if (!storage) {
379
- this.logger.debug('Cannot get workflow run execution result. Mastra storage is not initialized');
380
- return null;
381
- }
382
-
383
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
384
-
385
- if (!run?.snapshot) {
386
- return null;
387
- }
388
-
389
- if (typeof run.snapshot === 'string') {
390
- return null;
391
- }
392
-
393
- return {
394
- status: run.snapshot.status,
395
- result: run.snapshot.result,
396
- error: run.snapshot.error,
397
- payload: run.snapshot.context?.input,
398
- steps: run.snapshot.context as any,
399
- };
400
- }
401
-
402
- __registerMastra(mastra: Mastra) {
403
- this.#mastra = mastra;
404
- this.executionEngine.__registerMastra(mastra);
405
- const updateNested = (step: StepFlowEntry) => {
406
- if (
407
- (step.type === 'step' || step.type === 'loop' || step.type === 'foreach') &&
408
- step.step instanceof InngestWorkflow
409
- ) {
410
- step.step.__registerMastra(mastra);
411
- } else if (step.type === 'parallel' || step.type === 'conditional') {
412
- for (const subStep of step.steps) {
413
- updateNested(subStep);
414
- }
415
- }
416
- };
417
-
418
- if (this.executionGraph.steps.length) {
419
- for (const step of this.executionGraph.steps) {
420
- updateNested(step);
421
- }
422
- }
423
- }
424
-
425
- createRun(options?: { runId?: string }): Run<TEngineType, TSteps, TInput, TOutput> {
426
- const runIdToUse = options?.runId || randomUUID();
427
-
428
- // Return a new Run instance with object parameters
429
- const run: Run<TEngineType, TSteps, TInput, TOutput> =
430
- this.runs.get(runIdToUse) ??
431
- new InngestRun(
432
- {
433
- workflowId: this.id,
434
- runId: runIdToUse,
435
- executionEngine: this.executionEngine,
436
- executionGraph: this.executionGraph,
437
- serializedStepGraph: this.serializedStepGraph,
438
- mastra: this.#mastra,
439
- retryConfig: this.retryConfig,
440
- cleanup: () => this.runs.delete(runIdToUse),
441
- },
442
- this.inngest,
443
- );
444
-
445
- this.runs.set(runIdToUse, run);
446
- return run;
447
- }
448
-
449
- async createRunAsync(options?: { runId?: string }): Promise<Run<TEngineType, TSteps, TInput, TOutput>> {
450
- const runIdToUse = options?.runId || randomUUID();
451
-
452
- // Return a new Run instance with object parameters
453
- const run: Run<TEngineType, TSteps, TInput, TOutput> =
454
- this.runs.get(runIdToUse) ??
455
- new InngestRun(
456
- {
457
- workflowId: this.id,
458
- runId: runIdToUse,
459
- executionEngine: this.executionEngine,
460
- executionGraph: this.executionGraph,
461
- serializedStepGraph: this.serializedStepGraph,
462
- mastra: this.#mastra,
463
- retryConfig: this.retryConfig,
464
- cleanup: () => this.runs.delete(runIdToUse),
465
- },
466
- this.inngest,
467
- );
468
-
469
- this.runs.set(runIdToUse, run);
470
-
471
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
472
-
473
- if (!workflowSnapshotInStorage) {
474
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
475
- workflowName: this.id,
476
- runId: runIdToUse,
477
- snapshot: {
478
- runId: runIdToUse,
479
- status: 'pending',
480
- value: {},
481
- context: {},
482
- activePaths: [],
483
- serializedStepGraph: this.serializedStepGraph,
484
- suspendedPaths: {},
485
- result: undefined,
486
- error: undefined,
487
- // @ts-ignore
488
- timestamp: Date.now(),
489
- },
490
- });
491
- }
492
-
493
- return run;
494
- }
495
-
496
- getFunction() {
497
- if (this.function) {
498
- return this.function;
499
- }
500
- this.function = this.inngest.createFunction(
501
- {
502
- id: `workflow.${this.id}`,
503
- // @ts-ignore
504
- retries: this.retryConfig?.attempts ?? 0,
505
- cancelOn: [{ event: `cancel.workflow.${this.id}` }],
506
- },
507
- { event: `workflow.${this.id}` },
508
- async ({ event, step, attempt, publish }) => {
509
- let { inputData, runId, resume } = event.data;
510
-
511
- if (!runId) {
512
- runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
513
- return randomUUID();
514
- });
515
- }
516
-
517
- const emitter = {
518
- emit: async (event: string, data: any) => {
519
- if (!publish) {
520
- return;
521
- }
522
-
523
- try {
524
- await publish({
525
- channel: `workflow:${this.id}:${runId}`,
526
- topic: event,
527
- data,
528
- });
529
- } catch (err: any) {
530
- this.logger.error('Error emitting event: ' + (err?.stack ?? err?.message ?? err));
531
- }
532
- },
533
- on: (_event: string, _callback: (data: any) => void) => {
534
- // no-op
535
- },
536
- off: (_event: string, _callback: (data: any) => void) => {
537
- // no-op
538
- },
539
- once: (_event: string, _callback: (data: any) => void) => {
540
- // no-op
541
- },
542
- };
543
-
544
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
545
- const result = await engine.execute<z.infer<TInput>, WorkflowResult<TOutput, TSteps>>({
546
- workflowId: this.id,
547
- runId,
548
- graph: this.executionGraph,
549
- serializedStepGraph: this.serializedStepGraph,
550
- input: inputData,
551
- emitter,
552
- retryConfig: this.retryConfig,
553
- runtimeContext: new RuntimeContext(), // TODO
554
- resume,
555
- abortController: new AbortController(),
556
- });
557
-
558
- return { result, runId };
559
- },
560
- );
561
- return this.function;
562
- }
563
-
564
- getNestedFunctions(steps: StepFlowEntry[]): ReturnType<Inngest['createFunction']>[] {
565
- return steps.flatMap(step => {
566
- if (step.type === 'step' || step.type === 'loop' || step.type === 'foreach') {
567
- if (step.step instanceof InngestWorkflow) {
568
- return [step.step.getFunction(), ...step.step.getNestedFunctions(step.step.executionGraph.steps)];
569
- }
570
- return [];
571
- } else if (step.type === 'parallel' || step.type === 'conditional') {
572
- return this.getNestedFunctions(step.steps);
573
- }
574
-
575
- return [];
576
- });
577
- }
578
-
579
- getFunctions() {
580
- return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
581
- }
582
- }
583
-
584
- function isAgent(params: any): params is Agent<any, any, any> {
585
- return params?.component === 'AGENT';
586
- }
587
-
588
- function isTool(params: any): params is Tool<any, any, any> {
589
- return params instanceof Tool;
590
- }
591
-
592
- export function createStep<
593
- TStepId extends string,
594
- TStepInput extends z.ZodType<any>,
595
- TStepOutput extends z.ZodType<any>,
596
- TResumeSchema extends z.ZodType<any>,
597
- TSuspendSchema extends z.ZodType<any>,
598
- >(params: {
599
- id: TStepId;
600
- description?: string;
601
- inputSchema: TStepInput;
602
- outputSchema: TStepOutput;
603
- resumeSchema?: TResumeSchema;
604
- suspendSchema?: TSuspendSchema;
605
- execute: ExecuteFunction<
606
- z.infer<TStepInput>,
607
- z.infer<TStepOutput>,
608
- z.infer<TResumeSchema>,
609
- z.infer<TSuspendSchema>,
610
- InngestEngineType
611
- >;
612
- }): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
613
-
614
- export function createStep<
615
- TStepId extends string,
616
- TStepInput extends z.ZodObject<{ prompt: z.ZodString }>,
617
- TStepOutput extends z.ZodObject<{ text: z.ZodString }>,
618
- TResumeSchema extends z.ZodType<any>,
619
- TSuspendSchema extends z.ZodType<any>,
620
- >(
621
- agent: Agent<TStepId, any, any>,
622
- ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
623
-
624
- export function createStep<
625
- TSchemaIn extends z.ZodType<any>,
626
- TSchemaOut extends z.ZodType<any>,
627
- TContext extends ToolExecutionContext<TSchemaIn>,
628
- >(
629
- tool: Tool<TSchemaIn, TSchemaOut, TContext> & {
630
- inputSchema: TSchemaIn;
631
- outputSchema: TSchemaOut;
632
- execute: (context: TContext) => Promise<any>;
633
- },
634
- ): Step<string, TSchemaIn, TSchemaOut, z.ZodType<any>, z.ZodType<any>, InngestEngineType>;
635
- export function createStep<
636
- TStepId extends string,
637
- TStepInput extends z.ZodType<any>,
638
- TStepOutput extends z.ZodType<any>,
639
- TResumeSchema extends z.ZodType<any>,
640
- TSuspendSchema extends z.ZodType<any>,
641
- >(
642
- params:
643
- | {
644
- id: TStepId;
645
- description?: string;
646
- inputSchema: TStepInput;
647
- outputSchema: TStepOutput;
648
- resumeSchema?: TResumeSchema;
649
- suspendSchema?: TSuspendSchema;
650
- execute: ExecuteFunction<
651
- z.infer<TStepInput>,
652
- z.infer<TStepOutput>,
653
- z.infer<TResumeSchema>,
654
- z.infer<TSuspendSchema>,
655
- InngestEngineType
656
- >;
657
- }
658
- | Agent<any, any, any>
659
- | (Tool<TStepInput, TStepOutput, any> & {
660
- inputSchema: TStepInput;
661
- outputSchema: TStepOutput;
662
- execute: (context: ToolExecutionContext<TStepInput>) => Promise<any>;
663
- }),
664
- ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType> {
665
- if (isAgent(params)) {
666
- return {
667
- id: params.name,
668
- // @ts-ignore
669
- inputSchema: z.object({
670
- prompt: z.string(),
671
- // resourceId: z.string().optional(),
672
- // threadId: z.string().optional(),
673
- }),
674
- // @ts-ignore
675
- outputSchema: z.object({
676
- text: z.string(),
677
- }),
678
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
679
- let streamPromise = {} as {
680
- promise: Promise<string>;
681
- resolve: (value: string) => void;
682
- reject: (reason?: any) => void;
683
- };
684
-
685
- streamPromise.promise = new Promise((resolve, reject) => {
686
- streamPromise.resolve = resolve;
687
- streamPromise.reject = reject;
688
- });
689
- const toolData = {
690
- name: params.name,
691
- args: inputData,
692
- };
693
- await emitter.emit('watch-v2', {
694
- type: 'tool-call-streaming-start',
695
- ...toolData,
696
- });
697
- const { fullStream } = await params.stream(inputData.prompt, {
698
- // resourceId: inputData.resourceId,
699
- // threadId: inputData.threadId,
700
- runtimeContext,
701
- onFinish: result => {
702
- streamPromise.resolve(result.text);
703
- },
704
- abortSignal,
705
- });
706
-
707
- if (abortSignal.aborted) {
708
- return abort();
709
- }
710
-
711
- for await (const chunk of fullStream) {
712
- switch (chunk.type) {
713
- case 'text-delta':
714
- await emitter.emit('watch-v2', {
715
- type: 'tool-call-delta',
716
- ...toolData,
717
- argsTextDelta: chunk.textDelta,
718
- });
719
- break;
720
-
721
- case 'step-start':
722
- case 'step-finish':
723
- case 'finish':
724
- break;
725
-
726
- case 'tool-call':
727
- case 'tool-result':
728
- case 'tool-call-streaming-start':
729
- case 'tool-call-delta':
730
- case 'source':
731
- case 'file':
732
- default:
733
- await emitter.emit('watch-v2', chunk);
734
- break;
735
- }
736
- }
737
-
738
- return {
739
- text: await streamPromise.promise,
740
- };
741
- },
742
- };
743
- }
744
-
745
- if (isTool(params)) {
746
- if (!params.inputSchema || !params.outputSchema) {
747
- throw new Error('Tool must have input and output schemas defined');
748
- }
749
-
750
- return {
751
- // TODO: tool probably should have strong id type
752
- // @ts-ignore
753
- id: params.id,
754
- inputSchema: params.inputSchema,
755
- outputSchema: params.outputSchema,
756
- execute: async ({ inputData, mastra, runtimeContext }) => {
757
- return params.execute({
758
- context: inputData,
759
- mastra,
760
- runtimeContext,
761
- });
762
- },
763
- };
764
- }
765
-
766
- return {
767
- id: params.id,
768
- description: params.description,
769
- inputSchema: params.inputSchema,
770
- outputSchema: params.outputSchema,
771
- resumeSchema: params.resumeSchema,
772
- suspendSchema: params.suspendSchema,
773
- execute: params.execute,
774
- };
775
- }
776
-
777
- export function init(inngest: Inngest) {
778
- return {
779
- createWorkflow<
780
- TWorkflowId extends string = string,
781
- TInput extends z.ZodType<any> = z.ZodType<any>,
782
- TOutput extends z.ZodType<any> = z.ZodType<any>,
783
- TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
784
- string,
785
- any,
786
- any,
787
- any,
788
- any,
789
- InngestEngineType
790
- >[],
791
- >(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>) {
792
- return new InngestWorkflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TInput>(params, inngest);
793
- },
794
- createStep,
795
- cloneStep<TStepId extends string>(
796
- step: Step<string, any, any, any, any, InngestEngineType>,
797
- opts: { id: TStepId },
798
- ): Step<TStepId, any, any, any, any, InngestEngineType> {
799
- return {
800
- id: opts.id,
801
- description: step.description,
802
- inputSchema: step.inputSchema,
803
- outputSchema: step.outputSchema,
804
- execute: step.execute,
805
- };
806
- },
807
- cloneWorkflow<
808
- TWorkflowId extends string = string,
809
- TInput extends z.ZodType<any> = z.ZodType<any>,
810
- TOutput extends z.ZodType<any> = z.ZodType<any>,
811
- TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
812
- string,
813
- any,
814
- any,
815
- any,
816
- any,
817
- InngestEngineType
818
- >[],
819
- TPrevSchema extends z.ZodType<any> = TInput,
820
- >(
821
- workflow: Workflow<InngestEngineType, TSteps, string, TInput, TOutput, TPrevSchema>,
822
- opts: { id: TWorkflowId },
823
- ): Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
824
- const wf: Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> = new Workflow({
825
- id: opts.id,
826
- inputSchema: workflow.inputSchema,
827
- outputSchema: workflow.outputSchema,
828
- steps: workflow.stepDefs,
829
- mastra: workflow.mastra,
830
- });
831
-
832
- wf.setStepFlow(workflow.stepGraph);
833
- wf.commit();
834
- return wf;
835
- },
836
- };
837
- }
838
-
839
- export class InngestExecutionEngine extends DefaultExecutionEngine {
840
- private inngestStep: BaseContext<Inngest>['step'];
841
- private inngestAttempts: number;
842
-
843
- constructor(mastra: Mastra, inngestStep: BaseContext<Inngest>['step'], inngestAttempts: number = 0) {
844
- super({ mastra });
845
- this.inngestStep = inngestStep;
846
- this.inngestAttempts = inngestAttempts;
847
- }
848
-
849
- async execute<TInput, TOutput>(params: {
850
- workflowId: string;
851
- runId: string;
852
- graph: ExecutionGraph;
853
- serializedStepGraph: SerializedStepFlowEntry[];
854
- input?: TInput;
855
- resume?: {
856
- // TODO: add execute path
857
- steps: string[];
858
- stepResults: Record<string, StepResult<any, any, any, any>>;
859
- resumePayload: any;
860
- resumePath: number[];
861
- };
862
- emitter: Emitter;
863
- retryConfig?: {
864
- attempts?: number;
865
- delay?: number;
866
- };
867
- runtimeContext: RuntimeContext;
868
- abortController: AbortController;
869
- }): Promise<TOutput> {
870
- await params.emitter.emit('watch-v2', {
871
- type: 'start',
872
- payload: { runId: params.runId },
873
- });
874
-
875
- const result = await super.execute<TInput, TOutput>(params);
876
-
877
- await params.emitter.emit('watch-v2', {
878
- type: 'finish',
879
- payload: { runId: params.runId },
880
- });
881
-
882
- return result;
883
- }
884
-
885
- protected async fmtReturnValue<TOutput>(
886
- executionSpan: Span | undefined,
887
- emitter: Emitter,
888
- stepResults: Record<string, StepResult<any, any, any, any>>,
889
- lastOutput: StepResult<any, any, any, any>,
890
- error?: Error | string,
891
- ): Promise<TOutput> {
892
- const base: any = {
893
- status: lastOutput.status,
894
- steps: stepResults,
895
- };
896
- if (lastOutput.status === 'success') {
897
- await emitter.emit('watch', {
898
- type: 'watch',
899
- payload: {
900
- workflowState: {
901
- status: lastOutput.status,
902
- steps: stepResults,
903
- result: lastOutput.output,
904
- },
905
- },
906
- eventTimestamp: Date.now(),
907
- });
908
-
909
- base.result = lastOutput.output;
910
- } else if (lastOutput.status === 'failed') {
911
- base.error =
912
- error instanceof Error
913
- ? (error?.stack ?? error.message)
914
- : lastOutput?.error instanceof Error
915
- ? lastOutput.error.message
916
- : (lastOutput.error ?? error ?? 'Unknown error');
917
-
918
- await emitter.emit('watch', {
919
- type: 'watch',
920
- payload: {
921
- workflowState: {
922
- status: lastOutput.status,
923
- steps: stepResults,
924
- result: null,
925
- error: base.error,
926
- },
927
- },
928
- eventTimestamp: Date.now(),
929
- });
930
- } else if (lastOutput.status === 'suspended') {
931
- await emitter.emit('watch', {
932
- type: 'watch',
933
- payload: {
934
- workflowState: {
935
- status: lastOutput.status,
936
- steps: stepResults,
937
- result: null,
938
- error: null,
939
- },
940
- },
941
- eventTimestamp: Date.now(),
942
- });
943
-
944
- const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
945
- if (stepResult?.status === 'suspended') {
946
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
947
- return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
948
- }
949
-
950
- return [];
951
- });
952
- base.suspended = suspendedStepIds;
953
- }
954
-
955
- executionSpan?.end();
956
- return base as TOutput;
957
- }
958
-
959
- async superExecuteStep({
960
- workflowId,
961
- runId,
962
- step,
963
- stepResults,
964
- executionContext,
965
- resume,
966
- prevOutput,
967
- emitter,
968
- abortController,
969
- runtimeContext,
970
- }: {
971
- workflowId: string;
972
- runId: string;
973
- step: Step<string, any, any>;
974
- stepResults: Record<string, StepResult<any, any, any, any>>;
975
- executionContext: ExecutionContext;
976
- resume?: {
977
- steps: string[];
978
- resumePayload: any;
979
- };
980
- prevOutput: any;
981
- emitter: Emitter;
982
- abortController: AbortController;
983
- runtimeContext: RuntimeContext;
984
- }): Promise<StepResult<any, any, any, any>> {
985
- return super.executeStep({
986
- workflowId,
987
- runId,
988
- step,
989
- stepResults,
990
- executionContext,
991
- resume,
992
- prevOutput,
993
- emitter,
994
- abortController,
995
- runtimeContext,
996
- });
997
- }
998
-
999
- async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
1000
- await this.inngestStep.sleep(id, duration);
1001
- }
1002
-
1003
- async executeWaitForEvent({ event, timeout }: { event: string; timeout?: number }): Promise<any> {
1004
- const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
1005
- event: `user-event-${event}`,
1006
- timeout: timeout ?? 5e3,
1007
- });
1008
-
1009
- if (eventData === null) {
1010
- throw 'Timeout waiting for event';
1011
- }
1012
-
1013
- return eventData?.data;
1014
- }
1015
-
1016
- async executeStep({
1017
- step,
1018
- stepResults,
1019
- executionContext,
1020
- resume,
1021
- prevOutput,
1022
- emitter,
1023
- abortController,
1024
- runtimeContext,
1025
- }: {
1026
- step: Step<string, any, any>;
1027
- stepResults: Record<string, StepResult<any, any, any, any>>;
1028
- executionContext: ExecutionContext;
1029
- resume?: {
1030
- steps: string[];
1031
- resumePayload: any;
1032
- runId?: string;
1033
- };
1034
- prevOutput: any;
1035
- emitter: Emitter;
1036
- abortController: AbortController;
1037
- runtimeContext: RuntimeContext;
1038
- }): Promise<StepResult<any, any, any, any>> {
1039
- const startedAt = await this.inngestStep.run(
1040
- `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
1041
- async () => {
1042
- const startedAt = Date.now();
1043
- await emitter.emit('watch', {
1044
- type: 'watch',
1045
- payload: {
1046
- currentStep: {
1047
- id: step.id,
1048
- status: 'running',
1049
- },
1050
- workflowState: {
1051
- status: 'running',
1052
- steps: {
1053
- ...stepResults,
1054
- [step.id]: {
1055
- status: 'running',
1056
- },
1057
- },
1058
- result: null,
1059
- error: null,
1060
- },
1061
- },
1062
- eventTimestamp: Date.now(),
1063
- });
1064
-
1065
- await emitter.emit('watch-v2', {
1066
- type: 'step-start',
1067
- payload: {
1068
- id: step.id,
1069
- status: 'running',
1070
- },
1071
- });
1072
-
1073
- return startedAt;
1074
- },
1075
- );
1076
-
1077
- if (step instanceof InngestWorkflow) {
1078
- const isResume = !!resume?.steps?.length;
1079
- let result: WorkflowResult<any, any>;
1080
- let runId: string;
1081
- if (isResume) {
1082
- // @ts-ignore
1083
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? randomUUID();
1084
-
1085
- const snapshot: any = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1086
- workflowName: step.id,
1087
- runId: runId,
1088
- });
1089
-
1090
- const invokeResp = (await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1091
- function: step.getFunction(),
1092
- data: {
1093
- inputData: prevOutput,
1094
- runId: runId,
1095
- resume: {
1096
- runId: runId,
1097
- steps: resume.steps.slice(1),
1098
- stepResults: snapshot?.context as any,
1099
- resumePayload: resume.resumePayload,
1100
- // @ts-ignore
1101
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]] as any,
1102
- },
1103
- },
1104
- })) as any;
1105
- result = invokeResp.result;
1106
- runId = invokeResp.runId;
1107
- } else {
1108
- const invokeResp = (await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1109
- function: step.getFunction(),
1110
- data: {
1111
- inputData: prevOutput,
1112
- },
1113
- })) as any;
1114
- result = invokeResp.result;
1115
- runId = invokeResp.runId;
1116
- }
1117
-
1118
- const res = await this.inngestStep.run(
1119
- `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
1120
- async () => {
1121
- if (result.status === 'failed') {
1122
- await emitter.emit('watch', {
1123
- type: 'watch',
1124
- payload: {
1125
- currentStep: {
1126
- id: step.id,
1127
- status: 'failed',
1128
- error: result?.error,
1129
- },
1130
- workflowState: {
1131
- status: 'running',
1132
- steps: stepResults,
1133
- result: null,
1134
- error: null,
1135
- },
1136
- },
1137
- eventTimestamp: Date.now(),
1138
- });
1139
-
1140
- await emitter.emit('watch-v2', {
1141
- type: 'step-result',
1142
- payload: {
1143
- id: step.id,
1144
- status: 'failed',
1145
- error: result?.error,
1146
- payload: prevOutput,
1147
- },
1148
- });
1149
-
1150
- return { executionContext, result: { status: 'failed', error: result?.error } };
1151
- } else if (result.status === 'suspended') {
1152
- const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
1153
- const stepRes: StepResult<any, any, any, any> = stepResult as StepResult<any, any, any, any>;
1154
- return stepRes?.status === 'suspended';
1155
- });
1156
-
1157
- for (const [stepName, stepResult] of suspendedSteps) {
1158
- // @ts-ignore
1159
- const suspendPath: string[] = [stepName, ...(stepResult?.payload?.__workflow_meta?.path ?? [])];
1160
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1161
-
1162
- await emitter.emit('watch', {
1163
- type: 'watch',
1164
- payload: {
1165
- currentStep: {
1166
- id: step.id,
1167
- status: 'suspended',
1168
- payload: { ...(stepResult as any)?.payload, __workflow_meta: { runId: runId, path: suspendPath } },
1169
- },
1170
- workflowState: {
1171
- status: 'running',
1172
- steps: stepResults,
1173
- result: null,
1174
- error: null,
1175
- },
1176
- },
1177
- eventTimestamp: Date.now(),
1178
- });
1179
-
1180
- await emitter.emit('watch-v2', {
1181
- type: 'step-suspended',
1182
- payload: {
1183
- id: step.id,
1184
- status: 'suspended',
1185
- },
1186
- });
1187
-
1188
- return {
1189
- executionContext,
1190
- result: {
1191
- status: 'suspended',
1192
- payload: { ...(stepResult as any)?.payload, __workflow_meta: { runId: runId, path: suspendPath } },
1193
- },
1194
- };
1195
- }
1196
-
1197
- await emitter.emit('watch', {
1198
- type: 'watch',
1199
- payload: {
1200
- currentStep: {
1201
- id: step.id,
1202
- status: 'suspended',
1203
- payload: {},
1204
- },
1205
- workflowState: {
1206
- status: 'running',
1207
- steps: stepResults,
1208
- result: null,
1209
- error: null,
1210
- },
1211
- },
1212
- eventTimestamp: Date.now(),
1213
- });
1214
-
1215
- return {
1216
- executionContext,
1217
- result: {
1218
- status: 'suspended',
1219
- payload: {},
1220
- },
1221
- };
1222
- }
1223
-
1224
- // is success
1225
-
1226
- await emitter.emit('watch', {
1227
- type: 'watch',
1228
- payload: {
1229
- currentStep: {
1230
- id: step.id,
1231
- status: 'success',
1232
- output: result?.result,
1233
- },
1234
- workflowState: {
1235
- status: 'running',
1236
- steps: stepResults,
1237
- result: null,
1238
- error: null,
1239
- },
1240
- },
1241
- eventTimestamp: Date.now(),
1242
- });
1243
-
1244
- await emitter.emit('watch-v2', {
1245
- type: 'step-result',
1246
- payload: {
1247
- id: step.id,
1248
- status: 'success',
1249
- output: result?.result,
1250
- },
1251
- });
1252
-
1253
- await emitter.emit('watch-v2', {
1254
- type: 'step-finish',
1255
- payload: {
1256
- id: step.id,
1257
- metadata: {},
1258
- },
1259
- });
1260
-
1261
- return { executionContext, result: { status: 'success', output: result?.result } };
1262
- },
1263
- );
1264
-
1265
- Object.assign(executionContext, res.executionContext);
1266
- return res.result as StepResult<any, any, any, any>;
1267
- }
1268
-
1269
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1270
- let execResults: any;
1271
- let suspended: { payload: any } | undefined;
1272
- let bailed: { payload: any } | undefined;
1273
-
1274
- try {
1275
- const result = await step.execute({
1276
- runId: executionContext.runId,
1277
- mastra: this.mastra!,
1278
- runtimeContext,
1279
- inputData: prevOutput,
1280
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1281
- getInitData: () => stepResults?.input as any,
1282
- getStepResult: (step: any) => {
1283
- const result = stepResults[step.id];
1284
- if (result?.status === 'success') {
1285
- return result.output;
1286
- }
1287
-
1288
- return null;
1289
- },
1290
- suspend: async (suspendPayload: any) => {
1291
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1292
- suspended = { payload: suspendPayload };
1293
- },
1294
- bail: (result: any) => {
1295
- bailed = { payload: result };
1296
- },
1297
- resume: {
1298
- steps: resume?.steps?.slice(1) || [],
1299
- resumePayload: resume?.resumePayload,
1300
- // @ts-ignore
1301
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId,
1302
- },
1303
- [EMITTER_SYMBOL]: emitter,
1304
- engine: {
1305
- step: this.inngestStep,
1306
- },
1307
- abortSignal: abortController.signal,
1308
- });
1309
- const endedAt = Date.now();
1310
-
1311
- execResults = {
1312
- status: 'success',
1313
- output: result,
1314
- startedAt,
1315
- endedAt,
1316
- payload: prevOutput,
1317
- resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1318
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1319
- };
1320
- } catch (e) {
1321
- execResults = {
1322
- status: 'failed',
1323
- payload: prevOutput,
1324
- error: e instanceof Error ? e.message : String(e),
1325
- endedAt: Date.now(),
1326
- startedAt,
1327
- resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1328
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1329
- };
1330
- }
1331
-
1332
- if (suspended) {
1333
- execResults = {
1334
- status: 'suspended',
1335
- suspendedPayload: suspended.payload,
1336
- payload: prevOutput,
1337
- suspendedAt: Date.now(),
1338
- startedAt,
1339
- resumedAt: resume?.steps[0] === step.id ? startedAt : undefined,
1340
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : undefined,
1341
- };
1342
- } else if (bailed) {
1343
- execResults = { status: 'bailed', output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1344
- }
1345
-
1346
- if (execResults.status === 'failed') {
1347
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1348
- throw execResults.error;
1349
- }
1350
- }
1351
-
1352
- await emitter.emit('watch', {
1353
- type: 'watch',
1354
- payload: {
1355
- currentStep: {
1356
- id: step.id,
1357
- ...execResults,
1358
- },
1359
- workflowState: {
1360
- status: 'running',
1361
- steps: { ...stepResults, [step.id]: execResults },
1362
- result: null,
1363
- error: null,
1364
- },
1365
- },
1366
- eventTimestamp: Date.now(),
1367
- });
1368
-
1369
- if (execResults.status === 'suspended') {
1370
- await emitter.emit('watch-v2', {
1371
- type: 'step-suspended',
1372
- payload: {
1373
- id: step.id,
1374
- ...execResults,
1375
- },
1376
- });
1377
- } else {
1378
- await emitter.emit('watch-v2', {
1379
- type: 'step-result',
1380
- payload: {
1381
- id: step.id,
1382
- ...execResults,
1383
- },
1384
- });
1385
-
1386
- await emitter.emit('watch-v2', {
1387
- type: 'step-finish',
1388
- payload: {
1389
- id: step.id,
1390
- metadata: {},
1391
- },
1392
- });
1393
- }
1394
-
1395
- return { result: execResults, executionContext, stepResults };
1396
- });
1397
-
1398
- // @ts-ignore
1399
- Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1400
- // @ts-ignore
1401
- Object.assign(stepResults, stepRes.stepResults);
1402
-
1403
- // @ts-ignore
1404
- return stepRes.result;
1405
- }
1406
-
1407
- async persistStepUpdate({
1408
- workflowId,
1409
- runId,
1410
- stepResults,
1411
- executionContext,
1412
- serializedStepGraph,
1413
- workflowStatus,
1414
- result,
1415
- error,
1416
- }: {
1417
- workflowId: string;
1418
- runId: string;
1419
- stepResults: Record<string, StepResult<any, any, any, any>>;
1420
- serializedStepGraph: SerializedStepFlowEntry[];
1421
- executionContext: ExecutionContext;
1422
- workflowStatus: 'success' | 'failed' | 'suspended' | 'running';
1423
- result?: Record<string, any>;
1424
- error?: string | Error;
1425
- }) {
1426
- await this.inngestStep.run(
1427
- `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1428
- async () => {
1429
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1430
- workflowName: workflowId,
1431
- runId,
1432
- snapshot: {
1433
- runId,
1434
- value: {},
1435
- context: stepResults as any,
1436
- activePaths: [],
1437
- suspendedPaths: executionContext.suspendedPaths,
1438
- serializedStepGraph,
1439
- status: workflowStatus,
1440
- result,
1441
- error,
1442
- // @ts-ignore
1443
- timestamp: Date.now(),
1444
- },
1445
- });
1446
- },
1447
- );
1448
- }
1449
-
1450
- async executeConditional({
1451
- workflowId,
1452
- runId,
1453
- entry,
1454
- prevOutput,
1455
- prevStep,
1456
- stepResults,
1457
- serializedStepGraph,
1458
- resume,
1459
- executionContext,
1460
- emitter,
1461
- abortController,
1462
- runtimeContext,
1463
- }: {
1464
- workflowId: string;
1465
- runId: string;
1466
- entry: {
1467
- type: 'conditional';
1468
- steps: StepFlowEntry[];
1469
- conditions: ExecuteFunction<any, any, any, any, InngestEngineType>[];
1470
- };
1471
- prevStep: StepFlowEntry;
1472
- serializedStepGraph: SerializedStepFlowEntry[];
1473
- prevOutput: any;
1474
- stepResults: Record<string, StepResult<any, any, any, any>>;
1475
- resume?: {
1476
- steps: string[];
1477
- stepResults: Record<string, StepResult<any, any, any, any>>;
1478
- resumePayload: any;
1479
- resumePath: number[];
1480
- };
1481
- executionContext: ExecutionContext;
1482
- emitter: Emitter;
1483
- abortController: AbortController;
1484
- runtimeContext: RuntimeContext;
1485
- }): Promise<StepResult<any, any, any, any>> {
1486
- let execResults: any;
1487
- const truthyIndexes = (
1488
- await Promise.all(
1489
- entry.conditions.map((cond, index) =>
1490
- this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1491
- try {
1492
- const result = await cond({
1493
- runId,
1494
- mastra: this.mastra!,
1495
- runtimeContext,
1496
- runCount: -1,
1497
- inputData: prevOutput,
1498
- getInitData: () => stepResults?.input as any,
1499
- getStepResult: (step: any) => {
1500
- if (!step?.id) {
1501
- return null;
1502
- }
1503
-
1504
- const result = stepResults[step.id];
1505
- if (result?.status === 'success') {
1506
- return result.output;
1507
- }
1508
-
1509
- return null;
1510
- },
1511
-
1512
- // TODO: this function shouldn't have suspend probably?
1513
- suspend: async (_suspendPayload: any) => {},
1514
- bail: () => {},
1515
- abort: () => {
1516
- abortController.abort();
1517
- },
1518
- [EMITTER_SYMBOL]: emitter,
1519
- engine: {
1520
- step: this.inngestStep,
1521
- },
1522
- abortSignal: abortController.signal,
1523
- });
1524
- return result ? index : null;
1525
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1526
- } catch (e: unknown) {
1527
- return null;
1528
- }
1529
- }),
1530
- ),
1531
- )
1532
- ).filter((index: any): index is number => index !== null);
1533
-
1534
- const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1535
- const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
1536
- stepsToRun.map((step, index) =>
1537
- this.executeEntry({
1538
- workflowId,
1539
- runId,
1540
- entry: step,
1541
- prevStep,
1542
- stepResults,
1543
- resume,
1544
- serializedStepGraph,
1545
- executionContext: {
1546
- workflowId,
1547
- runId,
1548
- executionPath: [...executionContext.executionPath, index],
1549
- suspendedPaths: executionContext.suspendedPaths,
1550
- retryConfig: executionContext.retryConfig,
1551
- executionSpan: executionContext.executionSpan,
1552
- },
1553
- emitter,
1554
- abortController,
1555
- runtimeContext,
1556
- }),
1557
- ),
1558
- );
1559
- const hasFailed = results.find(result => result.result.status === 'failed') as {
1560
- result: StepFailure<any, any, any>;
1561
- };
1562
- const hasSuspended = results.find(result => result.result.status === 'suspended');
1563
- if (hasFailed) {
1564
- execResults = { status: 'failed', error: hasFailed.result.error };
1565
- } else if (hasSuspended) {
1566
- execResults = { status: 'suspended', payload: hasSuspended.result.suspendPayload };
1567
- } else {
1568
- execResults = {
1569
- status: 'success',
1570
- output: results.reduce((acc: Record<string, any>, result, index) => {
1571
- if (result.result.status === 'success') {
1572
- // @ts-ignore
1573
- acc[stepsToRun[index]!.step.id] = result.output;
1574
- }
1575
-
1576
- return acc;
1577
- }, {}),
1578
- };
1579
- }
1580
-
1581
- return execResults;
1582
- }
1583
- }