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

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