@mastra/inngest 0.0.0-message-file-url-handling-fix-20250904234524 → 0.0.0-model-router-unknown-provider-20251017212006

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,13 +7,19 @@ var di = require('@mastra/core/di');
7
7
  var tools = require('@mastra/core/tools');
8
8
  var workflows = require('@mastra/core/workflows');
9
9
  var _constants = require('@mastra/core/workflows/_constants');
10
+ var inngest = require('inngest');
10
11
  var hono = require('inngest/hono');
11
12
  var zod = require('zod');
12
13
 
13
14
  // src/index.ts
14
- function serve({ mastra, inngest }) {
15
+ function serve({
16
+ mastra,
17
+ inngest,
18
+ functions: userFunctions = [],
19
+ registerOptions
20
+ }) {
15
21
  const wfs = mastra.getWorkflows();
16
- const functions = Array.from(
22
+ const workflowFunctions = Array.from(
17
23
  new Set(
18
24
  Object.values(wfs).flatMap((wf) => {
19
25
  if (wf instanceof InngestWorkflow) {
@@ -25,8 +31,9 @@ function serve({ mastra, inngest }) {
25
31
  )
26
32
  );
27
33
  return hono.serve({
34
+ ...registerOptions,
28
35
  client: inngest,
29
- functions
36
+ functions: [...workflowFunctions, ...userFunctions]
30
37
  });
31
38
  }
32
39
  var InngestRun = class extends workflows.Run {
@@ -54,9 +61,15 @@ var InngestRun = class extends workflows.Run {
54
61
  await new Promise((resolve) => setTimeout(resolve, 1e3));
55
62
  runs = await this.getRuns(eventId);
56
63
  if (runs?.[0]?.status === "Failed") {
57
- console.log("run", runs?.[0]);
58
- throw new Error(`Function run ${runs?.[0]?.status}`);
59
- } else if (runs?.[0]?.status === "Cancelled") {
64
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
65
+ workflowName: this.workflowId,
66
+ runId: this.runId
67
+ });
68
+ return {
69
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
70
+ };
71
+ }
72
+ if (runs?.[0]?.status === "Cancelled") {
60
73
  const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
61
74
  workflowName: this.workflowId,
62
75
  runId: this.runId
@@ -87,6 +100,7 @@ var InngestRun = class extends workflows.Run {
87
100
  await this.#mastra?.storage?.persistWorkflowSnapshot({
88
101
  workflowName: this.workflowId,
89
102
  runId: this.runId,
103
+ resourceId: this.resourceId,
90
104
  snapshot: {
91
105
  ...snapshot,
92
106
  status: "canceled"
@@ -95,11 +109,13 @@ var InngestRun = class extends workflows.Run {
95
109
  }
96
110
  }
97
111
  async start({
98
- inputData
112
+ inputData,
113
+ initialState
99
114
  }) {
100
115
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
101
116
  workflowName: this.workflowId,
102
117
  runId: this.runId,
118
+ resourceId: this.resourceId,
103
119
  snapshot: {
104
120
  runId: this.runId,
105
121
  serializedStepGraph: this.serializedStepGraph,
@@ -107,16 +123,21 @@ var InngestRun = class extends workflows.Run {
107
123
  context: {},
108
124
  activePaths: [],
109
125
  suspendedPaths: {},
126
+ resumeLabels: {},
110
127
  waitingPaths: {},
111
128
  timestamp: Date.now(),
112
129
  status: "running"
113
130
  }
114
131
  });
132
+ const inputDataToUse = await this._validateInput(inputData);
133
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
115
134
  const eventOutput = await this.inngest.send({
116
135
  name: `workflow.${this.workflowId}`,
117
136
  data: {
118
- inputData,
119
- runId: this.runId
137
+ inputData: inputDataToUse,
138
+ initialState: initialStateToUse,
139
+ runId: this.runId,
140
+ resourceId: this.resourceId
120
141
  }
121
142
  });
122
143
  const eventId = eventOutput.ids[0];
@@ -152,17 +173,20 @@ var InngestRun = class extends workflows.Run {
152
173
  workflowName: this.workflowId,
153
174
  runId: this.runId
154
175
  });
176
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
177
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
155
178
  const eventOutput = await this.inngest.send({
156
179
  name: `workflow.${this.workflowId}`,
157
180
  data: {
158
- inputData: params.resumeData,
181
+ inputData: resumeDataToUse,
182
+ initialState: snapshot?.value ?? {},
159
183
  runId: this.runId,
160
184
  workflowId: this.workflowId,
161
185
  stepResults: snapshot?.context,
162
186
  resume: {
163
187
  steps,
164
188
  stepResults: snapshot?.context,
165
- resumePayload: params.resumeData,
189
+ resumePayload: resumeDataToUse,
166
190
  // @ts-ignore
167
191
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
168
192
  }
@@ -204,33 +228,9 @@ var InngestRun = class extends workflows.Run {
204
228
  }
205
229
  stream({ inputData, runtimeContext } = {}) {
206
230
  const { readable, writable } = new TransformStream();
207
- let currentToolData = void 0;
208
231
  const writer = writable.getWriter();
209
232
  const unwatch = this.watch(async (event) => {
210
- if (event.type === "workflow-agent-call-start") {
211
- currentToolData = {
212
- name: event.payload.name,
213
- args: event.payload.args
214
- };
215
- await writer.write({
216
- ...event.payload,
217
- type: "tool-call-streaming-start"
218
- });
219
- return;
220
- }
221
233
  try {
222
- if (event.type === "workflow-agent-call-finish") {
223
- return;
224
- } else if (!event.type.startsWith("workflow-")) {
225
- if (event.type === "text-delta") {
226
- await writer.write({
227
- type: "tool-call-delta",
228
- ...currentToolData ?? {},
229
- argsTextDelta: event.textDelta
230
- });
231
- }
232
- return;
233
- }
234
234
  const e = {
235
235
  ...event,
236
236
  type: event.type.replace("workflow-", "")
@@ -312,23 +312,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
312
312
  }
313
313
  }
314
314
  }
315
- createRun(options) {
316
- const runIdToUse = options?.runId || crypto.randomUUID();
317
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
318
- {
319
- workflowId: this.id,
320
- runId: runIdToUse,
321
- executionEngine: this.executionEngine,
322
- executionGraph: this.executionGraph,
323
- serializedStepGraph: this.serializedStepGraph,
324
- mastra: this.#mastra,
325
- retryConfig: this.retryConfig,
326
- cleanup: () => this.runs.delete(runIdToUse)
327
- },
328
- this.inngest
315
+ /**
316
+ * @deprecated Use createRunAsync() instead.
317
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
318
+ */
319
+ createRun(_options) {
320
+ throw new Error(
321
+ "createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
329
322
  );
330
- this.runs.set(runIdToUse, run);
331
- return run;
332
323
  }
333
324
  async createRunAsync(options) {
334
325
  const runIdToUse = options?.runId || crypto.randomUUID();
@@ -336,21 +327,28 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
336
327
  {
337
328
  workflowId: this.id,
338
329
  runId: runIdToUse,
330
+ resourceId: options?.resourceId,
339
331
  executionEngine: this.executionEngine,
340
332
  executionGraph: this.executionGraph,
341
333
  serializedStepGraph: this.serializedStepGraph,
342
334
  mastra: this.#mastra,
343
335
  retryConfig: this.retryConfig,
344
- cleanup: () => this.runs.delete(runIdToUse)
336
+ cleanup: () => this.runs.delete(runIdToUse),
337
+ workflowSteps: this.steps
345
338
  },
346
339
  this.inngest
347
340
  );
348
341
  this.runs.set(runIdToUse, run);
342
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
343
+ workflowStatus: run.workflowRunStatus,
344
+ stepResults: {}
345
+ });
349
346
  const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
350
- if (!workflowSnapshotInStorage) {
347
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
351
348
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
352
349
  workflowName: this.id,
353
350
  runId: runIdToUse,
351
+ resourceId: options?.resourceId,
354
352
  snapshot: {
355
353
  runId: runIdToUse,
356
354
  status: "pending",
@@ -360,6 +358,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
360
358
  waitingPaths: {},
361
359
  serializedStepGraph: this.serializedStepGraph,
362
360
  suspendedPaths: {},
361
+ resumeLabels: {},
363
362
  result: void 0,
364
363
  error: void 0,
365
364
  // @ts-ignore
@@ -384,7 +383,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
384
383
  },
385
384
  { event: `workflow.${this.id}` },
386
385
  async ({ event, step, attempt, publish }) => {
387
- let { inputData, runId, resume } = event.data;
386
+ let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
388
387
  if (!runId) {
389
388
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
390
389
  return crypto.randomUUID();
@@ -412,21 +411,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
412
411
  once: (_event, _callback) => {
413
412
  }
414
413
  };
415
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
414
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
416
415
  const result = await engine.execute({
417
416
  workflowId: this.id,
418
417
  runId,
418
+ resourceId,
419
419
  graph: this.executionGraph,
420
420
  serializedStepGraph: this.serializedStepGraph,
421
421
  input: inputData,
422
+ initialState,
422
423
  emitter,
423
424
  retryConfig: this.retryConfig,
424
425
  runtimeContext: new di.RuntimeContext(),
425
426
  // TODO
426
427
  resume,
427
428
  abortController: new AbortController(),
428
- currentSpan: void 0
429
+ currentSpan: void 0,
429
430
  // TODO: Pass actual parent AI span from workflow execution context
431
+ outputOptions
432
+ });
433
+ await step.run(`workflow.${this.id}.finalize`, async () => {
434
+ if (result.status === "failed") {
435
+ throw new inngest.NonRetriableError(`Workflow failed`, {
436
+ cause: result
437
+ });
438
+ }
439
+ return result;
430
440
  });
431
441
  return { result, runId };
432
442
  }
@@ -460,11 +470,10 @@ function createStep(params) {
460
470
  if (isAgent(params)) {
461
471
  return {
462
472
  id: params.name,
473
+ description: params.getDescription(),
463
474
  // @ts-ignore
464
475
  inputSchema: zod.z.object({
465
476
  prompt: zod.z.string()
466
- // resourceId: z.string().optional(),
467
- // threadId: z.string().optional(),
468
477
  }),
469
478
  // @ts-ignore
470
479
  outputSchema: zod.z.object({
@@ -480,34 +489,66 @@ function createStep(params) {
480
489
  name: params.name,
481
490
  args: inputData
482
491
  };
483
- await emitter.emit("watch-v2", {
484
- type: "workflow-agent-call-start",
485
- payload: toolData
486
- });
487
- const { fullStream } = await params.stream(inputData.prompt, {
488
- // resourceId: inputData.resourceId,
489
- // threadId: inputData.threadId,
490
- runtimeContext,
491
- tracingContext,
492
- onFinish: (result) => {
493
- streamPromise.resolve(result.text);
494
- },
495
- abortSignal
496
- });
497
- if (abortSignal.aborted) {
498
- return abort();
499
- }
500
- for await (const chunk of fullStream) {
501
- await emitter.emit("watch-v2", chunk);
492
+ if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
493
+ const { fullStream } = await params.stream(inputData.prompt, {
494
+ runtimeContext,
495
+ tracingContext,
496
+ onFinish: (result) => {
497
+ streamPromise.resolve(result.text);
498
+ },
499
+ abortSignal
500
+ });
501
+ if (abortSignal.aborted) {
502
+ return abort();
503
+ }
504
+ await emitter.emit("watch-v2", {
505
+ type: "tool-call-streaming-start",
506
+ ...toolData ?? {}
507
+ });
508
+ for await (const chunk of fullStream) {
509
+ if (chunk.type === "text-delta") {
510
+ await emitter.emit("watch-v2", {
511
+ type: "tool-call-delta",
512
+ ...toolData ?? {},
513
+ argsTextDelta: chunk.payload.text
514
+ });
515
+ }
516
+ }
517
+ } else {
518
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
519
+ runtimeContext,
520
+ tracingContext,
521
+ onFinish: (result) => {
522
+ streamPromise.resolve(result.text);
523
+ },
524
+ abortSignal
525
+ });
526
+ if (abortSignal.aborted) {
527
+ return abort();
528
+ }
529
+ await emitter.emit("watch-v2", {
530
+ type: "tool-call-streaming-start",
531
+ ...toolData ?? {}
532
+ });
533
+ for await (const chunk of fullStream) {
534
+ if (chunk.type === "text-delta") {
535
+ await emitter.emit("watch-v2", {
536
+ type: "tool-call-delta",
537
+ ...toolData ?? {},
538
+ argsTextDelta: chunk.textDelta
539
+ });
540
+ }
541
+ }
502
542
  }
503
543
  await emitter.emit("watch-v2", {
504
- type: "workflow-agent-call-finish",
505
- payload: toolData
544
+ type: "tool-call-streaming-finish",
545
+ ...toolData ?? {}
506
546
  });
507
547
  return {
508
548
  text: await streamPromise.promise
509
549
  };
510
- }
550
+ },
551
+ component: params.component
511
552
  };
512
553
  }
513
554
  if (isTool(params)) {
@@ -518,16 +559,20 @@ function createStep(params) {
518
559
  // TODO: tool probably should have strong id type
519
560
  // @ts-ignore
520
561
  id: params.id,
562
+ description: params.description,
521
563
  inputSchema: params.inputSchema,
522
564
  outputSchema: params.outputSchema,
523
- execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
565
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
524
566
  return params.execute({
525
567
  context: inputData,
526
568
  mastra: aiTracing.wrapMastra(mastra, tracingContext),
527
569
  runtimeContext,
528
- tracingContext
570
+ tracingContext,
571
+ suspend,
572
+ resumeData
529
573
  });
530
- }
574
+ },
575
+ component: "TOOL"
531
576
  };
532
577
  }
533
578
  return {
@@ -543,7 +588,10 @@ function createStep(params) {
543
588
  function init(inngest) {
544
589
  return {
545
590
  createWorkflow(params) {
546
- return new InngestWorkflow(params, inngest);
591
+ return new InngestWorkflow(
592
+ params,
593
+ inngest
594
+ );
547
595
  },
548
596
  createStep,
549
597
  cloneStep(step, opts) {
@@ -552,7 +600,11 @@ function init(inngest) {
552
600
  description: step.description,
553
601
  inputSchema: step.inputSchema,
554
602
  outputSchema: step.outputSchema,
555
- execute: step.execute
603
+ resumeSchema: step.resumeSchema,
604
+ suspendSchema: step.suspendSchema,
605
+ stateSchema: step.stateSchema,
606
+ execute: step.execute,
607
+ component: step.component
556
608
  };
557
609
  },
558
610
  cloneWorkflow(workflow, opts) {
@@ -572,8 +624,8 @@ function init(inngest) {
572
624
  var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
573
625
  inngestStep;
574
626
  inngestAttempts;
575
- constructor(mastra, inngestStep, inngestAttempts = 0) {
576
- super({ mastra });
627
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
628
+ super({ mastra, options });
577
629
  this.inngestStep = inngestStep;
578
630
  this.inngestAttempts = inngestAttempts;
579
631
  }
@@ -636,7 +688,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
636
688
  });
637
689
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
638
690
  if (stepResult?.status === "suspended") {
639
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
691
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
640
692
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
641
693
  }
642
694
  return [];
@@ -669,7 +721,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
669
721
  attributes: {
670
722
  durationMs: duration,
671
723
  sleepType: fn ? "dynamic" : "fixed"
672
- }
724
+ },
725
+ tracingPolicy: this.options?.tracingPolicy
673
726
  });
674
727
  if (fn) {
675
728
  const stepCallId = crypto.randomUUID();
@@ -680,21 +733,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
680
733
  mastra: this.mastra,
681
734
  runtimeContext,
682
735
  inputData: prevOutput,
736
+ state: executionContext.state,
737
+ setState: (state) => {
738
+ executionContext.state = state;
739
+ },
683
740
  runCount: -1,
684
741
  tracingContext: {
685
742
  currentSpan: sleepSpan
686
743
  },
687
744
  getInitData: () => stepResults?.input,
688
- getStepResult: (step) => {
689
- if (!step?.id) {
690
- return null;
691
- }
692
- const result = stepResults[step.id];
693
- if (result?.status === "success") {
694
- return result.output;
695
- }
696
- return null;
697
- },
745
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
698
746
  // TODO: this function shouldn't have suspend probably?
699
747
  suspend: async (_suspendPayload) => {
700
748
  },
@@ -754,7 +802,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
754
802
  untilDate: date,
755
803
  durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
756
804
  sleepType: fn ? "dynamic" : "fixed"
757
- }
805
+ },
806
+ tracingPolicy: this.options?.tracingPolicy
758
807
  });
759
808
  if (fn) {
760
809
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
@@ -765,21 +814,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
765
814
  mastra: this.mastra,
766
815
  runtimeContext,
767
816
  inputData: prevOutput,
817
+ state: executionContext.state,
818
+ setState: (state) => {
819
+ executionContext.state = state;
820
+ },
768
821
  runCount: -1,
769
822
  tracingContext: {
770
823
  currentSpan: sleepUntilSpan
771
824
  },
772
825
  getInitData: () => stepResults?.input,
773
- getStepResult: (step) => {
774
- if (!step?.id) {
775
- return null;
776
- }
777
- const result = stepResults[step.id];
778
- if (result?.status === "success") {
779
- return result.output;
780
- }
781
- return null;
782
- },
826
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
783
827
  // TODO: this function shouldn't have suspend probably?
784
828
  suspend: async (_suspendPayload) => {
785
829
  },
@@ -804,6 +848,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
804
848
  )
805
849
  });
806
850
  });
851
+ if (date && !(date instanceof Date)) {
852
+ date = new Date(date);
853
+ }
807
854
  const time = !date ? 0 : date.getTime() - Date.now();
808
855
  sleepUntilSpan?.update({
809
856
  attributes: {
@@ -852,7 +899,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
852
899
  input: prevOutput,
853
900
  attributes: {
854
901
  stepId: step.id
855
- }
902
+ },
903
+ tracingPolicy: this.options?.tracingPolicy
904
+ });
905
+ const { inputData, validationError } = await workflows.validateStepInput({
906
+ prevOutput,
907
+ step,
908
+ validateInputs: this.options?.validateInputs ?? false
856
909
  });
857
910
  const startedAt = await this.inngestStep.run(
858
911
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
@@ -884,7 +937,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
884
937
  payload: {
885
938
  id: step.id,
886
939
  status: "running",
887
- payload: prevOutput,
940
+ payload: inputData,
888
941
  startedAt: startedAt2
889
942
  }
890
943
  });
@@ -895,38 +948,60 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
895
948
  const isResume = !!resume?.steps?.length;
896
949
  let result;
897
950
  let runId;
898
- if (isResume) {
899
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
900
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
901
- workflowName: step.id,
902
- runId
903
- });
904
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
905
- function: step.getFunction(),
906
- data: {
907
- inputData: prevOutput,
908
- runId,
909
- resume: {
951
+ try {
952
+ if (isResume) {
953
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
954
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
955
+ workflowName: step.id,
956
+ runId
957
+ });
958
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
959
+ function: step.getFunction(),
960
+ data: {
961
+ inputData,
962
+ initialState: executionContext.state ?? snapshot?.value ?? {},
910
963
  runId,
911
- steps: resume.steps.slice(1),
912
- stepResults: snapshot?.context,
913
- resumePayload: resume.resumePayload,
914
- // @ts-ignore
915
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
964
+ resume: {
965
+ runId,
966
+ steps: resume.steps.slice(1),
967
+ stepResults: snapshot?.context,
968
+ resumePayload: resume.resumePayload,
969
+ // @ts-ignore
970
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
971
+ },
972
+ outputOptions: { includeState: true }
916
973
  }
917
- }
918
- });
919
- result = invokeResp.result;
920
- runId = invokeResp.runId;
921
- } else {
922
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
923
- function: step.getFunction(),
924
- data: {
925
- inputData: prevOutput
926
- }
927
- });
928
- result = invokeResp.result;
929
- runId = invokeResp.runId;
974
+ });
975
+ result = invokeResp.result;
976
+ runId = invokeResp.runId;
977
+ executionContext.state = invokeResp.result.state;
978
+ } else {
979
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
980
+ function: step.getFunction(),
981
+ data: {
982
+ inputData,
983
+ initialState: executionContext.state ?? {},
984
+ outputOptions: { includeState: true }
985
+ }
986
+ });
987
+ result = invokeResp.result;
988
+ runId = invokeResp.runId;
989
+ executionContext.state = invokeResp.result.state;
990
+ }
991
+ } catch (e) {
992
+ const errorCause = e?.cause;
993
+ if (errorCause && typeof errorCause === "object") {
994
+ result = errorCause;
995
+ runId = errorCause.runId || crypto.randomUUID();
996
+ } else {
997
+ runId = crypto.randomUUID();
998
+ result = {
999
+ status: "failed",
1000
+ error: e instanceof Error ? e : new Error(String(e)),
1001
+ steps: {},
1002
+ input: inputData
1003
+ };
1004
+ }
930
1005
  }
