@mastra/inngest 0.0.0-message-list-update-20250715150321 → 0.0.0-model-router-unknown-provider-20251017212006

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2,17 +2,24 @@
2
2
 
3
3
  var crypto = require('crypto');
4
4
  var realtime = require('@inngest/realtime');
5
+ var aiTracing = require('@mastra/core/ai-tracing');
5
6
  var di = require('@mastra/core/di');
6
7
  var tools = require('@mastra/core/tools');
7
8
  var workflows = require('@mastra/core/workflows');
8
9
  var _constants = require('@mastra/core/workflows/_constants');
10
+ var inngest = require('inngest');
9
11
  var hono = require('inngest/hono');
10
12
  var zod = require('zod');
11
13
 
12
14
  // src/index.ts
13
- function serve({ mastra, inngest }) {
15
+ function serve({
16
+ mastra,
17
+ inngest,
18
+ functions: userFunctions = [],
19
+ registerOptions
20
+ }) {
14
21
  const wfs = mastra.getWorkflows();
15
- const functions = Array.from(
22
+ const workflowFunctions = Array.from(
16
23
  new Set(
17
24
  Object.values(wfs).flatMap((wf) => {
18
25
  if (wf instanceof InngestWorkflow) {
@@ -24,8 +31,9 @@ function serve({ mastra, inngest }) {
24
31
  )
25
32
  );
26
33
  return hono.serve({
34
+ ...registerOptions,
27
35
  client: inngest,
28
- functions
36
+ functions: [...workflowFunctions, ...userFunctions]
29
37
  });
30
38
  }
31
39
  var InngestRun = class extends workflows.Run {
@@ -53,9 +61,15 @@ var InngestRun = class extends workflows.Run {
53
61
  await new Promise((resolve) => setTimeout(resolve, 1e3));
54
62
  runs = await this.getRuns(eventId);
55
63
  if (runs?.[0]?.status === "Failed") {
56
- console.log("run", runs?.[0]);
57
- throw new Error(`Function run ${runs?.[0]?.status}`);
58
- } else if (runs?.[0]?.status === "Cancelled") {
64
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
65
+ workflowName: this.workflowId,
66
+ runId: this.runId
67
+ });
68
+ return {
69
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
70
+ };
71
+ }
72
+ if (runs?.[0]?.status === "Cancelled") {
59
73
  const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
60
74
  workflowName: this.workflowId,
61
75
  runId: this.runId
@@ -86,6 +100,7 @@ var InngestRun = class extends workflows.Run {
86
100
  await this.#mastra?.storage?.persistWorkflowSnapshot({
87
101
  workflowName: this.workflowId,
88
102
  runId: this.runId,
103
+ resourceId: this.resourceId,
89
104
  snapshot: {
90
105
  ...snapshot,
91
106
  status: "canceled"
@@ -94,11 +109,13 @@ var InngestRun = class extends workflows.Run {
94
109
  }
95
110
  }
96
111
  async start({
97
- inputData
112
+ inputData,
113
+ initialState
98
114
  }) {
99
115
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
100
116
  workflowName: this.workflowId,
101
117
  runId: this.runId,
118
+ resourceId: this.resourceId,
102
119
  snapshot: {
103
120
  runId: this.runId,
104
121
  serializedStepGraph: this.serializedStepGraph,
@@ -106,15 +123,21 @@ var InngestRun = class extends workflows.Run {
106
123
  context: {},
107
124
  activePaths: [],
108
125
  suspendedPaths: {},
126
+ resumeLabels: {},
127
+ waitingPaths: {},
109
128
  timestamp: Date.now(),
110
129
  status: "running"
111
130
  }
112
131
  });
132
+ const inputDataToUse = await this._validateInput(inputData);
133
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
113
134
  const eventOutput = await this.inngest.send({
114
135
  name: `workflow.${this.workflowId}`,
115
136
  data: {
116
- inputData,
117
- runId: this.runId
137
+ inputData: inputDataToUse,
138
+ initialState: initialStateToUse,
139
+ runId: this.runId,
140
+ resourceId: this.resourceId
118
141
  }
119
142
  });
120
143
  const eventId = eventOutput.ids[0];
@@ -150,16 +173,20 @@ var InngestRun = class extends workflows.Run {
150
173
  workflowName: this.workflowId,
151
174
  runId: this.runId
152
175
  });
176
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
177
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
153
178
  const eventOutput = await this.inngest.send({
154
179
  name: `workflow.${this.workflowId}`,
155
180
  data: {
156
- inputData: params.resumeData,
181
+ inputData: resumeDataToUse,
182
+ initialState: snapshot?.value ?? {},
157
183
  runId: this.runId,
184
+ workflowId: this.workflowId,
158
185
  stepResults: snapshot?.context,
159
186
  resume: {
160
187
  steps,
161
188
  stepResults: snapshot?.context,
162
- resumePayload: params.resumeData,
189
+ resumePayload: resumeDataToUse,
163
190
  // @ts-ignore
164
191
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
165
192
  }
@@ -204,7 +231,11 @@ var InngestRun = class extends workflows.Run {
204
231
  const writer = writable.getWriter();
205
232
  const unwatch = this.watch(async (event) => {
206
233
  try {
207
- await writer.write(event);
234
+ const e = {
235
+ ...event,
236
+ type: event.type.replace("workflow-", "")
237
+ };
238
+ await writer.write(e);
208
239
  } catch {
209
240
  }
210
241
  }, "watch-v2");
@@ -235,8 +266,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
235
266
  #mastra;
236
267
  inngest;
237
268
  function;
269
+ flowControlConfig;
238
270
  constructor(params, inngest) {
239
- super(params);
271
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
272
+ super(workflowParams);
273
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
274
+ ([_, value]) => value !== void 0
275
+ );
276
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
240
277
  this.#mastra = params.mastra;
241
278
  this.inngest = inngest;
242
279
  }
@@ -257,27 +294,6 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
257
294
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
258
295
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
259
296
  }
260
- async getWorkflowRunExecutionResult(runId) {
261
- const storage = this.#mastra?.getStorage();
262
- if (!storage) {
263
- this.logger.debug("Cannot get workflow run execution result. Mastra storage is not initialized");
264
- return null;
265
- }
266
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
267
- if (!run?.snapshot) {
268
- return null;
269
- }
270
- if (typeof run.snapshot === "string") {
271
- return null;
272
- }
273
- return {
274
- status: run.snapshot.status,
275
- result: run.snapshot.result,
276
- error: run.snapshot.error,
277
- payload: run.snapshot.context?.input,
278
- steps: run.snapshot.context
279
- };
280
- }
281
297
  __registerMastra(mastra) {
282
298
  this.#mastra = mastra;
283
299
  this.executionEngine.__registerMastra(mastra);
@@ -296,23 +312,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
296
312
  }
297
313
  }
298
314
  }
299
- createRun(options) {
300
- const runIdToUse = options?.runId || crypto.randomUUID();
301
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
302
- {
303
- workflowId: this.id,
304
- runId: runIdToUse,
305
- executionEngine: this.executionEngine,
306
- executionGraph: this.executionGraph,
307
- serializedStepGraph: this.serializedStepGraph,
308
- mastra: this.#mastra,
309
- retryConfig: this.retryConfig,
310
- cleanup: () => this.runs.delete(runIdToUse)
311
- },
312
- this.inngest
315
+ /**
316
+ * @deprecated Use createRunAsync() instead.
317
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
318
+ */
319
+ createRun(_options) {
320
+ throw new Error(
321
+ "createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
313
322
  );
314
- this.runs.set(runIdToUse, run);
315
- return run;
316
323
  }
317
324
  async createRunAsync(options) {
318
325
  const runIdToUse = options?.runId || crypto.randomUUID();
@@ -320,29 +327,38 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
320
327
  {
321
328
  workflowId: this.id,
322
329
  runId: runIdToUse,
330
+ resourceId: options?.resourceId,
323
331
  executionEngine: this.executionEngine,
324
332
  executionGraph: this.executionGraph,
325
333
  serializedStepGraph: this.serializedStepGraph,
326
334
  mastra: this.#mastra,
327
335
  retryConfig: this.retryConfig,
328
- cleanup: () => this.runs.delete(runIdToUse)
336
+ cleanup: () => this.runs.delete(runIdToUse),
337
+ workflowSteps: this.steps
329
338
  },
330
339
  this.inngest
331
340
  );
332
341
  this.runs.set(runIdToUse, run);
333
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
334
- if (!workflowSnapshotInStorage) {
342
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
343
+ workflowStatus: run.workflowRunStatus,
344
+ stepResults: {}
345
+ });
346
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
347
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
335
348
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
336
349
  workflowName: this.id,
337
350
  runId: runIdToUse,
351
+ resourceId: options?.resourceId,
338
352
  snapshot: {
339
353
  runId: runIdToUse,
340
354
  status: "pending",
341
355
  value: {},
342
356
  context: {},
343
357
  activePaths: [],
358
+ waitingPaths: {},
344
359
  serializedStepGraph: this.serializedStepGraph,
345
360
  suspendedPaths: {},
361
+ resumeLabels: {},
346
362
  result: void 0,
347
363
  error: void 0,
348
364
  // @ts-ignore
@@ -361,11 +377,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
361
377
  id: `workflow.${this.id}`,
362
378
  // @ts-ignore
363
379
  retries: this.retryConfig?.attempts ?? 0,
364
- cancelOn: [{ event: `cancel.workflow.${this.id}` }]
380
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
381
+ // Spread flow control configuration
382
+ ...this.flowControlConfig
365
383
  },
366
384
  { event: `workflow.${this.id}` },
367
385
  async ({ event, step, attempt, publish }) => {
368
- let { inputData, runId, resume } = event.data;
386
+ let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
369
387
  if (!runId) {
370
388
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
371
389
  return crypto.randomUUID();
@@ -393,19 +411,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
393
411
  once: (_event, _callback) => {
394
412
  }
395
413
  };
396
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
414
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
397
415
  const result = await engine.execute({
398
416
  workflowId: this.id,
399
417
  runId,
418
+ resourceId,
400
419
  graph: this.executionGraph,
401
420
  serializedStepGraph: this.serializedStepGraph,
402
421
  input: inputData,
422
+ initialState,
403
423
  emitter,
404
424
  retryConfig: this.retryConfig,
405
425
  runtimeContext: new di.RuntimeContext(),
406
426
  // TODO
407
427
  resume,
408
- abortController: new AbortController()
428
+ abortController: new AbortController(),
429
+ currentSpan: void 0,
430
+ // TODO: Pass actual parent AI span from workflow execution context
431
+ outputOptions
432
+ });
433
+ await step.run(`workflow.${this.id}.finalize`, async () => {
434
+ if (result.status === "failed") {
435
+ throw new inngest.NonRetriableError(`Workflow failed`, {
436
+ cause: result
437
+ });
438
+ }
439
+ return result;
409
440
  });
410
441
  return { result, runId };
411
442
  }
@@ -439,17 +470,16 @@ function createStep(params) {
439
470
  if (isAgent(params)) {
440
471
  return {
441
472
  id: params.name,
473
+ description: params.getDescription(),
442
474
  // @ts-ignore
443
475
  inputSchema: zod.z.object({
444
476
  prompt: zod.z.string()
445
- // resourceId: z.string().optional(),
446
- // threadId: z.string().optional(),
447
477
  }),
448
478
  // @ts-ignore
449
479
  outputSchema: zod.z.object({
450
480
  text: zod.z.string()
451
481
  }),
452
- execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
482
+ execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
453
483
  let streamPromise = {};
454
484
  streamPromise.promise = new Promise((resolve, reject) => {
455
485
  streamPromise.resolve = resolve;
@@ -459,50 +489,66 @@ function createStep(params) {
459
489
  name: params.name,
460
490
  args: inputData
461
491
  };
462
- await emitter.emit("watch-v2", {
463
- type: "tool-call-streaming-start",
464
- ...toolData
465
- });
466
- const { fullStream } = await params.stream(inputData.prompt, {
467
- // resourceId: inputData.resourceId,
468
- // threadId: inputData.threadId,
469
- runtimeContext,
470
- onFinish: (result) => {
471
- streamPromise.resolve(result.text);
472
- },
473
- abortSignal
474
- });
475
- if (abortSignal.aborted) {
476
- return abort();
477
- }
478
- for await (const chunk of fullStream) {
479
- switch (chunk.type) {
480
- case "text-delta":
492
+ if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
493
+ const { fullStream } = await params.stream(inputData.prompt, {
494
+ runtimeContext,
495
+ tracingContext,
496
+ onFinish: (result) => {
497
+ streamPromise.resolve(result.text);
498
+ },
499
+ abortSignal
500
+ });
501
+ if (abortSignal.aborted) {
502
+ return abort();
503
+ }
504
+ await emitter.emit("watch-v2", {
505
+ type: "tool-call-streaming-start",
506
+ ...toolData ?? {}
507
+ });
508
+ for await (const chunk of fullStream) {
509
+ if (chunk.type === "text-delta") {
510
+ await emitter.emit("watch-v2", {
511
+ type: "tool-call-delta",
512
+ ...toolData ?? {},
513
+ argsTextDelta: chunk.payload.text
514
+ });
515
+ }
516
+ }
517
+ } else {
518
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
519
+ runtimeContext,
520
+ tracingContext,
521
+ onFinish: (result) => {
522
+ streamPromise.resolve(result.text);
523
+ },
524
+ abortSignal
525
+ });
526
+ if (abortSignal.aborted) {
527
+ return abort();
528
+ }
529
+ await emitter.emit("watch-v2", {
530
+ type: "tool-call-streaming-start",
531
+ ...toolData ?? {}
532
+ });
533
+ for await (const chunk of fullStream) {
534
+ if (chunk.type === "text-delta") {
481
535
  await emitter.emit("watch-v2", {
482
536
  type: "tool-call-delta",
483
- ...toolData,
537
+ ...toolData ?? {},
484
538
  argsTextDelta: chunk.textDelta
485
539
  });
486
- break;
487
- case "step-start":
488
- case "step-finish":
489
- case "finish":
490
- break;
491
- case "tool-call":
492
- case "tool-result":
493
- case "tool-call-streaming-start":
494
- case "tool-call-delta":
495
- case "source":
496
- case "file":
497
- default:
498
- await emitter.emit("watch-v2", chunk);
499
- break;
540
+ }
500
541
  }
501
542
  }
543
+ await emitter.emit("watch-v2", {
544
+ type: "tool-call-streaming-finish",
545
+ ...toolData ?? {}
546
+ });
502
547
  return {
503
548
  text: await streamPromise.promise
504
549
  };
505
- }
550
+ },
551
+ component: params.component
506
552
  };
507
553
  }
508
554
  if (isTool(params)) {
@@ -513,15 +559,20 @@ function createStep(params) {
513
559
  // TODO: tool probably should have strong id type
514
560
  // @ts-ignore
515
561
  id: params.id,
562
+ description: params.description,
516
563
  inputSchema: params.inputSchema,
517
564
  outputSchema: params.outputSchema,
518
- execute: async ({ inputData, mastra, runtimeContext }) => {
565
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
519
566
  return params.execute({
520
567
  context: inputData,
521
- mastra,
522
- runtimeContext
568
+ mastra: aiTracing.wrapMastra(mastra, tracingContext),
569
+ runtimeContext,
570
+ tracingContext,
571
+ suspend,
572
+ resumeData
523
573
  });
524
- }
574
+ },
575
+ component: "TOOL"
525
576
  };
526
577
  }
527
578
  return {
@@ -537,7 +588,10 @@ function createStep(params) {
537
588
  function init(inngest) {
538
589
  return {
539
590
  createWorkflow(params) {
540
- return new InngestWorkflow(params, inngest);
591
+ return new InngestWorkflow(
592
+ params,
593
+ inngest
594
+ );
541
595
  },
542
596
  createStep,
543
597
  cloneStep(step, opts) {
@@ -546,7 +600,11 @@ function init(inngest) {
546
600
  description: step.description,
547
601
  inputSchema: step.inputSchema,
548
602
  outputSchema: step.outputSchema,
549
- execute: step.execute
603
+ resumeSchema: step.resumeSchema,
604
+ suspendSchema: step.suspendSchema,
605
+ stateSchema: step.stateSchema,
606
+ execute: step.execute,
607
+ component: step.component
550
608
  };
551
609
  },
552
610
  cloneWorkflow(workflow, opts) {
@@ -566,19 +624,19 @@ function init(inngest) {
566
624
  var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
567
625
  inngestStep;
568
626
  inngestAttempts;
569
- constructor(mastra, inngestStep, inngestAttempts = 0) {
570
- super({ mastra });
627
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
628
+ super({ mastra, options });
571
629
  this.inngestStep = inngestStep;
572
630
  this.inngestAttempts = inngestAttempts;
573
631
  }
574
632
  async execute(params) {
575
633
  await params.emitter.emit("watch-v2", {
576
- type: "start",
634
+ type: "workflow-start",
577
635
  payload: { runId: params.runId }
578
636
  });
579
637
  const result = await super.execute(params);
580
638
  await params.emitter.emit("watch-v2", {
581
- type: "finish",
639
+ type: "workflow-finish",
582
640
  payload: { runId: params.runId }
583
641
  });
584
642
  return result;
@@ -630,7 +688,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
630
688
  });
631
689
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
632
690
  if (stepResult?.status === "suspended") {
633
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
691
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
634
692
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
635
693
  }
636
694
  return [];
@@ -640,31 +698,6 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
640
698
  executionSpan?.end();
641
699
  return base;
642
700
  }
643
- async superExecuteStep({
644
- workflowId,
645
- runId,
646
- step,
647
- stepResults,
648
- executionContext,
649
- resume,
650
- prevOutput,
651
- emitter,
652
- abortController,
653
- runtimeContext
654
- }) {
655
- return super.executeStep({
656
- workflowId,
657
- runId,
658
- step,
659
- stepResults,
660
- executionContext,
661
- resume,
662
- prevOutput,
663
- emitter,
664
- abortController,
665
- runtimeContext
666
- });
667
- }
668
701
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
669
702
  // await this.inngestStep.sleep(id, duration);
670
703
  // }
@@ -676,28 +709,40 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
676
709
  stepResults,
677
710
  emitter,
678
711
  abortController,
679
- runtimeContext
712
+ runtimeContext,
713
+ executionContext,
714
+ writableStream,
715
+ tracingContext
680
716
  }) {
681
717
  let { duration, fn } = entry;
718
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
719
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
720
+ name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
721
+ attributes: {
722
+ durationMs: duration,
723
+ sleepType: fn ? "dynamic" : "fixed"
724
+ },
725
+ tracingPolicy: this.options?.tracingPolicy
726
+ });
682
727
  if (fn) {
728
+ const stepCallId = crypto.randomUUID();
683
729
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
684
730
  return await fn({
685
731
  runId,
732
+ workflowId,
686
733
  mastra: this.mastra,
687
734
  runtimeContext,
688
735
  inputData: prevOutput,
736
+ state: executionContext.state,
737
+ setState: (state) => {
738
+ executionContext.state = state;
739
+ },
689
740
  runCount: -1,
690
- getInitData: () => stepResults?.input,
691
- getStepResult: (step) => {
692
- if (!step?.id) {
693
- return null;
694
- }
695
- const result = stepResults[step.id];
696
- if (result?.status === "success") {
697
- return result.output;
698
- }
699
- return null;
741
+ tracingContext: {
742
+ currentSpan: sleepSpan
700
743
  },
744
+ getInitData: () => stepResults?.input,
745
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
701
746
  // TODO: this function shouldn't have suspend probably?
702
747
  suspend: async (_suspendPayload) => {
703
748
  },
@@ -707,12 +752,34 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
707
752
  abortController?.abort();
708
753
  },
709
754
  [_constants.EMITTER_SYMBOL]: emitter,
755
+ // TODO: add streamVNext support
756
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
710
757
  engine: { step: this.inngestStep },
711
- abortSignal: abortController?.signal
758
+ abortSignal: abortController?.signal,
759
+ writer: new tools.ToolStream(
760
+ {
761
+ prefix: "workflow-step",
762
+ callId: stepCallId,
763
+ name: "sleep",
764
+ runId
765
+ },
766
+ writableStream
767
+ )
712
768
  });
713
769
  });
770
+ sleepSpan?.update({
771
+ attributes: {
772
+ durationMs: duration
773
+ }
774
+ });
775
+ }
776
+ try {
777
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
778
+ sleepSpan?.end();
779
+ } catch (e) {
780
+ sleepSpan?.error({ error: e });
781
+ throw e;
714
782
  }
715
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
716
783
  }
717
784
  async executeSleepUntil({
718
785
  workflowId,
@@ -722,28 +789,41 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
722
789
  stepResults,
723
790
  emitter,
724
791
  abortController,
725
- runtimeContext
792
+ runtimeContext,
793
+ executionContext,
794
+ writableStream,
795
+ tracingContext
726
796
  }) {
727
797
  let { date, fn } = entry;
798
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
799
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
800
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
801
+ attributes: {
802
+ untilDate: date,
803
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
804
+ sleepType: fn ? "dynamic" : "fixed"
805
+ },
806
+ tracingPolicy: this.options?.tracingPolicy
807
+ });
728
808
  if (fn) {
729
809
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
810
+ const stepCallId = crypto.randomUUID();
730
811
  return await fn({
731
812
  runId,
813
+ workflowId,
732
814
  mastra: this.mastra,
733
815
  runtimeContext,
734
816
  inputData: prevOutput,
817
+ state: executionContext.state,
818
+ setState: (state) => {
819
+ executionContext.state = state;
820
+ },
735
821
  runCount: -1,
736
- getInitData: () => stepResults?.input,
737
- getStepResult: (step) => {
738
- if (!step?.id) {
739
- return null;
740
- }
741
- const result = stepResults[step.id];
742
- if (result?.status === "success") {
743
- return result.output;
744
- }
745
- return null;
822
+ tracingContext: {
823
+ currentSpan: sleepUntilSpan
746
824
  },
825
+ getInitData: () => stepResults?.input,
826
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
747
827
  // TODO: this function shouldn't have suspend probably?
748
828
  suspend: async (_suspendPayload) => {
749
829
  },
@@ -753,15 +833,42 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
753
833
  abortController?.abort();
754
834
  },
755
835
  [_constants.EMITTER_SYMBOL]: emitter,
836
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
837
+ // TODO: add streamVNext support
756
838
  engine: { step: this.inngestStep },
757
- abortSignal: abortController?.signal
839
+ abortSignal: abortController?.signal,
840
+ writer: new tools.ToolStream(
841
+ {
842
+ prefix: "workflow-step",
843
+ callId: stepCallId,
844
+ name: "sleep",
845
+ runId
846
+ },
847
+ writableStream
848
+ )
758
849
  });
759
850
  });
851
+ if (date && !(date instanceof Date)) {
852
+ date = new Date(date);
853
+ }
854
+ const time = !date ? 0 : date.getTime() - Date.now();
855
+ sleepUntilSpan?.update({
856
+ attributes: {
857
+ durationMs: Math.max(0, time)
858
+ }
859
+ });
760
860
  }
761
861
  if (!(date instanceof Date)) {
862
+ sleepUntilSpan?.end();
762
863
  return;
763
864
  }
764
- await this.inngestStep.sleepUntil(entry.id, date);
865
+ try {
866
+ await this.inngestStep.sleepUntil(entry.id, date);
867
+ sleepUntilSpan?.end();
868
+ } catch (e) {
869
+ sleepUntilSpan?.error({ error: e });
870
+ throw e;
871
+ }
765
872
  }
