@mastra/inngest 0.0.0-iterate-traces-ui-again-20250912091900 → 0.0.0-main-test-20251105183450

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,17 +1,25 @@
1
1
  import { randomUUID } from 'crypto';
2
+ import { ReadableStream } from 'stream/web';
2
3
  import { subscribe } from '@inngest/realtime';
3
- import { wrapMastra, AISpanType } from '@mastra/core/ai-tracing';
4
- import { RuntimeContext } from '@mastra/core/di';
4
+ import { RequestContext } from '@mastra/core/di';
5
+ import { wrapMastra, SpanType } from '@mastra/core/observability';
6
+ import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
5
7
  import { ToolStream, Tool } from '@mastra/core/tools';
6
- import { Run, Workflow, DefaultExecutionEngine } from '@mastra/core/workflows';
8
+ import { Run, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput } from '@mastra/core/workflows';
7
9
  import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
10
+ import { NonRetriableError, RetryAfterError } from 'inngest';
8
11
  import { serve as serve$1 } from 'inngest/hono';
9
12
  import { z } from 'zod';
10
13
 
11
14
  // src/index.ts
12
- function serve({ mastra, inngest }) {
13
- const wfs = mastra.getWorkflows();
14
- const functions = Array.from(
15
+ function serve({
16
+ mastra,
17
+ inngest,
18
+ functions: userFunctions = [],
19
+ registerOptions
20
+ }) {
21
+ const wfs = mastra.listWorkflows();
22
+ const workflowFunctions = Array.from(
15
23
  new Set(
16
24
  Object.values(wfs).flatMap((wf) => {
17
25
  if (wf instanceof InngestWorkflow) {
@@ -23,8 +31,9 @@ function serve({ mastra, inngest }) {
23
31
  )
24
32
  );
25
33
  return serve$1({
34
+ ...registerOptions,
26
35
  client: inngest,
27
- functions
36
+ functions: [...workflowFunctions, ...userFunctions]
28
37
  });
29
38
  }
30
39
  var InngestRun = class extends Run {
@@ -48,14 +57,21 @@ var InngestRun = class extends Run {
48
57
  }
49
58
  async getRunOutput(eventId) {
50
59
  let runs = await this.getRuns(eventId);
60
+ const storage = this.#mastra?.getStorage();
51
61
  while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
52
62
  await new Promise((resolve) => setTimeout(resolve, 1e3));
53
63
  runs = await this.getRuns(eventId);
54
64
  if (runs?.[0]?.status === "Failed") {
55
- console.log("run", runs?.[0]);
56
- throw new Error(`Function run ${runs?.[0]?.status}`);
57
- } else if (runs?.[0]?.status === "Cancelled") {
58
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
65
+ const snapshot = await storage?.loadWorkflowSnapshot({
66
+ workflowName: this.workflowId,
67
+ runId: this.runId
68
+ });
69
+ return {
70
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
71
+ };
72
+ }
73
+ if (runs?.[0]?.status === "Cancelled") {
74
+ const snapshot = await storage?.loadWorkflowSnapshot({
59
75
  workflowName: this.workflowId,
60
76
  runId: this.runId
61
77
  });
@@ -71,20 +87,22 @@ var InngestRun = class extends Run {
71
87
  });
72
88
  }
73
89
  async cancel() {
90
+ const storage = this.#mastra?.getStorage();
74
91
  await this.inngest.send({
75
92
  name: `cancel.workflow.${this.workflowId}`,
76
93
  data: {
77
94
  runId: this.runId
78
95
  }
79
96
  });
80
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
97
+ const snapshot = await storage?.loadWorkflowSnapshot({
81
98
  workflowName: this.workflowId,
82
99
  runId: this.runId
83
100
  });
84
101
  if (snapshot) {
85
- await this.#mastra?.storage?.persistWorkflowSnapshot({
102
+ await storage?.persistWorkflowSnapshot({
86
103
  workflowName: this.workflowId,
87
104
  runId: this.runId,
105
+ resourceId: this.resourceId,
88
106
  snapshot: {
89
107
  ...snapshot,
90
108
  status: "canceled"
@@ -92,12 +110,20 @@ var InngestRun = class extends Run {
92
110
  });
93
111
  }
94
112
  }
95
- async start({
96
- inputData
113
+ async start(params) {
114
+ return this._start(params);
115
+ }
116
+ async _start({
117
+ inputData,
118
+ initialState,
119
+ outputOptions,
120
+ tracingOptions,
121
+ format
97
122
  }) {
98
123
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
99
124
  workflowName: this.workflowId,
100
125
  runId: this.runId,
126
+ resourceId: this.resourceId,
101
127
  snapshot: {
102
128
  runId: this.runId,
103
129
  serializedStepGraph: this.serializedStepGraph,
@@ -105,16 +131,24 @@ var InngestRun = class extends Run {
105
131
  context: {},
106
132
  activePaths: [],
107
133
  suspendedPaths: {},
134
+ resumeLabels: {},
108
135
  waitingPaths: {},
109
136
  timestamp: Date.now(),
110
137
  status: "running"
111
138
  }
112
139
  });
140
+ const inputDataToUse = await this._validateInput(inputData);
141
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
113
142
  const eventOutput = await this.inngest.send({
114
143
  name: `workflow.${this.workflowId}`,
115
144
  data: {
116
- inputData,
117
- runId: this.runId
145
+ inputData: inputDataToUse,
146
+ initialState: initialStateToUse,
147
+ runId: this.runId,
148
+ resourceId: this.resourceId,
149
+ outputOptions,
150
+ tracingOptions,
151
+ format
118
152
  }
119
153
  });
120
154
  const eventId = eventOutput.ids[0];
@@ -143,24 +177,28 @@ var InngestRun = class extends Run {
143
177
  return p;
144
178
  }
145
179
  async _resume(params) {
180
+ const storage = this.#mastra?.getStorage();
146
181
  const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
147
182
  (step) => typeof step === "string" ? step : step?.id
148
183
  );
149
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
184
+ const snapshot = await storage?.loadWorkflowSnapshot({
150
185
  workflowName: this.workflowId,
151
186
  runId: this.runId
152
187
  });
188
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
189
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
153
190
  const eventOutput = await this.inngest.send({
154
191
  name: `workflow.${this.workflowId}`,
155
192
  data: {
156
- inputData: params.resumeData,
193
+ inputData: resumeDataToUse,
194
+ initialState: snapshot?.value ?? {},
157
195
  runId: this.runId,
158
196
  workflowId: this.workflowId,
159
197
  stepResults: snapshot?.context,
160
198
  resume: {
161
199
  steps,
162
200
  stepResults: snapshot?.context,
163
- resumePayload: params.resumeData,
201
+ resumePayload: resumeDataToUse,
164
202
  // @ts-ignore
165
203
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
166
204
  }
@@ -177,12 +215,12 @@ var InngestRun = class extends Run {
177
215
  }
178
216
  return result;
179
217
  }
180
- watch(cb, type = "watch") {
218
+ watch(cb) {
181
219
  let active = true;
182
220
  const streamPromise = subscribe(
183
221
  {
184
222
  channel: `workflow:${this.workflowId}:${this.runId}`,
185
- topics: [type],
223
+ topics: ["watch"],
186
224
  app: this.inngest
187
225
  },
188
226
  (message) => {
@@ -200,44 +238,35 @@ var InngestRun = class extends Run {
200
238
  });
201
239
  };
202
240
  }
203
- stream({ inputData, runtimeContext } = {}) {
241
+ streamLegacy({ inputData, requestContext } = {}) {
204
242
  const { readable, writable } = new TransformStream();
205
- let currentToolData = void 0;
206
243
  const writer = writable.getWriter();
207
244
  const unwatch = this.watch(async (event) => {
208
- if (event.type === "workflow-agent-call-start") {
209
- currentToolData = {
210
- name: event.payload.name,
211
- args: event.payload.args
212
- };
245
+ try {
213
246
  await writer.write({
214
- ...event.payload,
215
- type: "tool-call-streaming-start"
247
+ // @ts-ignore
248
+ type: "start",
249
+ // @ts-ignore
250
+ payload: { runId: this.runId }
216
251
  });
217
- return;
218
- }
219
- try {
220
- if (event.type === "workflow-agent-call-finish") {
221
- return;
222
- } else if (!event.type.startsWith("workflow-")) {
223
- if (event.type === "text-delta") {
224
- await writer.write({
225
- type: "tool-call-delta",
226
- ...currentToolData ?? {},
227
- argsTextDelta: event.textDelta
228
- });
229
- }
230
- return;
231
- }
232
252
  const e = {
233
253
  ...event,
234
254
  type: event.type.replace("workflow-", "")
235
255
  };
256
+ if (e.type === "step-output") {
257
+ e.type = e.payload.output.type;
258
+ e.payload = e.payload.output.payload;
259
+ }
236
260
  await writer.write(e);
237
261
  } catch {
238
262
  }
239
- }, "watch-v2");
263
+ });
240
264
  this.closeStreamAction = async () => {
265
+ await writer.write({
266
+ type: "finish",
267
+ // @ts-ignore
268
+ payload: { runId: this.runId }
269
+ });
241
270
  unwatch();
242
271
  try {
243
272
  await writer.close();
@@ -247,7 +276,7 @@ var InngestRun = class extends Run {
247
276
  writer.releaseLock();
248
277
  }
249
278
  };
250
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
279
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
251
280
  if (result.status !== "suspended") {
252
281
  this.closeStreamAction?.().catch(() => {
253
282
  });
@@ -259,6 +288,82 @@ var InngestRun = class extends Run {
259
288
  getWorkflowState: () => this.executionResults
260
289
  };
261
290
  }
291
+ stream({
292
+ inputData,
293
+ requestContext,
294
+ tracingOptions,
295
+ closeOnSuspend = true,
296
+ initialState,
297
+ outputOptions
298
+ } = {}) {
299
+ if (this.closeStreamAction && this.streamOutput) {
300
+ return this.streamOutput;
301
+ }
302
+ this.closeStreamAction = async () => {
303
+ };
304
+ const self = this;
305
+ const stream = new ReadableStream({
306
+ async start(controller) {
307
+ const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
308
+ controller.enqueue({
309
+ type,
310
+ runId: self.runId,
311
+ from,
312
+ payload: {
313
+ stepName: payload?.id,
314
+ ...payload
315
+ }
316
+ });
317
+ });
318
+ self.closeStreamAction = async () => {
319
+ unwatch();
320
+ try {
321
+ await controller.close();
322
+ } catch (err) {
323
+ console.error("Error closing stream:", err);
324
+ }
325
+ };
326
+ const executionResultsPromise = self._start({
327
+ inputData,
328
+ requestContext,
329
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
330
+ initialState,
331
+ tracingOptions,
332
+ outputOptions,
333
+ format: "vnext"
334
+ });
335
+ let executionResults;
336
+ try {
337
+ executionResults = await executionResultsPromise;
338
+ if (closeOnSuspend) {
339
+ self.closeStreamAction?.().catch(() => {
340
+ });
341
+ } else if (executionResults.status !== "suspended") {
342
+ self.closeStreamAction?.().catch(() => {
343
+ });
344
+ }
345
+ if (self.streamOutput) {
346
+ self.streamOutput.updateResults(
347
+ executionResults
348
+ );
349
+ }
350
+ } catch (err) {
351
+ self.streamOutput?.rejectResults(err);
352
+ self.closeStreamAction?.().catch(() => {
353
+ });
354
+ }
355
+ }
356
+ });
357
+ this.streamOutput = new WorkflowRunOutput({
358
+ runId: this.runId,
359
+ workflowId: this.workflowId,
360
+ stream
361
+ });
362
+ return this.streamOutput;
363
+ }
364
+ streamVNext(args = {}) {
365
+ return this.stream(args);
366
+ }
262
367
  };
263
368
  var InngestWorkflow = class _InngestWorkflow extends Workflow {
264
369
  #mastra;
@@ -275,13 +380,13 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
275
380
  this.#mastra = params.mastra;
276
381
  this.inngest = inngest;
277
382
  }
278
- async getWorkflowRuns(args) {
383
+ async listWorkflowRuns(args) {
279
384
  const storage = this.#mastra?.getStorage();
280
385
  if (!storage) {
281
386
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
282
387
  return { runs: [], total: 0 };
283
388
  }
284
- return storage.getWorkflowRuns({ workflowName: this.id, ...args ?? {} });
389
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
285
390
  }
286
391
  async getWorkflowRunById(runId) {
287
392
  const storage = this.#mastra?.getStorage();
@@ -310,45 +415,34 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
310
415
  }
311
416
  }
312
417
  }
313
- createRun(options) {
314
- const runIdToUse = options?.runId || randomUUID();
315
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
316
- {
317
- workflowId: this.id,
318
- runId: runIdToUse,
319
- executionEngine: this.executionEngine,
320
- executionGraph: this.executionGraph,
321
- serializedStepGraph: this.serializedStepGraph,
322
- mastra: this.#mastra,
323
- retryConfig: this.retryConfig,
324
- cleanup: () => this.runs.delete(runIdToUse)
325
- },
326
- this.inngest
327
- );
328
- this.runs.set(runIdToUse, run);
329
- return run;
330
- }
331
- async createRunAsync(options) {
418
+ async createRun(options) {
332
419
  const runIdToUse = options?.runId || randomUUID();
333
420
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
334
421
  {
335
422
  workflowId: this.id,
336
423
  runId: runIdToUse,
424
+ resourceId: options?.resourceId,
337
425
  executionEngine: this.executionEngine,
338
426
  executionGraph: this.executionGraph,
339
427
  serializedStepGraph: this.serializedStepGraph,
340
428
  mastra: this.#mastra,
341
429
  retryConfig: this.retryConfig,
342
- cleanup: () => this.runs.delete(runIdToUse)
430
+ cleanup: () => this.runs.delete(runIdToUse),
431
+ workflowSteps: this.steps
343
432
  },
344
433
  this.inngest
345
434
  );
346
435
  this.runs.set(runIdToUse, run);
436
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
437
+ workflowStatus: run.workflowRunStatus,
438
+ stepResults: {}
439
+ });
347
440
  const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
348
- if (!workflowSnapshotInStorage) {
441
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
349
442
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
350
443
  workflowName: this.id,
351
444
  runId: runIdToUse,
445
+ resourceId: options?.resourceId,
352
446
  snapshot: {
353
447
  runId: runIdToUse,
354
448
  status: "pending",
@@ -358,6 +452,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
358
452
  waitingPaths: {},
359
453
  serializedStepGraph: this.serializedStepGraph,
360
454
  suspendedPaths: {},
455
+ resumeLabels: {},
361
456
  result: void 0,
362
457
  error: void 0,
363
458
  // @ts-ignore
@@ -382,7 +477,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
382
477
  },
383
478
  { event: `workflow.${this.id}` },
384
479
  async ({ event, step, attempt, publish }) => {
385
- let { inputData, runId, resume } = event.data;
480
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
386
481
  if (!runId) {
387
482
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
388
483
  return randomUUID();
@@ -410,21 +505,38 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
410
505
  once: (_event, _callback) => {
411
506
  }
412
507
  };
413
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
508
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
414
509
  const result = await engine.execute({
415
510
  workflowId: this.id,
416
511
  runId,
512
+ resourceId,
417
513
  graph: this.executionGraph,
418
514
  serializedStepGraph: this.serializedStepGraph,
419
515
  input: inputData,
516
+ initialState,
420
517
  emitter,
421
518
  retryConfig: this.retryConfig,
422
- runtimeContext: new RuntimeContext(),
519
+ requestContext: new RequestContext(),
423
520
  // TODO
424
521
  resume,
522
+ format,
425
523
  abortController: new AbortController(),
426
- currentSpan: void 0
427
- // TODO: Pass actual parent AI span from workflow execution context
524
+ // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
525
+ outputOptions,
526
+ writableStream: new WritableStream({
527
+ write(chunk) {
528
+ void emitter.emit("watch", chunk).catch(() => {
529
+ });
530
+ }
531
+ })
532
+ });
533
+ await step.run(`workflow.${this.id}.finalize`, async () => {
534
+ if (result.status === "failed") {
535
+ throw new NonRetriableError(`Workflow failed`, {
536
+ cause: result
537
+ });
538
+ }
539
+ return result;
428
540
  });
429
541
  return { result, runId };
430
542
  }
@@ -454,10 +566,11 @@ function isAgent(params) {
454
566
  function isTool(params) {
455
567
  return params instanceof Tool;
456
568
  }
457
- function createStep(params) {
569
+ function createStep(params, agentOptions) {
458
570
  if (isAgent(params)) {
459
571
  return {
460
572
  id: params.name,
573
+ description: params.getDescription(),
461
574
  // @ts-ignore
462
575
  inputSchema: z.object({
463
576
  prompt: z.string()
@@ -468,7 +581,16 @@ function createStep(params) {
468
581
  outputSchema: z.object({
469
582
  text: z.string()
470
583
  }),
471
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
584
+ execute: async ({
585
+ inputData,
586
+ [EMITTER_SYMBOL]: emitter,
587
+ [STREAM_FORMAT_SYMBOL]: streamFormat,
588
+ requestContext,
589
+ tracingContext,
590
+ abortSignal,
591
+ abort,
592
+ writer
593
+ }) => {
472
594
  let streamPromise = {};
473
595
  streamPromise.promise = new Promise((resolve, reject) => {
474
596
  streamPromise.resolve = resolve;
@@ -478,34 +600,65 @@ function createStep(params) {
478
600
  name: params.name,
479
601
  args: inputData
480
602
  };
481
- await emitter.emit("watch-v2", {
482
- type: "workflow-agent-call-start",
483
- payload: toolData
484
- });
485
- const { fullStream } = await params.stream(inputData.prompt, {
486
- // resourceId: inputData.resourceId,
487
- // threadId: inputData.threadId,
488
- runtimeContext,
489
- tracingContext,
490
- onFinish: (result) => {
491
- streamPromise.resolve(result.text);
492
- },
493
- abortSignal
494
- });
603
+ let stream;
604
+ if ((await params.getModel()).specificationVersion === "v1") {
605
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
606
+ ...agentOptions ?? {},
607
+ // resourceId: inputData.resourceId,
608
+ // threadId: inputData.threadId,
609
+ requestContext,
610
+ tracingContext,
611
+ onFinish: (result) => {
612
+ streamPromise.resolve(result.text);
613
+ void agentOptions?.onFinish?.(result);
614
+ },
615
+ abortSignal
616
+ });
617
+ stream = fullStream;
618
+ } else {
619
+ const modelOutput = await params.stream(inputData.prompt, {
620
+ ...agentOptions ?? {},
621
+ requestContext,
622
+ tracingContext,
623
+ onFinish: (result) => {
624
+ streamPromise.resolve(result.text);
625
+ void agentOptions?.onFinish?.(result);
626
+ },
627
+ abortSignal
628
+ });
629
+ stream = modelOutput.fullStream;
630
+ }
631
+ if (streamFormat === "legacy") {
632
+ await emitter.emit("watch", {
633
+ type: "tool-call-streaming-start",
634
+ ...toolData ?? {}
635
+ });
636
+ for await (const chunk of stream) {
637
+ if (chunk.type === "text-delta") {
638
+ await emitter.emit("watch", {
639
+ type: "tool-call-delta",
640
+ ...toolData ?? {},
641
+ argsTextDelta: chunk.textDelta
642
+ });
643
+ }
644
+ }
645
+ await emitter.emit("watch", {
646
+ type: "tool-call-streaming-finish",
647
+ ...toolData ?? {}
648
+ });
649
+ } else {
650
+ for await (const chunk of stream) {
651
+ await writer.write(chunk);
652
+ }
653
+ }
495
654
  if (abortSignal.aborted) {
496
655
  return abort();
497
656
  }
498
- for await (const chunk of fullStream) {
499
- await emitter.emit("watch-v2", chunk);
500
- }
501
- await emitter.emit("watch-v2", {
502
- type: "workflow-agent-call-finish",
503
- payload: toolData
504
- });
505
657
  return {
506
658
  text: await streamPromise.promise
507
659
  };
508
- }
660
+ },
661
+ component: params.component
509
662
  };
510
663
  }
511
664
  if (isTool(params)) {
@@ -516,16 +669,20 @@ function createStep(params) {
516
669
  // TODO: tool probably should have strong id type
517
670
  // @ts-ignore
518
671
  id: params.id,
672
+ description: params.description,
519
673
  inputSchema: params.inputSchema,
520
674
  outputSchema: params.outputSchema,
521
- execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
675
+ execute: async ({ inputData, mastra, requestContext, tracingContext, suspend, resumeData }) => {
522
676
  return params.execute({
523
677
  context: inputData,
524
678
  mastra: wrapMastra(mastra, tracingContext),
525
- runtimeContext,
526
- tracingContext
679
+ requestContext,
680
+ tracingContext,
681
+ suspend,
682
+ resumeData
527
683
  });
528
- }
684
+ },
685
+ component: "TOOL"
529
686
  };
530
687
  }
531
688
  return {
@@ -541,7 +698,10 @@ function createStep(params) {
541
698
  function init(inngest) {
542
699
  return {
543
700
  createWorkflow(params) {
544
- return new InngestWorkflow(params, inngest);
701
+ return new InngestWorkflow(
702
+ params,
703
+ inngest
704
+ );
545
705
  },
546
706
  createStep,
547
707
  cloneStep(step, opts) {
@@ -550,7 +710,11 @@ function init(inngest) {
550
710
  description: step.description,
551
711
  inputSchema: step.inputSchema,
552
712
  outputSchema: step.outputSchema,
553
- execute: step.execute
713
+ resumeSchema: step.resumeSchema,
714
+ suspendSchema: step.suspendSchema,
715
+ stateSchema: step.stateSchema,
716
+ execute: step.execute,
717
+ component: step.component
554
718
  };
555
719
  },
556
720
  cloneWorkflow(workflow, opts) {
@@ -570,78 +734,30 @@ function init(inngest) {
570
734
  var InngestExecutionEngine = class extends DefaultExecutionEngine {
571
735
  inngestStep;
572
736
  inngestAttempts;
573
- constructor(mastra, inngestStep, inngestAttempts = 0) {
574
- super({ mastra });
737
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
738
+ super({ mastra, options });
575
739
  this.inngestStep = inngestStep;
576
740
  this.inngestAttempts = inngestAttempts;
577
741
  }
578
- async execute(params) {
579
- await params.emitter.emit("watch-v2", {
580
- type: "workflow-start",
581
- payload: { runId: params.runId }
582
- });
583
- const result = await super.execute(params);
584
- await params.emitter.emit("watch-v2", {
585
- type: "workflow-finish",
586
- payload: { runId: params.runId }
587
- });
588
- return result;
589
- }
590
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
742
+ async fmtReturnValue(emitter, stepResults, lastOutput, error) {
591
743
  const base = {
592
744
  status: lastOutput.status,
593
745
  steps: stepResults
594
746
  };
595
747
  if (lastOutput.status === "success") {
596
- await emitter.emit("watch", {
597
- type: "watch",
598
- payload: {
599
- workflowState: {
600
- status: lastOutput.status,
601
- steps: stepResults,
602
- result: lastOutput.output
603
- }
604
- },
605
- eventTimestamp: Date.now()
606
- });
607
748
  base.result = lastOutput.output;
608
749
  } else if (lastOutput.status === "failed") {
609
750
  base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
610
- await emitter.emit("watch", {
611
- type: "watch",
612
- payload: {
613
- workflowState: {
614
- status: lastOutput.status,
615
- steps: stepResults,
616
- result: null,
617
- error: base.error
618
- }
619
- },
620
- eventTimestamp: Date.now()
621
- });
622
751
  } else if (lastOutput.status === "suspended") {
623
- await emitter.emit("watch", {
624
- type: "watch",
625
- payload: {
626
- workflowState: {
627
- status: lastOutput.status,
628
- steps: stepResults,
629
- result: null,
630
- error: null
631
- }
632
- },
633
- eventTimestamp: Date.now()
634
- });
635
752
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
636
753
  if (stepResult?.status === "suspended") {
637
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
754
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
638
755
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
639
756
  }
640
757
  return [];
641
758
  });
642
759
  base.suspended = suspendedStepIds;
643
760
  }
644
- executionSpan?.end();
645
761
  return base;
646
762
  }
647
763
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
@@ -655,67 +771,71 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
655
771
  stepResults,
656
772
  emitter,
657
773
  abortController,
658
- runtimeContext,
774
+ requestContext,
659
775
  executionContext,
660
776
  writableStream,
661
777
  tracingContext
662
778
  }) {
663
779
  let { duration, fn } = entry;
664
780
  const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
665
- type: AISpanType.WORKFLOW_SLEEP,
781
+ type: SpanType.WORKFLOW_SLEEP,
666
782
  name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
667
783
  attributes: {
668
784
  durationMs: duration,
669
785
  sleepType: fn ? "dynamic" : "fixed"
670
- }
786
+ },
787
+ tracingPolicy: this.options?.tracingPolicy
671
788
  });
672
789
  if (fn) {
673
790
  const stepCallId = randomUUID();
674
791
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
675
- return await fn({
676
- runId,
677
- workflowId,
678
- mastra: this.mastra,
679
- runtimeContext,
680
- inputData: prevOutput,
681
- runCount: -1,
682
- tracingContext: {
683
- currentSpan: sleepSpan
684
- },
685
- getInitData: () => stepResults?.input,
686
- getStepResult: (step) => {
687
- if (!step?.id) {
688
- return null;
689
- }
690
- const result = stepResults[step.id];
691
- if (result?.status === "success") {
692
- return result.output;
693
- }
694
- return null;
695
- },
696
- // TODO: this function shouldn't have suspend probably?
697
- suspend: async (_suspendPayload) => {
698
- },
699
- bail: () => {
700
- },
701
- abort: () => {
702
- abortController?.abort();
703
- },
704
- [EMITTER_SYMBOL]: emitter,
705
- // TODO: add streamVNext support
706
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
707
- engine: { step: this.inngestStep },
708
- abortSignal: abortController?.signal,
709
- writer: new ToolStream(
792
+ return await fn(
793
+ createDeprecationProxy(
710
794
  {
711
- prefix: "workflow-step",
712
- callId: stepCallId,
713
- name: "sleep",
714
- runId
795
+ runId,
796
+ workflowId,
797
+ mastra: this.mastra,
798
+ requestContext,
799
+ inputData: prevOutput,
800
+ state: executionContext.state,
801
+ setState: (state) => {
802
+ executionContext.state = state;
803
+ },
804
+ retryCount: -1,
805
+ tracingContext: {
806
+ currentSpan: sleepSpan
807
+ },
808
+ getInitData: () => stepResults?.input,
809
+ getStepResult: getStepResult.bind(this, stepResults),
810
+ // TODO: this function shouldn't have suspend probably?
811
+ suspend: async (_suspendPayload) => {
812
+ },
813
+ bail: () => {
814
+ },
815
+ abort: () => {
816
+ abortController?.abort();
817
+ },
818
+ [EMITTER_SYMBOL]: emitter,
819
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
820
+ engine: { step: this.inngestStep },
821
+ abortSignal: abortController?.signal,
822
+ writer: new ToolStream(
823
+ {
824
+ prefix: "workflow-step",
825
+ callId: stepCallId,
826
+ name: "sleep",
827
+ runId
828
+ },
829
+ writableStream
830
+ )
715
831
  },
716
- writableStream
832
+ {
833
+ paramName: "runCount",
834
+ deprecationMessage: runCountDeprecationMessage,
835
+ logger: this.logger
836
+ }
717
837
  )
718
- });
838
+ );
719
839
  });
720
840
  sleepSpan?.update({
721
841
  attributes: {
@@ -739,69 +859,76 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
739
859
  stepResults,
740
860
  emitter,
741
861
  abortController,
742
- runtimeContext,
862
+ requestContext,
743
863
  executionContext,
744
864
  writableStream,
745
865
  tracingContext
746
866
  }) {
747
867
  let { date, fn } = entry;
748
868
  const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
749
- type: AISpanType.WORKFLOW_SLEEP,
869
+ type: SpanType.WORKFLOW_SLEEP,
750
870
  name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
751
871
  attributes: {
752
872
  untilDate: date,
753
873
  durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
754
874
  sleepType: fn ? "dynamic" : "fixed"
755
- }
875
+ },
876
+ tracingPolicy: this.options?.tracingPolicy
756
877
  });
757
878
  if (fn) {
758
879
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
759
880
  const stepCallId = randomUUID();
760
- return await fn({
761
- runId,
762
- workflowId,
763
- mastra: this.mastra,
764
- runtimeContext,
765
- inputData: prevOutput,
766
- runCount: -1,
767
- tracingContext: {
768
- currentSpan: sleepUntilSpan
769
- },
770
- getInitData: () => stepResults?.input,
771
- getStepResult: (step) => {
772
- if (!step?.id) {
773
- return null;
774
- }
775
- const result = stepResults[step.id];
776
- if (result?.status === "success") {
777
- return result.output;
778
- }
779
- return null;
780
- },
781
- // TODO: this function shouldn't have suspend probably?
782
- suspend: async (_suspendPayload) => {
783
- },
784
- bail: () => {
785
- },
786
- abort: () => {
787
- abortController?.abort();
788
- },
789
- [EMITTER_SYMBOL]: emitter,
790
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
791
- // TODO: add streamVNext support
792
- engine: { step: this.inngestStep },
793
- abortSignal: abortController?.signal,
794
- writer: new ToolStream(
881
+ return await fn(
882
+ createDeprecationProxy(
795
883
  {
796
- prefix: "workflow-step",
797
- callId: stepCallId,
798
- name: "sleep",
799
- runId
884
+ runId,
885
+ workflowId,
886
+ mastra: this.mastra,
887
+ requestContext,
888
+ inputData: prevOutput,
889
+ state: executionContext.state,
890
+ setState: (state) => {
891
+ executionContext.state = state;
892
+ },
893
+ retryCount: -1,
894
+ tracingContext: {
895
+ currentSpan: sleepUntilSpan
896
+ },
897
+ getInitData: () => stepResults?.input,
898
+ getStepResult: getStepResult.bind(this, stepResults),
899
+ // TODO: this function shouldn't have suspend probably?
900
+ suspend: async (_suspendPayload) => {
901
+ },
902
+ bail: () => {
903
+ },
904
+ abort: () => {
905
+ abortController?.abort();
906
+ },
907
+ [EMITTER_SYMBOL]: emitter,
908
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
909
+ engine: { step: this.inngestStep },
910
+ abortSignal: abortController?.signal,
911
+ writer: new ToolStream(
912
+ {
913
+ prefix: "workflow-step",
914
+ callId: stepCallId,
915
+ name: "sleep",
916
+ runId
917
+ },
918
+ writableStream
919
+ )
800
920
  },
801
- writableStream
921
+ {
922
+ paramName: "runCount",
923
+ deprecationMessage: runCountDeprecationMessage,
924
+ logger: this.logger
925
+ }
802
926
  )
803
- });
927
+ );
804
928
  });
929
+ if (date && !(date instanceof Date)) {
930
+ date = new Date(date);
931
+ }
805
932
  const time = !date ? 0 : date.getTime() - Date.now();
806
933
  sleepUntilSpan?.update({
807
934
  attributes: {
@@ -839,50 +966,35 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
839
966
  prevOutput,
840
967
  emitter,
841
968
  abortController,
842
- runtimeContext,
969
+ requestContext,
843
970
  tracingContext,
844
971
  writableStream,
845
972
  disableScorers
846
973
  }) {
847
- const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
974
+ const stepSpan = tracingContext?.currentSpan?.createChildSpan({
848
975
  name: `workflow step: '${step.id}'`,
849
- type: AISpanType.WORKFLOW_STEP,
976
+ type: SpanType.WORKFLOW_STEP,
850
977
  input: prevOutput,
851
978
  attributes: {
852
979
  stepId: step.id
853
- }
980
+ },
981
+ tracingPolicy: this.options?.tracingPolicy
982
+ });
983
+ const { inputData, validationError } = await validateStepInput({
984
+ prevOutput,
985
+ step,
986
+ validateInputs: this.options?.validateInputs ?? false
854
987
  });
855
988
  const startedAt = await this.inngestStep.run(
856
989
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
857
990
  async () => {
858
991
  const startedAt2 = Date.now();
859
992
  await emitter.emit("watch", {
860
- type: "watch",
861
- payload: {
862
- currentStep: {
863
- id: step.id,
864
- status: "running"
865
- },
866
- workflowState: {
867
- status: "running",
868
- steps: {
869
- ...stepResults,
870
- [step.id]: {
871
- status: "running"
872
- }
873
- },
874
- result: null,
875
- error: null
876
- }
877
- },
878
- eventTimestamp: Date.now()
879
- });
880
- await emitter.emit("watch-v2", {
881
993
  type: "workflow-step-start",
882
994
  payload: {
883
995
  id: step.id,
884
996
  status: "running",
885
- payload: prevOutput,
997
+ payload: inputData,
886
998
  startedAt: startedAt2
887
999
  }
888
1000
  });
@@ -893,61 +1005,66 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
893
1005
  const isResume = !!resume?.steps?.length;
894
1006
  let result;
895
1007
  let runId;
896
- if (isResume) {
897
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? randomUUID();
898
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
899
- workflowName: step.id,
900
- runId
901
- });
902
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
903
- function: step.getFunction(),
904
- data: {
905
- inputData: prevOutput,
906
- runId,
907
- resume: {
1008
+ try {
1009
+ if (isResume) {
1010
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
1011
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1012
+ workflowName: step.id,
1013
+ runId
1014
+ });
1015
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1016
+ function: step.getFunction(),
1017
+ data: {
1018
+ inputData,
1019
+ initialState: executionContext.state ?? snapshot?.value ?? {},
908
1020
  runId,
909
- steps: resume.steps.slice(1),
910
- stepResults: snapshot?.context,
911
- resumePayload: resume.resumePayload,
912
- // @ts-ignore
913
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1021
+ resume: {
1022
+ runId,
1023
+ steps: resume.steps.slice(1),
1024
+ stepResults: snapshot?.context,
1025
+ resumePayload: resume.resumePayload,
1026
+ // @ts-ignore
1027
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1028
+ },
1029
+ outputOptions: { includeState: true }
914
1030
  }
915
- }
916
- });
917
- result = invokeResp.result;
918
- runId = invokeResp.runId;
919
- } else {
920
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
921
- function: step.getFunction(),
922
- data: {
923
- inputData: prevOutput
924
- }
925
- });
926
- result = invokeResp.result;
927
- runId = invokeResp.runId;
1031
+ });
1032
+ result = invokeResp.result;
1033
+ runId = invokeResp.runId;
1034
+ executionContext.state = invokeResp.result.state;
1035
+ } else {
1036
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1037
+ function: step.getFunction(),
1038
+ data: {
1039
+ inputData,
1040
+ initialState: executionContext.state ?? {},
1041
+ outputOptions: { includeState: true }
1042
+ }
1043
+ });
1044
+ result = invokeResp.result;
1045
+ runId = invokeResp.runId;
1046
+ executionContext.state = invokeResp.result.state;
1047
+ }
1048
+ } catch (e) {
1049
+ const errorCause = e?.cause;
1050
+ if (errorCause && typeof errorCause === "object") {
1051
+ result = errorCause;
1052
+ runId = errorCause.runId || randomUUID();
1053
+ } else {
1054
+ runId = randomUUID();
1055
+ result = {
1056
+ status: "failed",
1057
+ error: e instanceof Error ? e : new Error(String(e)),
1058
+ steps: {},
1059
+ input: inputData
1060
+ };
1061
+ }
928
1062
  }
929
1063
  const res = await this.inngestStep.run(
930
1064
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
931
1065
  async () => {
932
1066
  if (result.status === "failed") {
933
1067
  await emitter.emit("watch", {
934
- type: "watch",
935
- payload: {
936
- currentStep: {
937
- id: step.id,
938
- status: "failed",
939
- error: result?.error
940
- },
941
- workflowState: {
942
- status: "running",
943
- steps: stepResults,
944
- result: null,
945
- error: null
946
- }
947
- },
948
- eventTimestamp: Date.now()
949
- });
950
- await emitter.emit("watch-v2", {
951
1068
  type: "workflow-step-result",
952
1069
  payload: {
953
1070
  id: step.id,
@@ -963,26 +1080,9 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
963
1080
  return stepRes2?.status === "suspended";
964
1081
  });
965
1082
  for (const [stepName, stepResult] of suspendedSteps) {
966
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1083
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
967
1084
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
968
1085
  await emitter.emit("watch", {
969
- type: "watch",
970
- payload: {
971
- currentStep: {
972
- id: step.id,
973
- status: "suspended",
974
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
975
- },
976
- workflowState: {
977
- status: "running",
978
- steps: stepResults,
979
- result: null,
980
- error: null
981
- }
982
- },
983
- eventTimestamp: Date.now()
984
- });
985
- await emitter.emit("watch-v2", {
986
1086
  type: "workflow-step-suspended",
987
1087
  payload: {
988
1088
  id: step.id,
@@ -993,27 +1093,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
993
1093
  executionContext,
994
1094
  result: {
995
1095
  status: "suspended",
996
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1096
+ payload: stepResult.payload,
1097
+ suspendPayload: {
1098
+ ...stepResult?.suspendPayload,
1099
+ __workflow_meta: { runId, path: suspendPath }
1100
+ }
997
1101
  }
998
1102
  };
999
1103
  }
1000
- await emitter.emit("watch", {
1001
- type: "watch",
1002
- payload: {
1003
- currentStep: {
1004
- id: step.id,
1005
- status: "suspended",
1006
- payload: {}
1007
- },
1008
- workflowState: {
1009
- status: "running",
1010
- steps: stepResults,
1011
- result: null,
1012
- error: null
1013
- }
1014
- },
1015
- eventTimestamp: Date.now()
1016
- });
1017
1104
  return {
1018
1105
  executionContext,
1019
1106
  result: {
@@ -1023,23 +1110,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1023
1110
  };
1024
1111
  }
1025
1112
  await emitter.emit("watch", {
1026
- type: "watch",
1027
- payload: {
1028
- currentStep: {
1029
- id: step.id,
1030
- status: "success",
1031
- output: result?.result
1032
- },
1033
- workflowState: {
1034
- status: "running",
1035
- steps: stepResults,
1036
- result: null,
1037
- error: null
1038
- }
1039
- },
1040
- eventTimestamp: Date.now()
1041
- });
1042
- await emitter.emit("watch-v2", {
1043
1113
  type: "workflow-step-result",
1044
1114
  payload: {
1045
1115
  id: step.id,
@@ -1047,7 +1117,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1047
1117
  output: result?.result
1048
1118
  }
1049
1119
  });
1050
- await emitter.emit("watch-v2", {
1120
+ await emitter.emit("watch", {
1051
1121
  type: "workflow-step-finish",
1052
1122
  payload: {
1053
1123
  id: step.id,
@@ -1058,159 +1128,196 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1058
1128
  }
1059
1129
  );
1060
1130
  Object.assign(executionContext, res.executionContext);
1061
- return res.result;
1131
+ return {
1132
+ ...res.result,
1133
+ startedAt,
1134
+ endedAt: Date.now(),
1135
+ payload: inputData,
1136
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1137
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1138
+ };
1062
1139
  }
1063
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1064
- let execResults;
1065
- let suspended;
1066
- let bailed;
1067
- try {
1068
- const result = await step.execute({
1069
- runId: executionContext.runId,
1070
- mastra: this.mastra,
1071
- runtimeContext,
1072
- writableStream,
1073
- inputData: prevOutput,
1074
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1075
- tracingContext: {
1076
- currentSpan: stepAISpan
1077
- },
1078
- getInitData: () => stepResults?.input,
1079
- getStepResult: (step2) => {
1080
- const result2 = stepResults[step2.id];
1081
- if (result2?.status === "success") {
1082
- return result2.output;
1140
+ const stepCallId = randomUUID();
1141
+ let stepRes;
1142
+ try {
1143
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1144
+ let execResults;
1145
+ let suspended;
1146
+ let bailed;
1147
+ try {
1148
+ if (validationError) {
1149
+ throw validationError;
1150
+ }
1151
+ const result = await step.execute({
1152
+ runId: executionContext.runId,
1153
+ mastra: this.mastra,
1154
+ requestContext,
1155
+ writer: new ToolStream(
1156
+ {
1157
+ prefix: "workflow-step",
1158
+ callId: stepCallId,
1159
+ name: step.id,
1160
+ runId: executionContext.runId
1161
+ },
1162
+ writableStream
1163
+ ),
1164
+ state: executionContext?.state ?? {},
1165
+ setState: (state) => {
1166
+ executionContext.state = state;
1167
+ },
1168
+ inputData,
1169
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1170
+ tracingContext: {
1171
+ currentSpan: stepSpan
1172
+ },
1173
+ getInitData: () => stepResults?.input,
1174
+ getStepResult: getStepResult.bind(this, stepResults),
1175
+ suspend: async (suspendPayload, suspendOptions) => {
1176
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1177
+ if (suspendOptions?.resumeLabel) {
1178
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1179
+ for (const label of resumeLabel) {
1180
+ executionContext.resumeLabels[label] = {
1181
+ stepId: step.id,
1182
+ foreachIndex: executionContext.foreachIndex
1183
+ };
1184
+ }
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
+ [EMITTER_SYMBOL]: emitter,
1198
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1199
+ engine: {
1200
+ step: this.inngestStep
1201
+ },
1202
+ abortSignal: abortController.signal
1203
+ });
1204
+ const endedAt = Date.now();
1205
+ execResults = {
1206
+ status: "success",
1207
+ output: result,
1208
+ startedAt,
1209
+ endedAt,
1210
+ payload: inputData,
1211
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1212
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1213
+ };
1214
+ } catch (e) {
1215
+ const stepFailure = {
1216
+ status: "failed",
1217
+ payload: inputData,
1218
+ error: e instanceof Error ? e.message : String(e),
1219
+ endedAt: Date.now(),
1220
+ startedAt,
1221
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1222
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1223
+ };
1224
+ execResults = stepFailure;
1225
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1226
+ stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1227
+ throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1228
+ cause: execResults
1229
+ });
1230
+ }
1231
+ if (suspended) {
1232
+ execResults = {
1233
+ status: "suspended",
1234
+ suspendPayload: suspended.payload,
1235
+ payload: inputData,
1236
+ suspendedAt: Date.now(),
1237
+ startedAt,
1238
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1239
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1240
+ };
1241
+ } else if (bailed) {
1242
+ execResults = {
1243
+ status: "bailed",
1244
+ output: bailed.payload,
1245
+ payload: inputData,
1246
+ endedAt: Date.now(),
1247
+ startedAt
1248
+ };
1249
+ }
1250
+ if (execResults.status === "suspended") {
1251
+ await emitter.emit("watch", {
1252
+ type: "workflow-step-suspended",
1253
+ payload: {
1254
+ id: step.id,
1255
+ ...execResults
1083
1256
  }
1084
- return null;
1085
- },
1086
- suspend: async (suspendPayload) => {
1087
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1088
- suspended = { payload: suspendPayload };
1089
- },
1090
- bail: (result2) => {
1091
- bailed = { payload: result2 };
1092
- },
1093
- resume: {
1094
- steps: resume?.steps?.slice(1) || [],
1095
- resumePayload: resume?.resumePayload,
1096
- // @ts-ignore
1097
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1098
- },
1099
- [EMITTER_SYMBOL]: emitter,
1100
- engine: {
1101
- step: this.inngestStep
1102
- },
1103
- abortSignal: abortController.signal
1104
- });
1105
- const endedAt = Date.now();
1106
- execResults = {
1107
- status: "success",
1108
- output: result,
1109
- startedAt,
1110
- endedAt,
1111
- payload: prevOutput,
1112
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1113
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1114
- };
1115
- } catch (e) {
1116
- execResults = {
1117
- status: "failed",
1118
- payload: prevOutput,
1119
- error: e instanceof Error ? e.message : String(e),
1120
- endedAt: Date.now(),
1121
- startedAt,
1122
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1123
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1124
- };
1125
- }
1126
- if (suspended) {
1127
- execResults = {
1128
- status: "suspended",
1129
- suspendedPayload: suspended.payload,
1130
- payload: prevOutput,
1131
- suspendedAt: Date.now(),
1132
- startedAt,
1133
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1134
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1135
- };
1136
- } else if (bailed) {
1137
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1138
- }
1139
- if (execResults.status === "failed") {
1140
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1141
- const error = new Error(execResults.error);
1142
- stepAISpan?.error({ error });
1143
- throw error;
1257
+ });
1258
+ } else {
1259
+ await emitter.emit("watch", {
1260
+ type: "workflow-step-result",
1261
+ payload: {
1262
+ id: step.id,
1263
+ ...execResults
1264
+ }
1265
+ });
1266
+ await emitter.emit("watch", {
1267
+ type: "workflow-step-finish",
1268
+ payload: {
1269
+ id: step.id,
1270
+ metadata: {}
1271
+ }
1272
+ });
1144
1273
  }
1145
- }
1146
- await emitter.emit("watch", {
1147
- type: "watch",
1148
- payload: {
1149
- currentStep: {
1150
- id: step.id,
1151
- ...execResults
1152
- },
1153
- workflowState: {
1154
- status: "running",
1155
- steps: { ...stepResults, [step.id]: execResults },
1156
- result: null,
1157
- error: null
1158
- }
1159
- },
1160
- eventTimestamp: Date.now()
1274
+ stepSpan?.end({ output: execResults });
1275
+ return { result: execResults, executionContext, stepResults };
1161
1276
  });
1162
- if (execResults.status === "suspended") {
1163
- await emitter.emit("watch-v2", {
1164
- type: "workflow-step-suspended",
1165
- payload: {
1166
- id: step.id,
1167
- ...execResults
1168
- }
1169
- });
1170
- } else {
1171
- await emitter.emit("watch-v2", {
1172
- type: "workflow-step-result",
1173
- payload: {
1174
- id: step.id,
1175
- ...execResults
1176
- }
1177
- });
1178
- await emitter.emit("watch-v2", {
1179
- type: "workflow-step-finish",
1180
- payload: {
1181
- id: step.id,
1182
- metadata: {}
1183
- }
1184
- });
1185
- }
1186
- stepAISpan?.end({ output: execResults });
1187
- return { result: execResults, executionContext, stepResults };
1188
- });
1189
- if (disableScorers !== false) {
1277
+ } catch (e) {
1278
+ const stepFailure = e instanceof Error ? e?.cause : {
1279
+ status: "failed",
1280
+ error: e instanceof Error ? e.message : String(e),
1281
+ payload: inputData,
1282
+ startedAt,
1283
+ endedAt: Date.now()
1284
+ };
1285
+ stepRes = {
1286
+ result: stepFailure,
1287
+ executionContext,
1288
+ stepResults: {
1289
+ ...stepResults,
1290
+ [step.id]: stepFailure
1291
+ }
1292
+ };
1293
+ }
1294
+ if (disableScorers !== false && stepRes.result.status === "success") {
1190
1295
  await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1191
1296
  if (step.scorers) {
1192
1297
  await this.runScorers({
1193
1298
  scorers: step.scorers,
1194
1299
  runId: executionContext.runId,
1195
- input: prevOutput,
1300
+ input: inputData,
1196
1301
  output: stepRes.result,
1197
1302
  workflowId: executionContext.workflowId,
1198
1303
  stepId: step.id,
1199
- runtimeContext,
1304
+ requestContext,
1200
1305
  disableScorers,
1201
- tracingContext: { currentSpan: stepAISpan }
1306
+ tracingContext: { currentSpan: stepSpan }
1202
1307
  });
1203
1308
  }
1204
1309
  });
1205
1310
  }
1206
1311
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1207
1312
  Object.assign(stepResults, stepRes.stepResults);
1313
+ executionContext.state = stepRes.executionContext.state;
1208
1314
  return stepRes.result;
1209
1315
  }
1210
1316
  async persistStepUpdate({
1211
1317
  workflowId,
1212
1318
  runId,
1213
1319
  stepResults,
1320
+ resourceId,
1214
1321
  executionContext,
1215
1322
  serializedStepGraph,
1216
1323
  workflowStatus,
@@ -1220,15 +1327,21 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1220
1327
  await this.inngestStep.run(
1221
1328
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1222
1329
  async () => {
1330
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1331
+ if (!shouldPersistSnapshot) {
1332
+ return;
1333
+ }
1223
1334
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1224
1335
  workflowName: workflowId,
1225
1336
  runId,
1337
+ resourceId,
1226
1338
  snapshot: {
1227
1339
  runId,
1228
- value: {},
1340
+ value: executionContext.state,
1229
1341
  context: stepResults,
1230
1342
  activePaths: [],
1231
1343
  suspendedPaths: executionContext.suspendedPaths,
1344
+ resumeLabels: executionContext.resumeLabels,
1232
1345
  waitingPaths: {},
1233
1346
  serializedStepGraph,
1234
1347
  status: workflowStatus,
@@ -1246,85 +1359,88 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1246
1359
  runId,
1247
1360
  entry,
1248
1361
  prevOutput,
1249
- prevStep,
1250
1362
  stepResults,
1251
- serializedStepGraph,
1252
1363
  resume,
1253
1364
  executionContext,
1254
1365
  emitter,
1255
1366
  abortController,
1256
- runtimeContext,
1367
+ requestContext,
1257
1368
  writableStream,
1258
1369
  disableScorers,
1259
1370
  tracingContext
1260
1371
  }) {
1261
1372
  const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1262
- type: AISpanType.WORKFLOW_CONDITIONAL,
1373
+ type: SpanType.WORKFLOW_CONDITIONAL,
1263
1374
  name: `conditional: '${entry.conditions.length} conditions'`,
1264
1375
  input: prevOutput,
1265
1376
  attributes: {
1266
1377
  conditionCount: entry.conditions.length
1267
- }
1378
+ },
1379
+ tracingPolicy: this.options?.tracingPolicy
1268
1380
  });
1269
1381
  let execResults;
1270
1382
  const truthyIndexes = (await Promise.all(
1271
1383
  entry.conditions.map(
1272
1384
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1273
1385
  const evalSpan = conditionalSpan?.createChildSpan({
1274
- type: AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1386
+ type: SpanType.WORKFLOW_CONDITIONAL_EVAL,
1275
1387
  name: `condition: '${index}'`,
1276
1388
  input: prevOutput,
1277
1389
  attributes: {
1278
1390
  conditionIndex: index
1279
- }
1391
+ },
1392
+ tracingPolicy: this.options?.tracingPolicy
1280
1393
  });
1281
1394
  try {
1282
- const result = await cond({
1283
- runId,
1284
- workflowId,
1285
- mastra: this.mastra,
1286
- runtimeContext,
1287
- runCount: -1,
1288
- inputData: prevOutput,
1289
- tracingContext: {
1290
- currentSpan: evalSpan
1291
- },
1292
- getInitData: () => stepResults?.input,
1293
- getStepResult: (step) => {
1294
- if (!step?.id) {
1295
- return null;
1296
- }
1297
- const result2 = stepResults[step.id];
1298
- if (result2?.status === "success") {
1299
- return result2.output;
1300
- }
1301
- return null;
1302
- },
1303
- // TODO: this function shouldn't have suspend probably?
1304
- suspend: async (_suspendPayload) => {
1305
- },
1306
- bail: () => {
1307
- },
1308
- abort: () => {
1309
- abortController.abort();
1310
- },
1311
- [EMITTER_SYMBOL]: emitter,
1312
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
1313
- // TODO: add streamVNext support
1314
- engine: {
1315
- step: this.inngestStep
1316
- },
1317
- abortSignal: abortController.signal,
1318
- writer: new ToolStream(
1395
+ const result = await cond(
1396
+ createDeprecationProxy(
1319
1397
  {
1320
- prefix: "workflow-step",
1321
- callId: randomUUID(),
1322
- name: "conditional",
1323
- runId
1398
+ runId,
1399
+ workflowId,
1400
+ mastra: this.mastra,
1401
+ requestContext,
1402
+ retryCount: -1,
1403
+ inputData: prevOutput,
1404
+ state: executionContext.state,
1405
+ setState: (state) => {
1406
+ executionContext.state = state;
1407
+ },
1408
+ tracingContext: {
1409
+ currentSpan: evalSpan
1410
+ },
1411
+ getInitData: () => stepResults?.input,
1412
+ getStepResult: getStepResult.bind(this, stepResults),
1413
+ // TODO: this function shouldn't have suspend probably?
1414
+ suspend: async (_suspendPayload) => {
1415
+ },
1416
+ bail: () => {
1417
+ },
1418
+ abort: () => {
1419
+ abortController.abort();
1420
+ },
1421
+ [EMITTER_SYMBOL]: emitter,
1422
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1423
+ engine: {
1424
+ step: this.inngestStep
1425
+ },
1426
+ abortSignal: abortController.signal,
1427
+ writer: new ToolStream(
1428
+ {
1429
+ prefix: "workflow-step",
1430
+ callId: randomUUID(),
1431
+ name: "conditional",
1432
+ runId
1433
+ },
1434
+ writableStream
1435
+ )
1324
1436
  },
1325
- writableStream
1437
+ {
1438
+ paramName: "runCount",
1439
+ deprecationMessage: runCountDeprecationMessage,
1440
+ logger: this.logger
1441
+ }
1326
1442
  )
1327
- });
1443
+ );
1328
1444
  evalSpan?.end({
1329
1445
  output: result,
1330
1446
  attributes: {
@@ -1352,13 +1468,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1352
1468
  }
1353
1469
  });
1354
1470
  const results = await Promise.all(
1355
- stepsToRun.map(
1356
- (step, index) => this.executeEntry({
1357
- workflowId,
1358
- runId,
1359
- entry: step,
1360
- serializedStepGraph,
1361
- prevStep,
1471
+ stepsToRun.map(async (step, index) => {
1472
+ const currStepResult = stepResults[step.step.id];
1473
+ if (currStepResult && currStepResult.status === "success") {
1474
+ return currStepResult;
1475
+ }
1476
+ const result = await this.executeStep({
1477
+ step: step.step,
1478
+ prevOutput,
1362
1479
  stepResults,
1363
1480
  resume,
1364
1481
  executionContext: {
@@ -1366,31 +1483,34 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1366
1483
  runId,
1367
1484
  executionPath: [...executionContext.executionPath, index],
1368
1485
  suspendedPaths: executionContext.suspendedPaths,
1486
+ resumeLabels: executionContext.resumeLabels,
1369
1487
  retryConfig: executionContext.retryConfig,
1370
- executionSpan: executionContext.executionSpan
1488
+ state: executionContext.state
1371
1489
  },
1372
1490
  emitter,
1373
1491
  abortController,
1374
- runtimeContext,
1492
+ requestContext,
1375
1493
  writableStream,
1376
1494
  disableScorers,
1377
1495
  tracingContext: {
1378
1496
  currentSpan: conditionalSpan
1379
1497
  }
1380
- })
1381
- )
1498
+ });
1499
+ stepResults[step.step.id] = result;
1500
+ return result;
1501
+ })
1382
1502
  );
1383
- const hasFailed = results.find((result) => result.result.status === "failed");
1384
- const hasSuspended = results.find((result) => result.result.status === "suspended");
1503
+ const hasFailed = results.find((result) => result.status === "failed");
1504
+ const hasSuspended = results.find((result) => result.status === "suspended");
1385
1505
  if (hasFailed) {
1386
- execResults = { status: "failed", error: hasFailed.result.error };
1506
+ execResults = { status: "failed", error: hasFailed.error };
1387
1507
  } else if (hasSuspended) {
1388
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1508
+ execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
1389
1509
  } else {
1390
1510
  execResults = {
1391
1511
  status: "success",
1392
1512
  output: results.reduce((acc, result, index) => {
1393
- if (result.result.status === "success") {
1513
+ if (result.status === "success") {
1394
1514
  acc[stepsToRun[index].step.id] = result.output;
1395
1515
  }
1396
1516
  return acc;