@mastra/inngest 0.10.3 → 0.10.5-alpha.0

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,9 @@
1
1
  import { randomUUID } from 'crypto';
2
2
  import { subscribe } from '@inngest/realtime';
3
- import type { Mastra, WorkflowRun, WorkflowRuns } from '@mastra/core';
3
+ import { Agent, Tool } from '@mastra/core';
4
+ import type { 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 { Workflow, Run, DefaultExecutionEngine } from '@mastra/core/workflows';
6
7
  import type {
7
8
  ExecuteFunction,
8
9
  ExecutionContext,
@@ -14,12 +15,17 @@ import type {
14
15
  StepResult,
15
16
  WorkflowResult,
16
17
  SerializedStepFlowEntry,
18
+ StepFailure,
17
19
  } from '@mastra/core/workflows';
18
20
  import { EMITTER_SYMBOL } from '@mastra/core/workflows/_constants';
19
21
  import type { Span } from '@opentelemetry/api';
20
22
  import type { Inngest, BaseContext } from 'inngest';
21
23
  import { serve as inngestServe } from 'inngest/hono';
22
- import type { z } from 'zod';
24
+ import { z } from 'zod';
25
+
26
+ export type InngestEngineType = {
27
+ step: any;
28
+ };
23
29
 
24
30
  export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest }): ReturnType<typeof inngestServe> {
25
31
  const wfs = mastra.getWorkflows();
@@ -37,10 +43,11 @@ export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest })
37
43
  }
38
44
 
39
45
  export class InngestRun<
46
+ TEngineType = InngestEngineType,
40
47
  TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
41
48
  TInput extends z.ZodType<any> = z.ZodType<any>,
42
49
  TOutput extends z.ZodType<any> = z.ZodType<any>,
43
- > extends Run<TSteps, TInput, TOutput> {
50
+ > extends Run<TEngineType, TSteps, TInput, TOutput> {
44
51
  private inngest: Inngest;
45
52
  serializedStepGraph: SerializedStepFlowEntry[];
46
53
  #mastra: Mastra;
@@ -106,6 +113,7 @@ export class InngestRun<
106
113
  activePaths: [],
107
114
  suspendedPaths: {},
108
115
  timestamp: Date.now(),
116
+ status: 'running',
109
117
  },
110
118
  });
111
119
 
@@ -201,12 +209,13 @@ export class InngestRun<
201
209
  }
202
210
 
203
211
  export class InngestWorkflow<
212
+ TEngineType = InngestEngineType,
204
213
  TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
205
214
  TWorkflowId extends string = string,
206
215
  TInput extends z.ZodType<any> = z.ZodType<any>,
207
216
  TOutput extends z.ZodType<any> = z.ZodType<any>,
208
217
  TPrevSchema extends z.ZodType<any> = TInput,
209
- > extends Workflow<TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
218
+ > extends Workflow<TEngineType, TSteps, TWorkflowId, TInput, TOutput, TPrevSchema> {
210
219
  #mastra: Mastra;
211
220
  public inngest: Inngest;
212
221
 
@@ -271,11 +280,11 @@ export class InngestWorkflow<
271
280
  }
272
281
  }
273
282
 