766
873
  async executeWaitForEvent({ event, timeout }) {
767
874
  const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
@@ -781,8 +888,25 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
781
888
  prevOutput,
782
889
  emitter,
783
890
  abortController,
784
- runtimeContext
891
+ runtimeContext,
892
+ tracingContext,
893
+ writableStream,
894
+ disableScorers
785
895
  }) {
896
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
897
+ name: `workflow step: '${step.id}'`,
898
+ type: aiTracing.AISpanType.WORKFLOW_STEP,
899
+ input: prevOutput,
900
+ attributes: {
901
+ stepId: step.id
902
+ },
903
+ tracingPolicy: this.options?.tracingPolicy
904
+ });
905
+ const { inputData, validationError } = await workflows.validateStepInput({
906
+ prevOutput,
907
+ step,
908
+ validateInputs: this.options?.validateInputs ?? false
909
+ });
786
910
  const startedAt = await this.inngestStep.run(
787
911
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
788
912
  async () => {
@@ -809,11 +933,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
809
933
  eventTimestamp: Date.now()
810
934
  });
811
935
  await emitter.emit("watch-v2", {
812
- type: "step-start",
936
+ type: "workflow-step-start",
813
937
  payload: {
814
938
  id: step.id,
815
939
  status: "running",
816
- payload: prevOutput,
940
+ payload: inputData,
817
941
  startedAt: startedAt2
818
942
  }
819
943
  });
