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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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,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,16 +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,
181
+ workflowId: this.workflowId,
156
182
  stepResults: snapshot?.context,
157
183
  resume: {
158
184
  steps,
159
185
  stepResults: snapshot?.context,
160
- resumePayload: params.resumeData,
186
+ resumePayload: resumeDataToUse,
161
187
  // @ts-ignore
162
188
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
163
189
  }
@@ -202,7 +228,11 @@ var InngestRun = class extends Run {
202
228
  const writer = writable.getWriter();
203
229
  const unwatch = this.watch(async (event) => {
204
230
  try {
205
- await writer.write(event);
231
+ const e = {
232
+ ...event,
233
+ type: event.type.replace("workflow-", "")
234
+ };
235
+ await writer.write(e);
206
236
  } catch {
207
237
  }
208
238
  }, "watch-v2");
@@ -233,8 +263,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
233
263
  #mastra;
234
264
  inngest;
235
265
  function;
266
+ flowControlConfig;
236
267
  constructor(params, inngest) {
237
- 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;
238
274
  this.#mastra = params.mastra;
239
275
  this.inngest = inngest;
240
276
  }
@@ -255,27 +291,6 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
255
291
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
256
292
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
257
293
  }
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
294
  __registerMastra(mastra) {
280
295
  this.#mastra = mastra;
281
296
  this.executionEngine.__registerMastra(mastra);
@@ -294,23 +309,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
294
309
  }
295
310
  }
296
311
  }
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
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."
311
319
  );
312
- this.runs.set(runIdToUse, run);
313
- return run;
314
320
  }
315
321
  async createRunAsync(options) {
316
322
  const runIdToUse = options?.runId || randomUUID();
@@ -318,27 +324,35 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
318
324
  {
319
325
  workflowId: this.id,
320
326
  runId: runIdToUse,
327
+ resourceId: options?.resourceId,
321
328
  executionEngine: this.executionEngine,
322
329
  executionGraph: this.executionGraph,
323
330
  serializedStepGraph: this.serializedStepGraph,
324
331
  mastra: this.#mastra,
325
332
  retryConfig: this.retryConfig,
326
- cleanup: () => this.runs.delete(runIdToUse)
333
+ cleanup: () => this.runs.delete(runIdToUse),
334
+ workflowSteps: this.steps
327
335
  },
328
336
  this.inngest
329
337
  );
330
338
  this.runs.set(runIdToUse, run);
331
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
332
- 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) {
333
345
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
334
346
  workflowName: this.id,
335
347
  runId: runIdToUse,
348
+ resourceId: options?.resourceId,
336
349
  snapshot: {
337
350
  runId: runIdToUse,
338
351
  status: "pending",
339
352
  value: {},
340
353
  context: {},
341
354
  activePaths: [],
355
+ waitingPaths: {},
342
356
  serializedStepGraph: this.serializedStepGraph,
343
357
  suspendedPaths: {},
344
358
  result: void 0,
@@ -359,11 +373,13 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
359
373
  id: `workflow.${this.id}`,
360
374
  // @ts-ignore
361
375
  retries: this.retryConfig?.attempts ?? 0,
362
- cancelOn: [{ event: `cancel.workflow.${this.id}` }]
376
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
377
+ // Spread flow control configuration
378
+ ...this.flowControlConfig
363
379
  },
364
380
  { event: `workflow.${this.id}` },
365
381
  async ({ event, step, attempt, publish }) => {
366
- let { inputData, runId, resume } = event.data;
382
+ let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
367
383
  if (!runId) {
368
384
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
369
385
  return randomUUID();
@@ -391,19 +407,32 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
391
407
  once: (_event, _callback) => {
392
408
  }
393
409
  };
394
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
410
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
395
411
  const result = await engine.execute({
396
412
  workflowId: this.id,
397
413
  runId,
414
+ resourceId,
398
415
  graph: this.executionGraph,
399
416
  serializedStepGraph: this.serializedStepGraph,
400
417
  input: inputData,
418
+ initialState,
401
419
  emitter,
402
420
  retryConfig: this.retryConfig,
403
421
  runtimeContext: new RuntimeContext(),
404
422
  // TODO
405
423
  resume,
406
- 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;
407
436
  });
408
437
  return { result, runId };
409
438
  }
@@ -437,17 +466,16 @@ function createStep(params) {
437
466
  if (isAgent(params)) {
438
467
  return {
439
468
  id: params.name,
469
+ description: params.getDescription(),
440
470
  // @ts-ignore
441
471
  inputSchema: z.object({
442
472
  prompt: z.string()
443
- // resourceId: z.string().optional(),
444
- // threadId: z.string().optional(),
445
473
  }),
446
474
  // @ts-ignore
447
475
  outputSchema: z.object({
448
476
  text: z.string()
449
477
  }),
450
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
478
+ execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
451
479
  let streamPromise = {};
452
480
  streamPromise.promise = new Promise((resolve, reject) => {
453
481
  streamPromise.resolve = resolve;
@@ -457,50 +485,66 @@ function createStep(params) {
457
485
  name: params.name,
458
486
  args: inputData
459
487
  };
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":
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") {
479
531
  await emitter.emit("watch-v2", {
480
532
  type: "tool-call-delta",
481
- ...toolData,
533
+ ...toolData ?? {},
482
534
  argsTextDelta: chunk.textDelta
483
535
  });
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;
536
+ }
498
537
  }
499
538
  }
539
+ await emitter.emit("watch-v2", {
540
+ type: "tool-call-streaming-finish",
541
+ ...toolData ?? {}
542
+ });
500
543
  return {
501
544
  text: await streamPromise.promise
502
545
  };
503
- }
546
+ },
547
+ component: params.component
504
548
  };