274
- createRun(options?: { runId?: string }): Run<TSteps, TInput, TOutput> {
283
+ createRun(options?: { runId?: string }): Run<TEngineType, TSteps, TInput, TOutput> {
275
284
  const runIdToUse = options?.runId || randomUUID();
276
285
 
277
286
  // Return a new Run instance with object parameters
278
- const run: Run<TSteps, TInput, TOutput> =
287
+ const run: Run<TEngineType, TSteps, TInput, TOutput> =
279
288
  this.runs.get(runIdToUse) ??
280
289
  new InngestRun(
281
290
  {
@@ -369,29 +378,185 @@ export class InngestWorkflow<
369
378
  }
370
379
  }
371
380
 
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>[],
381
+ export function createStep<
382
+ TStepId extends string,
383
+ TStepInput extends z.ZodType<any>,
384
+ TStepOutput extends z.ZodType<any>,
385
+ TResumeSchema extends z.ZodType<any>,
386
+ TSuspendSchema extends z.ZodType<any>,
387
+ >(params: {
388
+ id: TStepId;
389
+ description?: string;
390
+ inputSchema: TStepInput;
391
+ outputSchema: TStepOutput;
392
+ resumeSchema?: TResumeSchema;
393
+ suspendSchema?: TSuspendSchema;
394
+ execute: ExecuteFunction<
395
+ z.infer<TStepInput>,
396
+ z.infer<TStepOutput>,
397
+ z.infer<TResumeSchema>,
398
+ z.infer<TSuspendSchema>,
399
+ InngestEngineType
400
+ >;
401
+ }): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
402
+
403
+ export function createStep<
404
+ TStepId extends string,
405
+ TStepInput extends z.ZodObject<{ prompt: z.ZodString }>,
406
+ TStepOutput extends z.ZodObject<{ text: z.ZodString }>,
407
+ TResumeSchema extends z.ZodType<any>,
408
+ TSuspendSchema extends z.ZodType<any>,
377
409
  >(
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
- );
410
+ agent: Agent<TStepId, any, any>,
411
+ ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType>;
412
+
413
+ export function createStep<
414
+ TSchemaIn extends z.ZodType<any>,
415
+ TSchemaOut extends z.ZodType<any>,
416
+ TContext extends ToolExecutionContext<TSchemaIn>,
417
+ >(
418
+ tool: Tool<TSchemaIn, TSchemaOut, TContext> & {
419
+ inputSchema: TSchemaIn;
420
+ outputSchema: TSchemaOut;
421
+ execute: (context: TContext) => Promise<any>;
422
+ },
423
+ ): Step<string, TSchemaIn, TSchemaOut, z.ZodType<any>, z.ZodType<any>, InngestEngineType>;
424
+
425
+ export function createStep<
426
+ TStepId extends string,
427
+ TStepInput extends z.ZodType<any>,
428
+ TStepOutput extends z.ZodType<any>,
429
+ TResumeSchema extends z.ZodType<any>,
430
+ TSuspendSchema extends z.ZodType<any>,
431
+ >(
432
+ params:
433
+ | {
434
+ id: TStepId;
435
+ description?: string;
436
+ inputSchema: TStepInput;
437
+ outputSchema: TStepOutput;
438
+ resumeSchema?: TResumeSchema;
439
+ suspendSchema?: TSuspendSchema;
440
+ execute: ExecuteFunction<
441
+ z.infer<TStepInput>,
442
+ z.infer<TStepOutput>,
443
+ z.infer<TResumeSchema>,
444
+ z.infer<TSuspendSchema>,
445
+ InngestEngineType
446
+ >;
447
+ }
448
+ | Agent<any, any, any>
449
+ | (Tool<TStepInput, TStepOutput, any> & {
450
+ inputSchema: TStepInput;
451
+ outputSchema: TStepOutput;
452
+ execute: (context: ToolExecutionContext<TStepInput>) => Promise<any>;
453
+ }),
454
+ ): Step<TStepId, TStepInput, TStepOutput, TResumeSchema, TSuspendSchema, InngestEngineType> {
455
+ if (params instanceof Agent) {
456
+ return {
457
+ id: params.name,
458
+ // @ts-ignore
459
+ inputSchema: z.object({
460
+ prompt: z.string(),
461
+ // resourceId: z.string().optional(),
462
+ // threadId: z.string().optional(),
463
+ }),
464
+ // @ts-ignore
465
+ outputSchema: z.object({
466
+ text: z.string(),
467
+ }),
468
+ execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext }) => {
469
+ let streamPromise = {} as {
470
+ promise: Promise<string>;
471
+ resolve: (value: string) => void;
472
+ reject: (reason?: any) => void;
473
+ };
474
+
475
+ streamPromise.promise = new Promise((resolve, reject) => {
476
+ streamPromise.resolve = resolve;
477
+ streamPromise.reject = reject;
478
+ });
479
+ const toolData = {
480
+ name: params.name,
481
+ args: inputData,
482
+ };
483
+ await emitter.emit('watch-v2', {
484
+ type: 'tool-call-streaming-start',
485
+ ...toolData,
486
+ });
487
+ const { fullStream } = await params.stream(inputData.prompt, {
488
+ // resourceId: inputData.resourceId,
489
+ // threadId: inputData.threadId,
490
+ runtimeContext,
491
+ onFinish: result => {
492
+ streamPromise.resolve(result.text);
493
+ },
494
+ });
495
+
496
+ for await (const chunk of fullStream) {
497
+ switch (chunk.type) {
498
+ case 'text-delta':
499
+ await emitter.emit('watch-v2', {
500
+ type: 'tool-call-delta',
501
+ ...toolData,
502
+ argsTextDelta: chunk.textDelta,
503
+ });
504
+ break;
505
+
506
+ case 'step-start':
507
+ case 'step-finish':
508
+ case 'finish':
509
+ break;
510
+
511
+ case 'tool-call':
512
+ case 'tool-result':
513
+ case 'tool-call-streaming-start':
514
+ case 'tool-call-delta':
515
+ case 'source':
516
+ case 'file':
517
+ default:
518
+ await emitter.emit('watch-v2', chunk);
519
+ break;
520
+ }
521
+ }
522
+
523
+ return {
524
+ text: await streamPromise.promise,
525
+ };
526
+ },
527
+ };
528
+ }
529
+
530
+ if (params instanceof Tool) {
531
+ if (!params.inputSchema || !params.outputSchema) {
532
+ throw new Error('Tool must have input and output schemas defined');
533
+ }
534
+
535
+ return {
536
+ // TODO: tool probably should have strong id type
537
+ // @ts-ignore
538
+ id: params.id,
539
+ inputSchema: params.inputSchema,
540
+ outputSchema: params.outputSchema,
541
+ execute: async ({ inputData, mastra, runtimeContext }) => {
542
+ return params.execute({
543
+ context: inputData,
544
+ mastra,
545
+ runtimeContext,
546
+ });
547
+ },
548
+ };
549
+ }
391
550
 
392
- wf.setStepFlow(workflow.stepGraph);
393
- wf.commit();
394
- return wf;
551
+ return {
552
+ id: params.id,
553
+ description: params.description,
554
+ inputSchema: params.inputSchema,
555
+ outputSchema: params.outputSchema,
556
+ resumeSchema: params.resumeSchema,
557
+ suspendSchema: params.suspendSchema,
558
+ execute: params.execute,
559
+ };
395
560
  }