@@ -824,38 +948,60 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
824
948
  const isResume = !!resume?.steps?.length;
825
949
  let result;
826
950
  let runId;
827
- if (isResume) {
828
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
829
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
830
- workflowName: step.id,
831
- runId
832
- });
833
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
834
- function: step.getFunction(),
835
- data: {
836
- inputData: prevOutput,
837
- runId,
838
- resume: {
951
+ try {
952
+ if (isResume) {
953
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
954
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
955
+ workflowName: step.id,
956
+ runId
957
+ });
958
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
959
+ function: step.getFunction(),
960
+ data: {
961
+ inputData,
962
+ initialState: executionContext.state ?? snapshot?.value ?? {},
839
963
  runId,
840
- steps: resume.steps.slice(1),
841
- stepResults: snapshot?.context,
842
- resumePayload: resume.resumePayload,
843
- // @ts-ignore
844
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
964
+ resume: {
965
+ runId,
966
+ steps: resume.steps.slice(1),
967
+ stepResults: snapshot?.context,
968
+ resumePayload: resume.resumePayload,
969
+ // @ts-ignore
970
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
971
+ },
972
+ outputOptions: { includeState: true }
845
973
  }
846
- }
847
- });
848
- result = invokeResp.result;
849
- runId = invokeResp.runId;
850
- } else {
851
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
852
- function: step.getFunction(),
853
- data: {
854
- inputData: prevOutput
855
- }
856
- });
857
- result = invokeResp.result;
858
- runId = invokeResp.runId;
974
+ });
975
+ result = invokeResp.result;
976
+ runId = invokeResp.runId;
977
+ executionContext.state = invokeResp.result.state;
978
+ } else {
979
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
980
+ function: step.getFunction(),
981
+ data: {
982
+ inputData,
983
+ initialState: executionContext.state ?? {},
984
+ outputOptions: { includeState: true }
985
+ }
986
+ });
987
+ result = invokeResp.result;
988
+ runId = invokeResp.runId;
989
+ executionContext.state = invokeResp.result.state;
990
+ }
991
+ } catch (e) {
992
+ const errorCause = e?.cause;
993
+ if (errorCause && typeof errorCause === "object") {
994
+ result = errorCause;
995
+ runId = errorCause.runId || crypto.randomUUID();
996
+ } else {
997
+ runId = crypto.randomUUID();
998
+ result = {
999
+ status: "failed",
1000
+ error: e instanceof Error ? e : new Error(String(e)),
1001
+ steps: {},
1002
+ input: inputData
1003
+ };
1004
+ }
859
1005
  }
