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