396
561
 
397
562
  export function init(inngest: Inngest) {
@@ -400,13 +565,58 @@ export function init(inngest: Inngest) {
400
565
  TWorkflowId extends string = string,
401
566
  TInput extends z.ZodType<any> = z.ZodType<any>,
402
567
  TOutput extends z.ZodType<any> = z.ZodType<any>,
403
- TSteps extends Step<string, any, any>[] = Step<string, any, any>[],
568
+ TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
569
+ string,
570
+ any,
571
+ any,
572
+ any,
573
+ any,
574
+ InngestEngineType
575
+ >[],
404
576
  >(params: WorkflowConfig<TWorkflowId, TInput, TOutput, TSteps>) {
405
- return new InngestWorkflow(params, inngest);
577
+ return new InngestWorkflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TInput>(params, inngest);
406
578
  },
407
579
  createStep,
408
- cloneStep,
409
- cloneWorkflow,
580
+ cloneStep<TStepId extends string>(
581
+ step: Step<string, any, any, any, any, InngestEngineType>,
582
+ opts: { id: TStepId },
583
+ ): Step<TStepId, any, any, any, any, InngestEngineType> {
584
+ return {
585
+ id: opts.id,
586
+ description: step.description,
587
+ inputSchema: step.inputSchema,
588
+ outputSchema: step.outputSchema,
589
+ execute: step.execute,
590
+ };
591
+ },
592
+ cloneWorkflow<
593
+ TWorkflowId extends string = string,
594
+ TInput extends z.ZodType<any> = z.ZodType<any>,
595
+ TOutput extends z.ZodType<any> = z.ZodType<any>,
596
+ TSteps extends Step<string, any, any, any, any, InngestEngineType>[] = Step<
597
+ string,
598
+ any,
599
+ any,
600
+ any,
601
+ any,
602
+ InngestEngineType
603
+ >[],
604
+ >(
605
+ workflow: Workflow<InngestEngineType, TSteps, string, TInput, TOutput, TInput>,
606
+ opts: { id: TWorkflowId },
607
+ ): Workflow<InngestEngineType, TSteps, TWorkflowId, TInput, TOutput, TInput> {
608
+ const wf = new Workflow({
609
+ id: opts.id,
610
+ inputSchema: workflow.inputSchema,
611
+ outputSchema: workflow.outputSchema,
612
+ steps: workflow.stepDefs,
613
+ mastra: workflow.mastra,
614
+ });
615
+
616
+ wf.setStepFlow(workflow.stepGraph);
617
+ wf.commit();
618
+ return wf;
619
+ },
410
620
  };
411
621
  }
412
622
 
@@ -531,6 +741,10 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
531
741
  });
532
742
  }
