@mastra/inngest 0.0.0-message-list-update-20250715150321 → 0.0.0-monorepo-binary-20251013210052

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