931
1006
  const res = await this.inngestStep.run(
932
1007
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -965,7 +1040,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
965
1040
  return stepRes2?.status === "suspended";
966
1041
  });
967
1042
  for (const [stepName, stepResult] of suspendedSteps) {
968
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1043
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
969
1044
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
970
1045
  await emitter.emit("watch", {
971
1046
  type: "watch",
@@ -973,7 +1048,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
973
1048
  currentStep: {
974
1049
  id: step.id,
975
1050
  status: "suspended",
976
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1051
+ payload: stepResult.payload,
1052
+ suspendPayload: {
1053
+ ...stepResult?.suspendPayload,
1054
+ __workflow_meta: { runId, path: suspendPath }
1055
+ }
977
1056
  },
978
1057
  workflowState: {
979
1058
  status: "running",
@@ -995,7 +1074,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
995
1074
  executionContext,
996
1075
  result: {
997
1076
  status: "suspended",
998
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1077
+ payload: stepResult.payload,
1078
+ suspendPayload: {
1079
+ ...stepResult?.suspendPayload,
1080
+ __workflow_meta: { runId, path: suspendPath }
1081
+ }
999
1082
  }
1000
1083
  };
1001
1084
  }
@@ -1060,141 +1143,176 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1060
1143
  }
1061
1144
  );