860
1006
  const res = await this.inngestStep.run(
861
1007
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -879,7 +1025,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
879
1025
  eventTimestamp: Date.now()
880
1026
  });
881
1027
  await emitter.emit("watch-v2", {
882
- type: "step-result",
1028
+ type: "workflow-step-result",
883
1029
  payload: {
884
1030
  id: step.id,
885
1031
  status: "failed",
@@ -894,7 +1040,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
894
1040
  return stepRes2?.status === "suspended";
895
1041
  });
896
1042
  for (const [stepName, stepResult] of suspendedSteps) {
897
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1043
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
898
1044
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
899
1045
  await emitter.emit("watch", {
900
1046
  type: "watch",
@@ -902,7 +1048,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
902
1048
  currentStep: {
903
1049
  id: step.id,
904
1050
  status: "suspended",
905
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1051
+ payload: stepResult.payload,
1052
+ suspendPayload: {
1053
+ ...stepResult?.suspendPayload,
1054
+ __workflow_meta: { runId, path: suspendPath }
1055
+ }
906
1056
  },
907
1057
  workflowState: {
908
1058
  status: "running",
@@ -914,7 +1064,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
914
1064
  eventTimestamp: Date.now()
915
1065
  });
916
1066
  await emitter.emit("watch-v2", {
917
- type: "step-suspended",
1067
+ type: "workflow-step-suspended",
918
1068
  payload: {
919
1069
  id: step.id,
920
1070
  status: "suspended"
@@ -924,7 +1074,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
924
1074
  executionContext,
925
1075
  result: {
926
1076
  status: "suspended",
927
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1077
+ payload: stepResult.payload,
1078
+ suspendPayload: {
1079
+ ...stepResult?.suspendPayload,
1080
+ __workflow_meta: { runId, path: suspendPath }
1081
+ }
928
1082
  }
929
1083
  };
930
1084
  }
@@ -971,7 +1125,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
971
1125
  eventTimestamp: Date.now()
972
1126
  });
973
1127
  await emitter.emit("watch-v2", {
974
- type: "step-result",
1128
+ type: "workflow-step-result",
975
1129
  payload: {
976
1130
  id: step.id,
977
1131
  status: "success",
@@ -979,7 +1133,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
979
1133
  }
980
1134
  });
981
1135
  await emitter.emit("watch-v2", {
982
- type: "step-finish",
1136
+ type: "workflow-step-finish",
983
1137
  payload: {
984
1138
  id: step.id,
985
1139
  metadata: {}
@@ -989,135 +1143,196 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
989
1143
  }
990
1144
  );
991
1145
  Object.assign(executionContext, res.executionContext);
992
- return res.result;
1146
+ return {
1147
+ ...res.result,
1148
+ startedAt,
1149
+ endedAt: Date.now(),
1150
+ payload: inputData,
1151
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1152
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1153
+ };
993
1154
  }
994
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
995
- let execResults;
996
- let suspended;
997
- let bailed;
998
- try {
999
- const result = await step.execute({
1000
- runId: executionContext.runId,
1001
- mastra: this.mastra,
1002
- runtimeContext,
1003
- inputData: prevOutput,
1004
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1005
- getInitData: () => stepResults?.input,
1006
- getStepResult: (step2) => {
1007
- const result2 = stepResults[step2.id];
1008
- if (result2?.status === "success") {
1009
- return result2.output;
1155
+ let stepRes;
1156
+ try {
1157
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1158
+ let execResults;
1159
+ let suspended;
1160
+ let bailed;
1161
+ try {
1162
+ if (validationError) {
1163
+ throw validationError;
1164
+ }
1165
+ const result = await step.execute({
1166
+ runId: executionContext.runId,
1167
+ mastra: this.mastra,
1168
+ runtimeContext,
1169
+ writableStream,
1170
+ state: executionContext?.state ?? {},
1171
+ setState: (state) => {
1172
+ executionContext.state = state;
1173
+ },
1174
+ inputData,
1175
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1176
+ tracingContext: {
1177
+ currentSpan: stepAISpan
1178
+ },
1179
+ getInitData: () => stepResults?.input,
1180
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1181
+ suspend: async (suspendPayload, suspendOptions) => {
1182
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1183
+ if (suspendOptions?.resumeLabel) {
1184
+ executionContext.resumeLabels[suspendOptions.resumeLabel] = step.id;
1185
+ }
1186
+ suspended = { payload: suspendPayload };
1187
+ },
1188
+ bail: (result2) => {
1189
+ bailed = { payload: result2 };
1190
+ },
1191
+ resume: {
1192
+ steps: resume?.steps?.slice(1) || [],
1193
+ resumePayload: resume?.resumePayload,
1194
+ // @ts-ignore
1195
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1196
+ },
1197
+ [_constants.EMITTER_SYMBOL]: emitter,
1198
+ engine: {
1199
+ step: this.inngestStep
1200
+ },
1201
+ abortSignal: abortController.signal
1202
+ });
1203
+ const endedAt = Date.now();
1204
+ execResults = {
1205
+ status: "success",
1206
+ output: result,
1207
+ startedAt,
1208
+ endedAt,
1209
+ payload: inputData,
1210
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1211
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1212
+ };
1213
+ } catch (e) {
1214
+ const stepFailure = {
1215
+ status: "failed",
1216
+ payload: inputData,
1217
+ error: e instanceof Error ? e.message : String(e),
1218
+ endedAt: Date.now(),
1219
+ startedAt,
1220
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1221
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1222
+ };
1223
+ execResults = stepFailure;
1224
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1225
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1226
+ throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1227
+ cause: execResults
1228
+ });
1229
+ }
1230
+ if (suspended) {
1231
+ execResults = {
1232
+ status: "suspended",
1233
+ suspendPayload: suspended.payload,
1234
+ payload: inputData,
1235
+ suspendedAt: Date.now(),
1236
+ startedAt,
1237
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1238
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1239
+ };
1240
+ } else if (bailed) {
1241
+ execResults = {
1242
+ status: "bailed",
1243
+ output: bailed.payload,
1244
+ payload: inputData,
1245
+ endedAt: Date.now(),
1246
+ startedAt
1247
+ };
1248
+ }
1249
+ await emitter.emit("watch", {
1250
+ type: "watch",
1251
+ payload: {
1252
+ currentStep: {
1253
+ id: step.id,
1254
+ ...execResults
1255
+ },
1256
+ workflowState: {
1257
+ status: "running",
1258
+ steps: { ...stepResults, [step.id]: execResults },
1259
+ result: null,
1260
+ error: null
1010
1261
  }
1011
- return null;
1012
- },
1013
- suspend: async (suspendPayload) => {
1014
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1015
- suspended = { payload: suspendPayload };
1016
- },
1017
- bail: (result2) => {
1018
- bailed = { payload: result2 };
1019
- },
1020
- resume: {
1021
- steps: resume?.steps?.slice(1) || [],
1022
- resumePayload: resume?.resumePayload,
1023
- // @ts-ignore
1024
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1025
- },
1026
- [_constants.EMITTER_SYMBOL]: emitter,
1027
- engine: {
1028
- step: this.inngestStep
1029
1262
  },
1030
- abortSignal: abortController.signal
1263
+ eventTimestamp: Date.now()
1031
1264
  });
1032
- const endedAt = Date.now();
1033
- execResults = {
1034
- status: "success",
1035
- output: result,
1036
- startedAt,
1037
- endedAt,
1038
- payload: prevOutput,
1039
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1040
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1041
- };
1042
- } catch (e) {
1043
- execResults = {
1044
- status: "failed",
1045
- payload: prevOutput,
1046
- error: e instanceof Error ? e.message : String(e),
1047
- endedAt: Date.now(),
1048
- startedAt,
1049
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1050
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1051
- };
1052
- }
1053
- if (suspended) {
1054
- execResults = {
1055
- status: "suspended",
1056
- suspendedPayload: suspended.payload,
1057
- payload: prevOutput,
1058
- suspendedAt: Date.now(),
1059
- startedAt,
1060
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1061
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1062
- };
1063
- } else if (bailed) {
1064
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1065
- }
1066
- if (execResults.status === "failed") {
1067
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1068
- throw execResults.error;
1265
+ if (execResults.status === "suspended") {
1266
+ await emitter.emit("watch-v2", {
1267
+ type: "workflow-step-suspended",
1268
+ payload: {
1269
+ id: step.id,
1270
+ ...execResults
1271
+ }
1272
+ });
1273
+ } else {
1274
+ await emitter.emit("watch-v2", {
1275
+ type: "workflow-step-result",
1276
+ payload: {
1277
+ id: step.id,
1278
+ ...execResults
1279
+ }
1280
+ });
1281
+ await emitter.emit("watch-v2", {
1282
+ type: "workflow-step-finish",
1283
+ payload: {
1284
+ id: step.id,
1285
+ metadata: {}
1286
+ }
1287
+ });
1069
1288
  }
1070
- }
1071
- await emitter.emit("watch", {
1072
- type: "watch",
1073
- payload: {
1074
- currentStep: {
1075
- id: step.id,
1076
- ...execResults
1077
- },
1078
- workflowState: {
1079
- status: "running",
1080
- steps: { ...stepResults, [step.id]: execResults },
1081
- result: null,
1082
- error: null
1083
- }
1084
- },
1085
- eventTimestamp: Date.now()
1289
+ stepAISpan?.end({ output: execResults });
1290
+ return { result: execResults, executionContext, stepResults };
1086
1291
  });
1087
- if (execResults.status === "suspended") {
1088
- await emitter.emit("watch-v2", {
1089
- type: "step-suspended",
1090
- payload: {
1091
- id: step.id,
1092
- ...execResults
1093
- }
1094
- });
1095
- } else {
1096
- await emitter.emit("watch-v2", {
1097
- type: "step-result",
1098
- payload: {
1099
- id: step.id,
1100
- ...execResults
1101
- }
1102
- });
1103
- await emitter.emit("watch-v2", {
1104
- type: "step-finish",
1105
- payload: {
1106
- id: step.id,
1107
- metadata: {}
1108
- }
1109
- });
1110
- }
1111
- return { result: execResults, executionContext, stepResults };
1112
- });
1292
+ } catch (e) {
1293
+ const stepFailure = e instanceof Error ? e?.cause : {
1294
+ status: "failed",
1295
+ error: e instanceof Error ? e.message : String(e),
1296
+ payload: inputData,
1297
+ startedAt,
1298
+ endedAt: Date.now()
1299
+ };
1300
+ stepRes = {
1301
+ result: stepFailure,
1302
+ executionContext,
1303
+ stepResults: {
1304
+ ...stepResults,
1305
+ [step.id]: stepFailure
1306
+ }
1307
+ };
1308
+ }
1309
+ if (disableScorers !== false && stepRes.result.status === "success") {
1310
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1311
+ if (step.scorers) {
1312
+ await this.runScorers({
1313
+ scorers: step.scorers,
1314
+ runId: executionContext.runId,
1315
+ input: inputData,
1316
+ output: stepRes.result,
1317
+ workflowId: executionContext.workflowId,
1318
+ stepId: step.id,
1319
+ runtimeContext,
1320
+ disableScorers,
1321
+ tracingContext: { currentSpan: stepAISpan }
1322
+ });
1323
+ }
1324
+ });
1325
+ }
1113
1326
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1114
1327
  Object.assign(stepResults, stepRes.stepResults);