505
549
  }
506
550
  if (isTool(params)) {
@@ -511,15 +555,20 @@ function createStep(params) {
511
555
  // TODO: tool probably should have strong id type
512
556
  // @ts-ignore
513
557
  id: params.id,
558
+ description: params.description,
514
559
  inputSchema: params.inputSchema,
515
560
  outputSchema: params.outputSchema,
516
- execute: async ({ inputData, mastra, runtimeContext }) => {
561
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
517
562
  return params.execute({
518
563
  context: inputData,
519
- mastra,
520
- runtimeContext
564
+ mastra: wrapMastra(mastra, tracingContext),
565
+ runtimeContext,
566
+ tracingContext,
567
+ suspend,
568
+ resumeData
521
569
  });
522
- }
570
+ },
571
+ component: "TOOL"
523
572
  };
524
573
  }
525
574
  return {
@@ -535,7 +584,10 @@ function createStep(params) {
535
584
  function init(inngest) {
536
585
  return {
537
586
  createWorkflow(params) {
538
- return new InngestWorkflow(params, inngest);
587
+ return new InngestWorkflow(
588
+ params,
589
+ inngest
590
+ );
539
591
  },
540
592
  createStep,
541
593
  cloneStep(step, opts) {
@@ -544,7 +596,11 @@ function init(inngest) {
544
596
  description: step.description,
545
597
  inputSchema: step.inputSchema,
546
598
  outputSchema: step.outputSchema,
547
- execute: step.execute
599
+ resumeSchema: step.resumeSchema,
600
+ suspendSchema: step.suspendSchema,
601
+ stateSchema: step.stateSchema,
602
+ execute: step.execute,
603
+ component: step.component
548
604
  };
549
605
  },
550
606
  cloneWorkflow(workflow, opts) {
@@ -564,19 +620,19 @@ function init(inngest) {
564
620
  var InngestExecutionEngine = class extends DefaultExecutionEngine {
565
621
  inngestStep;
566
622
  inngestAttempts;
567
- constructor(mastra, inngestStep, inngestAttempts = 0) {
568
- super({ mastra });
623
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
624
+ super({ mastra, options });
569
625
  this.inngestStep = inngestStep;
570
626
  this.inngestAttempts = inngestAttempts;
571
627
  }
572
628
  async execute(params) {
573
629
  await params.emitter.emit("watch-v2", {
574
- type: "start",
630
+ type: "workflow-start",
575
631
  payload: { runId: params.runId }
576
632
  });
577
633
  const result = await super.execute(params);
578
634
  await params.emitter.emit("watch-v2", {
579
- type: "finish",
635
+ type: "workflow-finish",
580
636
  payload: { runId: params.runId }
581
637
  });
582
638
  return result;
@@ -628,7 +684,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
628
684
  });
629
685
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
630
686
  if (stepResult?.status === "suspended") {
631
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
687
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
632
688
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
633
689
  }
634
690
  return [];
@@ -638,31 +694,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
638
694
  executionSpan?.end();
639
695
  return base;
640
696
  }
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
697
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
667
698
  // await this.inngestStep.sleep(id, duration);
668
699
  // }
@@ -674,28 +705,40 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
674
705
  stepResults,
675
706
  emitter,
676
707
  abortController,
677
- runtimeContext
708
+ runtimeContext,
709
+ executionContext,
710
+ writableStream,
711
+ tracingContext
678
712
  }) {
679
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
+ });
680
723
  if (fn) {
724
+ const stepCallId = randomUUID();
681
725
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
682
726
  return await fn({
683
727
  runId,
728
+ workflowId,
684
729
  mastra: this.mastra,
685
730
  runtimeContext,
686
731
  inputData: prevOutput,
732
+ state: executionContext.state,
733
+ setState: (state) => {
734
+ executionContext.state = state;
735
+ },
687
736
  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;
737
+ tracingContext: {
738
+ currentSpan: sleepSpan
698
739
  },
740
+ getInitData: () => stepResults?.input,
741
+ getStepResult: getStepResult.bind(this, stepResults),
699
742
  // TODO: this function shouldn't have suspend probably?
700
743
  suspend: async (_suspendPayload) => {
701
744
  },
@@ -705,12 +748,34 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
705
748
  abortController?.abort();
706
749
  },
707
750
  [EMITTER_SYMBOL]: emitter,
751
+ // TODO: add streamVNext support
752
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
708
753
  engine: { step: this.inngestStep },
709
- abortSignal: abortController?.signal
754
+ abortSignal: abortController?.signal,
755
+ writer: new ToolStream(
756
+ {
757
+ prefix: "workflow-step",
758
+ callId: stepCallId,
759
+ name: "sleep",
760
+ runId
761
+ },
762
+ writableStream
763
+ )
710
764
  });
711
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;
712
778
  }
713
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
714
779
  }
