@mastra/inngest 0.0.0-transpile-packages-20250731152758 → 0.0.0-unified-sidebar-20251010130811

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