1328
+ executionContext.state = stepRes.executionContext.state;
1115
1329
  return stepRes.result;
1116
1330
  }
1117
1331
  async persistStepUpdate({
1118
1332
  workflowId,
1119
1333
  runId,
1120
1334
  stepResults,
1335
+ resourceId,
1121
1336
  executionContext,
1122
1337
  serializedStepGraph,
1123
1338
  workflowStatus,
@@ -1127,15 +1342,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1127
1342
  await this.inngestStep.run(
1128
1343
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1129
1344
  async () => {
1345
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1346
+ if (!shouldPersistSnapshot) {
1347
+ return;
1348
+ }
1130
1349
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1131
1350
  workflowName: workflowId,
1132
1351
  runId,
1352
+ resourceId,
1133
1353
  snapshot: {
1134
1354
  runId,
1135
- value: {},
1355
+ value: executionContext.state,
1136
1356
  context: stepResults,
1137
1357
  activePaths: [],
1138
1358
  suspendedPaths: executionContext.suspendedPaths,
1359
+ resumeLabels: executionContext.resumeLabels,
1360
+ waitingPaths: {},
1139
1361
  serializedStepGraph,
1140
1362
  status: workflowStatus,
1141
1363
  result,
@@ -1159,30 +1381,50 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1159
1381
  executionContext,
1160
1382
  emitter,
1161
1383
  abortController,
1162
- runtimeContext
1384
+ runtimeContext,
1385
+ writableStream,
1386
+ disableScorers,
1387
+ tracingContext
1163
1388
  }) {
1389
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1390
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
1391
+ name: `conditional: '${entry.conditions.length} conditions'`,
1392
+ input: prevOutput,
1393
+ attributes: {
1394
+ conditionCount: entry.conditions.length
1395
+ },
1396
+ tracingPolicy: this.options?.tracingPolicy
1397
+ });
1164
1398
  let execResults;
1165
1399
  const truthyIndexes = (await Promise.all(
1166
1400
  entry.conditions.map(
1167
1401
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1402
+ const evalSpan = conditionalSpan?.createChildSpan({
1403
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1404
+ name: `condition: '${index}'`,
1405
+ input: prevOutput,
1406
+ attributes: {
1407
+ conditionIndex: index
1408
+ },
1409
+ tracingPolicy: this.options?.tracingPolicy
1410
+ });
1168
1411
  try {
1169
1412
  const result = await cond({
1170
1413
  runId,
1414
+ workflowId,
1171
1415
  mastra: this.mastra,
1172
1416
  runtimeContext,
1173
1417
  runCount: -1,
1174
1418
  inputData: prevOutput,
1175
- getInitData: () => stepResults?.input,
1176
- getStepResult: (step) => {
1177
- if (!step?.id) {
1178
- return null;
1179
- }
1180
- const result2 = stepResults[step.id];
1181
- if (result2?.status === "success") {
1182
- return result2.output;
1183
- }
1184
- return null;
1419
+ state: executionContext.state,
1420
+ setState: (state) => {
1421
+ executionContext.state = state;
1422
+ },
1423
+ tracingContext: {
1424
+ currentSpan: evalSpan
1185
1425
  },
1426
+ getInitData: () => stepResults?.input,
1427
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1186
1428
  // TODO: this function shouldn't have suspend probably?
1187
1429
  suspend: async (_suspendPayload) => {
1188
1430
  },
@@ -1192,40 +1434,76 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1192
1434
  abortController.abort();
1193
1435
  },
1194
1436
  [_constants.EMITTER_SYMBOL]: emitter,
1437
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1438
+ // TODO: add streamVNext support
1195
1439
  engine: {
1196
1440
  step: this.inngestStep
1197
1441
  },
1198
- abortSignal: abortController.signal
1442
+ abortSignal: abortController.signal,
1443
+ writer: new tools.ToolStream(
1444
+ {
1445
+ prefix: "workflow-step",
1446
+ callId: crypto.randomUUID(),
1447
+ name: "conditional",
1448
+ runId
1449
+ },
1450
+ writableStream
1451
+ )
1452
+ });
1453
+ evalSpan?.end({
1454
+ output: result,
1455
+ attributes: {
1456
+ result: !!result
1457
+ }
1199
1458
  });
1200
1459
  return result ? index : null;
1201
1460
  } catch (e) {
1461
+ evalSpan?.error({
1462
+ error: e instanceof Error ? e : new Error(String(e)),
1463
+ attributes: {
1464
+ result: false
1465
+ }
1466
+ });
1202
1467
  return null;
1203
1468
  }
1204
1469
  })
1205
1470
  )
1206
1471
  )).filter((index) => index !== null);