715
780
  async executeSleepUntil({
716
781
  workflowId,
@@ -720,28 +785,41 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
720
785
  stepResults,
721
786
  emitter,
722
787
  abortController,
723
- runtimeContext
788
+ runtimeContext,
789
+ executionContext,
790
+ writableStream,
791
+ tracingContext
724
792
  }) {
725
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
+ });
726
804
  if (fn) {
727
805
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
806
+ const stepCallId = randomUUID();
728
807
  return await fn({
729
808
  runId,
809
+ workflowId,
730
810
  mastra: this.mastra,
731
811
  runtimeContext,
732
812
  inputData: prevOutput,
813
+ state: executionContext.state,
814
+ setState: (state) => {
815
+ executionContext.state = state;
816
+ },
733
817
  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;
818
+ tracingContext: {
819
+ currentSpan: sleepUntilSpan
744
820
  },
821
+ getInitData: () => stepResults?.input,
822
+ getStepResult: getStepResult.bind(this, stepResults),
745
823
  // TODO: this function shouldn't have suspend probably?
746
824
  suspend: async (_suspendPayload) => {
747
825
  },
@@ -751,15 +829,42 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
751
829
  abortController?.abort();
752
830
  },
753
831
  [EMITTER_SYMBOL]: emitter,
832
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
833
+ // TODO: add streamVNext support
754
834
  engine: { step: this.inngestStep },
755
- abortSignal: abortController?.signal
835
+ abortSignal: abortController?.signal,
836
+ writer: new ToolStream(
837
+ {
838
+ prefix: "workflow-step",
839
+ callId: stepCallId,
840
+ name: "sleep",
841
+ runId
842
+ },
843
+ writableStream
844
+ )
756
845
  });
757
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
+ });
758
856
  }
759
857
  if (!(date instanceof Date)) {
858
+ sleepUntilSpan?.end();
760
859
  return;
761
860
  }
762
- 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
+ }
763
868
  }
764
869
  async executeWaitForEvent({ event, timeout }) {
765
870
  const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
@@ -779,8 +884,25 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
779
884
  prevOutput,
780
885
  emitter,
781
886
  abortController,
782
- runtimeContext
887
+ runtimeContext,
888
+ tracingContext,
889
+ writableStream,
890
+ disableScorers
783
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
+ });
784
906
  const startedAt = await this.inngestStep.run(
785
907
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
786
908
  async () => {
@@ -807,11 +929,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
807
929
  eventTimestamp: Date.now()
808
930
  });
809
931
  await emitter.emit("watch-v2", {
810
- type: "step-start",
932
+ type: "workflow-step-start",
811
933
  payload: {
812
934
  id: step.id,
813
935
  status: "running",
814
- payload: prevOutput,
936
+ payload: inputData,
815
937
  startedAt: startedAt2
816
938
  }
817
939
  });
@@ -822,38 +944,60 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
822
944
  const isResume = !!resume?.steps?.length;