1062
1145
  Object.assign(executionContext, res.executionContext);
1063
- return res.result;
1146
+ return {
1147
+ ...res.result,
1148
+ startedAt,
1149
+ endedAt: Date.now(),
1150
+ payload: inputData,
1151
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1152
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1153
+ };
1064
1154
  }
1065
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1066
- let execResults;
1067
- let suspended;
1068
- let bailed;
1069
- try {
1070
- const result = await step.execute({
1071
- runId: executionContext.runId,
1072
- mastra: this.mastra,
1073
- runtimeContext,
1074
- writableStream,
1075
- inputData: prevOutput,
1076
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1077
- tracingContext: {
1078
- currentSpan: stepAISpan
1079
- },
1080
- getInitData: () => stepResults?.input,
1081
- getStepResult: (step2) => {
1082
- const result2 = stepResults[step2.id];
1083
- if (result2?.status === "success") {
1084
- return result2.output;
1155
+ let stepRes;
1156
+ try {
1157
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1158
+ let execResults;
1159
+ let suspended;
1160
+ let bailed;
1161
+ try {
1162
+ if (validationError) {
1163
+ throw validationError;
1164
+ }
1165
+ const result = await step.execute({
1166
+ runId: executionContext.runId,
1167
+ mastra: this.mastra,
1168
+ runtimeContext,
1169
+ writableStream,
1170
+ state: executionContext?.state ?? {},
1171
+ setState: (state) => {
1172
+ executionContext.state = state;
1173
+ },
1174
+ inputData,
1175
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1176
+ tracingContext: {
1177
+ currentSpan: stepAISpan
1178
+ },
1179
+ getInitData: () => stepResults?.input,
1180
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1181
+ suspend: async (suspendPayload, suspendOptions) => {
1182
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1183
+ if (suspendOptions?.resumeLabel) {
1184
+ executionContext.resumeLabels[suspendOptions.resumeLabel] = step.id;
1185
+ }
1186
+ suspended = { payload: suspendPayload };
1187
+ },
1188
+ bail: (result2) => {
1189
+ bailed = { payload: result2 };
1190
+ },
1191
+ resume: {
1192
+ steps: resume?.steps?.slice(1) || [],
1193
+ resumePayload: resume?.resumePayload,
1194
+ // @ts-ignore
1195
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1196
+ },
1197
+ [_constants.EMITTER_SYMBOL]: emitter,
1198
+ engine: {
1199
+ step: this.inngestStep
1200
+ },
1201
+ abortSignal: abortController.signal
1202
+ });
1203
+ const endedAt = Date.now();
1204
+ execResults = {
1205
+ status: "success",
1206
+ output: result,
1207
+ startedAt,
1208
+ endedAt,
1209
+ payload: inputData,
1210
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1211
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1212
+ };
1213
+ } catch (e) {
1214
+ const stepFailure = {
1215
+ status: "failed",
1216
+ payload: inputData,
1217
+ error: e instanceof Error ? e.message : String(e),
1218
+ endedAt: Date.now(),
1219
+ startedAt,
1220
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1221
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1222
+ };
1223
+ execResults = stepFailure;
1224
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1225
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1226
+ throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1227
+ cause: execResults
1228
+ });
1229
+ }
1230
+ if (suspended) {
1231
+ execResults = {
1232
+ status: "suspended",
1233
+ suspendPayload: suspended.payload,
1234
+ payload: inputData,
1235
+ suspendedAt: Date.now(),
1236
+ startedAt,
1237
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1238
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1239
+ };
1240
+ } else if (bailed) {
1241
+ execResults = {
1242
+ status: "bailed",
1243
+ output: bailed.payload,
1244
+ payload: inputData,
1245
+ endedAt: Date.now(),
1246
+ startedAt
1247
+ };
1248
+ }
1249
+ await emitter.emit("watch", {
1250
+ type: "watch",
1251
+ payload: {
1252
+ currentStep: {
1253
+ id: step.id,
1254
+ ...execResults
1255
+ },
1256
+ workflowState: {
1257
+ status: "running",
1258
+ steps: { ...stepResults, [step.id]: execResults },
1259
+ result: null,
1260
+ error: null
1085
1261
  }
1086
- return null;
1087
- },
1088
- suspend: async (suspendPayload) => {
1089
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1090
- suspended = { payload: suspendPayload };
1091
- },
1092
- bail: (result2) => {
1093
- bailed = { payload: result2 };
1094
1262
  },
1095
- resume: {
1096
- steps: resume?.steps?.slice(1) || [],
1097
- resumePayload: resume?.resumePayload,
1098
- // @ts-ignore
1099
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1100
- },
1101
- [_constants.EMITTER_SYMBOL]: emitter,
1102
- engine: {
1103
- step: this.inngestStep
1104
- },
1105
- abortSignal: abortController.signal
1263
+ eventTimestamp: Date.now()
1106
1264
  });
1107
- const endedAt = Date.now();
1108
- execResults = {
1109
- status: "success",
1110
- output: result,
1111
- startedAt,
1112
- endedAt,
1113
- payload: prevOutput,
1114
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1115
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1116
- };
1117
- } catch (e) {
1118
- execResults = {
1119
- status: "failed",
1120
- payload: prevOutput,
1121
- error: e instanceof Error ? e.message : String(e),
1122
- endedAt: Date.now(),
1123
- startedAt,
1124
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1125
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1126
- };
1127
- }
1128
- if (suspended) {
1129
- execResults = {
1130
- status: "suspended",
1131
- suspendedPayload: suspended.payload,
1132
- payload: prevOutput,
1133
- suspendedAt: Date.now(),
1134
- startedAt,
1135
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1136
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1137
- };
1138
- } else if (bailed) {
1139
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1140
- }
1141
- if (execResults.status === "failed") {
1142
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1143
- const error = new Error(execResults.error);
1144
- stepAISpan?.error({ error });
1145
- throw error;
1265
+ if (execResults.status === "suspended") {
1266
+ await emitter.emit("watch-v2", {
1267
+ type: "workflow-step-suspended",
1268
+ payload: {
1269
+ id: step.id,
1270
+ ...execResults
1271
+ }
1272
+ });
1273
+ } else {
1274
+ await emitter.emit("watch-v2", {
1275
+ type: "workflow-step-result",
1276
+ payload: {
1277
+ id: step.id,
1278
+ ...execResults
1279
+ }
1280
+ });
1281
+ await emitter.emit("watch-v2", {
1282
+ type: "workflow-step-finish",
1283
+ payload: {
1284
+ id: step.id,
1285
+ metadata: {}
1286
+ }
1287
+ });
1146
1288
  }
1147
- }
1148
- await emitter.emit("watch", {
1149
- type: "watch",
1150
- payload: {
1151
- currentStep: {
1152
- id: step.id,
1153
- ...execResults
1154
- },
1155
- workflowState: {
1156
- status: "running",
1157
- steps: { ...stepResults, [step.id]: execResults },
1158
- result: null,
1159
- error: null
1160
- }
1161
- },
1162
- eventTimestamp: Date.now()
1289
+ stepAISpan?.end({ output: execResults });
1290
+ return { result: execResults, executionContext, stepResults };
1163
1291
  });
1164
- if (execResults.status === "suspended") {
1165
- await emitter.emit("watch-v2", {
1166
- type: "workflow-step-suspended",
1167
- payload: {
1168
- id: step.id,
1169
- ...execResults
1170
- }
1171
- });
1172
- } else {
1173
- await emitter.emit("watch-v2", {
1174
- type: "workflow-step-result",
1175
- payload: {
1176
- id: step.id,
1177
- ...execResults
1178
- }
1179
- });
1180
- await emitter.emit("watch-v2", {
1181
- type: "workflow-step-finish",
1182
- payload: {
1183
- id: step.id,
1184
- metadata: {}
1185
- }
1186
- });
1187
- }
1188
- stepAISpan?.end({ output: execResults });
1189
- return { result: execResults, executionContext, stepResults };
1190
- });
1191
- if (disableScorers !== false) {
1292
+ } catch (e) {
1293
+ const stepFailure = e instanceof Error ? e?.cause : {
1294
+ status: "failed",
1295
+ error: e instanceof Error ? e.message : String(e),
1296
+ payload: inputData,
1297
+ startedAt,
1298
+ endedAt: Date.now()
1299
+ };
1300
+ stepRes = {
1301
+ result: stepFailure,
1302
+ executionContext,
1303
+ stepResults: {
1304
+ ...stepResults,
1305
+ [step.id]: stepFailure
1306
+ }
1307
+ };
1308
+ }
1309
+ if (disableScorers !== false && stepRes.result.status === "success") {
1192
1310
  await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1193
1311
  if (step.scorers) {
1194
1312
  await this.runScorers({
1195
1313
  scorers: step.scorers,
1196
1314
  runId: executionContext.runId,
1197
- input: prevOutput,
1315
+ input: inputData,
1198
1316
  output: stepRes.result,
1199
1317
  workflowId: executionContext.workflowId,
1200
1318
  stepId: step.id,
@@ -1207,12 +1325,14 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1207
1325
  }
1208
1326
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1209
1327
  Object.assign(stepResults, stepRes.stepResults);
1328
+ executionContext.state = stepRes.executionContext.state;
1210
1329
  return stepRes.result;
1211
1330
  }
1212
1331
  async persistStepUpdate({
1213
1332
  workflowId,
1214
1333
  runId,
1215
1334
  stepResults,
1335
+ resourceId,
1216
1336
  executionContext,
1217
1337
  serializedStepGraph,
1218
1338
  workflowStatus,
@@ -1222,15 +1342,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1222
1342
  await this.inngestStep.run(
1223
1343
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1224
1344
  async () => {
1345
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1346
+ if (!shouldPersistSnapshot) {
1347
+ return;
1348
+ }
1225
1349
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1226
1350
  workflowName: workflowId,
1227
1351
  runId,
1352
+ resourceId,
1228
1353
  snapshot: {
1229
1354
  runId,
1230
- value: {},
1355
+ value: executionContext.state,
1231
1356
  context: stepResults,
1232
1357
  activePaths: [],
1233
1358
  suspendedPaths: executionContext.suspendedPaths,
1359
+ resumeLabels: executionContext.resumeLabels,
1234
1360
  waitingPaths: {},
1235
1361
  serializedStepGraph,
1236
1362
  status: workflowStatus,
@@ -1262,11 +1388,12 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1262
1388
  }) {
1263
1389
  const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1264
1390
  type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
1265
- name: `conditional: ${entry.conditions.length} conditions`,
1391
+ name: `conditional: '${entry.conditions.length} conditions'`,
1266
1392
  input: prevOutput,
1267
1393
  attributes: {
1268
1394
  conditionCount: entry.conditions.length
1269
- }
1395
+ },
1396
+ tracingPolicy: this.options?.tracingPolicy
1270
1397
  });
1271
1398
  let execResults;
1272
1399
  const truthyIndexes = (await Promise.all(
@@ -1274,11 +1401,12 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1274
1401
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1275
1402
  const evalSpan = conditionalSpan?.createChildSpan({
1276
1403
  type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1277
- name: `condition ${index}`,
1404
+ name: `condition: '${index}'`,
1278
1405
  input: prevOutput,
1279
1406
  attributes: {
1280
1407
  conditionIndex: index
1281
- }
1408
+ },
1409
+ tracingPolicy: this.options?.tracingPolicy
1282
1410
  });
1283
1411
  try {
1284
1412
  const result = await cond({
@@ -1288,20 +1416,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1288
1416
  runtimeContext,
1289
1417
  runCount: -1,
1290
1418
  inputData: prevOutput,
1419
+ state: executionContext.state,
1420
+ setState: (state) => {
1421
+ executionContext.state = state;
1422
+ },
1291
1423
  tracingContext: {
1292
1424
  currentSpan: evalSpan
1293
1425
  },
1294
1426
  getInitData: () => stepResults?.input,
1295
- getStepResult: (step) => {
1296
- if (!step?.id) {
1297
- return null;
1298
- }
1299
- const result2 = stepResults[step.id];
1300
- if (result2?.status === "success") {
1301
- return result2.output;
1302
- }
1303
- return null;
1304
- },
1427
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1305
1428
  // TODO: this function shouldn't have suspend probably?
1306
1429
  suspend: async (_suspendPayload) => {
1307
1430
  },
@@ -1368,8 +1491,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1368
1491
  runId,
1369
1492
  executionPath: [...executionContext.executionPath, index],
1370
1493
  suspendedPaths: executionContext.suspendedPaths,
1494
+ resumeLabels: executionContext.resumeLabels,
1371
1495
  retryConfig: executionContext.retryConfig,
1372
- executionSpan: executionContext.executionSpan
1496
+ executionSpan: executionContext.executionSpan,
1497
+ state: executionContext.state
1373
1498
  },
1374
1499
  emitter,
1375
1500
  abortController,
@@ -1387,7 +1512,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1387
1512
  if (hasFailed) {
1388
1513
  execResults = { status: "failed", error: hasFailed.result.error };
1389
1514
  } else if (hasSuspended) {
1390
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1515
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1391
1516
  } else {
1392
1517
  execResults = {
1393
1518
  status: "success",