533
743
 
744
+ async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
745
+ await this.inngestStep.sleep(id, duration);
746
+ }
747
+
534
748
  async executeStep({
535
749
  step,
536
750
  stepResults,
@@ -771,7 +985,10 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
771
985
  // @ts-ignore
772
986
  runId: stepResults[step.id]?.payload?.__workflow_meta?.runId,
773
987
  },
774
- emitter,
988
+ [EMITTER_SYMBOL]: emitter,
989
+ engine: {
990
+ step: this.inngestStep,
991
+ },
775
992
  });
776
993
 
777
994
  execResults = { status: 'success', output: result };
@@ -825,12 +1042,18 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
825
1042
  stepResults,
826
1043
  executionContext,
827
1044
  serializedStepGraph,
1045
+ workflowStatus,
1046
+ result,
1047
+ error,
828
1048
  }: {
829
1049
  workflowId: string;
830
1050
  runId: string;
831
1051
  stepResults: Record<string, StepResult<any, any, any, any>>;
832
1052
  serializedStepGraph: SerializedStepFlowEntry[];
833
1053
  executionContext: ExecutionContext;
1054
+ workflowStatus: 'success' | 'failed' | 'suspended' | 'running';
1055
+ result?: Record<string, any>;
1056
+ error?: string | Error;
834
1057
  }) {
835
1058
  await this.inngestStep.run(
836
1059
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -845,6 +1068,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
845
1068
  activePaths: [],
846
1069
  suspendedPaths: executionContext.suspendedPaths,
847
1070
  serializedStepGraph,
1071
+ status: workflowStatus,
1072
+ result,
1073
+ error,
848
1074
  // @ts-ignore
849
1075
  timestamp: Date.now(),
850
1076
  },
@@ -868,7 +1094,11 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
868
1094
  }: {
869
1095
  workflowId: string;
870
1096
  runId: string;
871
- entry: { type: 'conditional'; steps: StepFlowEntry[]; conditions: ExecuteFunction<any, any, any, any>[] };
1097
+ entry: {
1098
+ type: 'conditional';
1099
+ steps: StepFlowEntry[];
1100
+ conditions: ExecuteFunction<any, any, any, any, InngestEngineType>[];
1101
+ };
872
1102
  prevStep: StepFlowEntry;
873
1103
  serializedStepGraph: SerializedStepFlowEntry[];
874
1104
  prevOutput: any;
@@ -911,6 +1141,9 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
911
1141
  // TODO: this function shouldn't have suspend probably?
912
1142
  suspend: async (_suspendPayload: any) => {},
913
1143
  [EMITTER_SYMBOL]: emitter,
1144
+ engine: {
1145
+ step: this.inngestStep,
1146
+ },
914
1147
  });
915
1148
  return result ? index : null;
916
1149
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -923,7 +1156,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
923
1156
  ).filter((index: any): index is number => index !== null);
924
1157
 
925
1158
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
926
- const results: StepResult<any, any, any, any>[] = await Promise.all(
1159
+ const results: { result: StepResult<any, any, any, any> }[] = await Promise.all(
927
1160
  stepsToRun.map((step, index) =>
928
1161
  this.executeEntry({
929
1162
  workflowId,
@@ -946,17 +1179,19 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
946
1179
  }),
947
1180
  ),
948
1181
  );
949
- const hasFailed = results.find(result => result.status === 'failed');
950
- const hasSuspended = results.find(result => result.status === 'suspended');
1182
+ const hasFailed = results.find(result => result.result.status === 'failed') as {
1183
+ result: StepFailure<any, any, any>;
1184
+ };
1185
+ const hasSuspended = results.find(result => result.result.status === 'suspended');
951
1186
  if (hasFailed) {
952
- execResults = { status: 'failed', error: hasFailed.error };
1187
+ execResults = { status: 'failed', error: hasFailed.result.error };
953
1188
  } else if (hasSuspended) {
954
- execResults = { status: 'suspended', payload: hasSuspended.payload };
1189
+ execResults = { status: 'suspended', payload: hasSuspended.result.payload };
955
1190
  } else {
956
1191
  execResults = {
957
1192
  status: 'success',
958
1193
  output: results.reduce((acc: Record<string, any>, result, index) => {
959
- if (result.status === 'success') {
1194
+ if (result.result.status === 'success') {
960
1195
  // @ts-ignore
961
1196
  acc[stepsToRun[index]!.step.id] = result.output;
962
1197
  }