823
945
  let result;
824
946
  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: {
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 ?? {},
837
959
  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]]
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 }
843
969
  }
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;
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
+ }
857
1001
  }
858
1002
  const res = await this.inngestStep.run(
859
1003
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -877,7 +1021,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
877
1021
  eventTimestamp: Date.now()
878
1022
  });
879
1023
  await emitter.emit("watch-v2", {
880
- type: "step-result",
1024
+ type: "workflow-step-result",
881
1025
  payload: {
882
1026
  id: step.id,
883
1027
  status: "failed",
@@ -892,7 +1036,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
892
1036
  return stepRes2?.status === "suspended";
893
1037
  });
894
1038
  for (const [stepName, stepResult] of suspendedSteps) {
895
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1039
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
896
1040
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
897
1041
  await emitter.emit("watch", {
898
1042
  type: "watch",
@@ -900,7 +1044,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
900
1044
  currentStep: {
901
1045
  id: step.id,
902
1046
  status: "suspended",
903
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1047
+ payload: stepResult.payload,
1048
+ suspendPayload: {
1049
+ ...stepResult?.suspendPayload,
1050
+ __workflow_meta: { runId, path: suspendPath }
1051
+ }
904
1052
  },
905
1053
  workflowState: {
906
1054
  status: "running",
@@ -912,7 +1060,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
912
1060
  eventTimestamp: Date.now()
913
1061
  });
914
1062
  await emitter.emit("watch-v2", {
915
- type: "step-suspended",
1063
+ type: "workflow-step-suspended",
916
1064
  payload: {
917
1065
  id: step.id,
918
1066
  status: "suspended"
@@ -922,7 +1070,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
922
1070
  executionContext,
923
1071
  result: {
924
1072
  status: "suspended",
925
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1073
+ payload: stepResult.payload,
1074
+ suspendPayload: {
1075
+ ...stepResult?.suspendPayload,
1076
+ __workflow_meta: { runId, path: suspendPath }
1077
+ }
926
1078
  }
927
1079
  };
928
1080
  }
@@ -969,7 +1121,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
969
1121
  eventTimestamp: Date.now()
970
1122
  });
971
1123
  await emitter.emit("watch-v2", {
972
- type: "step-result",
1124
+ type: "workflow-step-result",
973
1125
  payload: {
974
1126
  id: step.id,
975
1127
  status: "success",
@@ -977,7 +1129,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
977
1129
  }
978
1130
  });
979
1131
  await emitter.emit("watch-v2", {
980
- type: "step-finish",
1132
+ type: "workflow-step-finish",
981
1133
  payload: {
982
1134
  id: step.id,
983
1135
  metadata: {}
@@ -987,135 +1139,193 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
987
1139
  }
988
1140
  );
989
1141
  Object.assign(executionContext, res.executionContext);
990
- 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
+ };
991
1150
  }
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;
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
1008
1254
  }
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
1255
  },
1028
- abortSignal: abortController.signal
1256
+ eventTimestamp: Date.now()
1029
1257
  });
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;
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
+ });
1067
1281
  }
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()
1282
+ stepAISpan?.end({ output: execResults });
1283
+ return { result: execResults, executionContext, stepResults };
1084
1284
  });
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
- });
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
+ }
1111
1319
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1112
1320
  Object.assign(stepResults, stepRes.stepResults);
1321
+ executionContext.state = stepRes.executionContext.state;
1113
1322
  return stepRes.result;
1114
1323
  }