1207
1472
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1473
+ conditionalSpan?.update({
1474
+ attributes: {
1475
+ truthyIndexes,
1476
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1477
+ }
1478
+ });
1208
1479
  const results = await Promise.all(
1209
1480
  stepsToRun.map(
1210
1481
  (step, index) => this.executeEntry({
1211
1482
  workflowId,
1212
1483
  runId,
1213
1484
  entry: step,
1485
+ serializedStepGraph,
1214
1486
  prevStep,
1215
1487
  stepResults,
1216
1488
  resume,
1217
- serializedStepGraph,
1218
1489
  executionContext: {
1219
1490
  workflowId,
1220
1491
  runId,
1221
1492
  executionPath: [...executionContext.executionPath, index],
1222
1493
  suspendedPaths: executionContext.suspendedPaths,
1494
+ resumeLabels: executionContext.resumeLabels,
1223
1495
  retryConfig: executionContext.retryConfig,
1224
- executionSpan: executionContext.executionSpan
1496
+ executionSpan: executionContext.executionSpan,
1497
+ state: executionContext.state
1225
1498
  },
1226
1499
  emitter,
1227
1500
  abortController,
1228
- runtimeContext
1501
+ runtimeContext,
1502
+ writableStream,
1503
+ disableScorers,
1504
+ tracingContext: {
1505
+ currentSpan: conditionalSpan
1506
+ }
1229
1507
  })
1230
1508
  )
1231
1509
  );
@@ -1234,7 +1512,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1234
1512
  if (hasFailed) {
1235
1513
  execResults = { status: "failed", error: hasFailed.result.error };
1236
1514
  } else if (hasSuspended) {
1237
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1515
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1238
1516
  } else {
1239
1517
  execResults = {
1240
1518
  status: "success",
@@ -1246,6 +1524,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
1246
1524
  }, {})
1247
1525
  };
1248
1526
  }
1527
+ if (execResults.status === "failed") {
1528
+ conditionalSpan?.error({
1529
+ error: new Error(execResults.error)
1530
+ });
1531
+ } else {
1532
+ conditionalSpan?.end({
1533
+ output: execResults.output || execResults
1534
+ });
1535
+ }
1249
1536
  return execResults;
1250
1537
  }
1251
1538
  };
@@ -1256,3 +1543,5 @@ exports.InngestWorkflow = InngestWorkflow;
1256
1543
  exports.createStep = createStep;
1257
1544
  exports.init = init;
1258
1545
  exports.serve = serve;
1546
+ //# sourceMappingURL=index.cjs.map
1547
+ //# sourceMappingURL=index.cjs.map