1115
1324
  async persistStepUpdate({
1116
1325
  workflowId,
1117
1326
  runId,
1118
1327
  stepResults,
1328
+ resourceId,
1119
1329
  executionContext,
1120
1330
  serializedStepGraph,
1121
1331
  workflowStatus,
@@ -1125,15 +1335,21 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1125
1335
  await this.inngestStep.run(
1126
1336
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1127
1337
  async () => {
1338
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1339
+ if (!shouldPersistSnapshot) {
1340
+ return;
1341
+ }
1128
1342
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1129
1343
  workflowName: workflowId,
1130
1344
  runId,
1345
+ resourceId,
1131
1346
  snapshot: {
1132
1347
  runId,
1133
- value: {},
1348
+ value: executionContext.state,
1134
1349
  context: stepResults,
1135
1350
  activePaths: [],
1136
1351
  suspendedPaths: executionContext.suspendedPaths,
1352
+ waitingPaths: {},
1137
1353
  serializedStepGraph,
1138
1354
  status: workflowStatus,
1139
1355
  result,
@@ -1157,30 +1373,50 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1157
1373
  executionContext,
1158
1374
  emitter,
1159
1375
  abortController,
1160
- runtimeContext
1376
+ runtimeContext,
1377
+ writableStream,
1378
+ disableScorers,
1379
+ tracingContext
1161
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
+ });
1162
1390
  let execResults;
1163
1391
  const truthyIndexes = (await Promise.all(
1164
1392
  entry.conditions.map(
1165
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
+ });
1166
1403
  try {
1167
1404
  const result = await cond({
1168
1405
  runId,
1406
+ workflowId,
1169
1407
  mastra: this.mastra,
1170
1408
  runtimeContext,
1171
1409
  runCount: -1,
1172
1410
  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;
1411
+ state: executionContext.state,
1412
+ setState: (state) => {
1413
+ executionContext.state = state;
1414
+ },
1415
+ tracingContext: {
1416
+ currentSpan: evalSpan
1183
1417
  },
1418
+ getInitData: () => stepResults?.input,
1419
+ getStepResult: getStepResult.bind(this, stepResults),
1184
1420
  // TODO: this function shouldn't have suspend probably?
1185
1421
  suspend: async (_suspendPayload) => {
1186
1422
  },
@@ -1190,40 +1426,75 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1190
1426
  abortController.abort();
1191
1427
  },
1192
1428
  [EMITTER_SYMBOL]: emitter,
1429
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1430
+ // TODO: add streamVNext support
1193
1431
  engine: {
1194
1432
  step: this.inngestStep
1195
1433
  },
1196
- abortSignal: abortController.signal
1434
+ abortSignal: abortController.signal,
1435
+ writer: new ToolStream(
1436
+ {
1437
+ prefix: "workflow-step",
1438
+ callId: randomUUID(),
1439
+ name: "conditional",
1440
+ runId
1441
+ },
1442
+ writableStream
1443
+ )
1444
+ });
1445
+ evalSpan?.end({
1446
+ output: result,
1447
+ attributes: {
1448
+ result: !!result
1449
+ }
1197
1450
  });
1198
1451
  return result ? index : null;
1199
1452
  } catch (e) {
1453
+ evalSpan?.error({
1454
+ error: e instanceof Error ? e : new Error(String(e)),
1455
+ attributes: {
1456
+ result: false
1457
+ }
1458
+ });
1200
1459
  return null;
1201
1460
  }
1202
1461
  })
1203
1462
  )
1204
1463
  )).filter((index) => index !== null);
1205
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
+ });
1206
1471
  const results = await Promise.all(
1207
1472
  stepsToRun.map(
1208
1473
  (step, index) => this.executeEntry({
1209
1474
  workflowId,
1210
1475
  runId,
1211
1476
  entry: step,
1477
+ serializedStepGraph,
1212
1478
  prevStep,
1213
1479
  stepResults,
1214
1480
  resume,
1215
- serializedStepGraph,
1216
1481
  executionContext: {
1217
1482
  workflowId,
1218
1483
  runId,
1219
1484
  executionPath: [...executionContext.executionPath, index],
1220
1485
  suspendedPaths: executionContext.suspendedPaths,
1221
1486
  retryConfig: executionContext.retryConfig,
1222
- executionSpan: executionContext.executionSpan
1487
+ executionSpan: executionContext.executionSpan,
1488
+ state: executionContext.state
1223
1489
  },
1224
1490
  emitter,
1225
1491
  abortController,
1226
- runtimeContext
1492
+ runtimeContext,
1493
+ writableStream,
1494
+ disableScorers,
1495
+ tracingContext: {
1496
+ currentSpan: conditionalSpan
1497
+ }
1227
1498
  })
1228
1499
  )
1229
1500
  );
@@ -1232,7 +1503,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1232
1503
  if (hasFailed) {
1233
1504
  execResults = { status: "failed", error: hasFailed.result.error };
1234
1505
  } else if (hasSuspended) {
1235
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1506
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1236
1507
  } else {
1237
1508
  execResults = {
1238
1509
  status: "success",
@@ -1244,8 +1515,19 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1244
1515
  }, {})
1245
1516
  };
1246
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
+ }
1247
1527
  return execResults;
1248
1528
  }
1249
1529
  };
1250
1530
 
1251
1531
  export { InngestExecutionEngine, InngestRun, InngestWorkflow, createStep, init, serve };
1532
+ //# sourceMappingURL=index.js.map
1533
+ //# sourceMappingURL=index.js.map