@mastra/inngest 0.0.0-experimental-agent-builder-20250815195917 → 0.0.0-extract-tool-ui-inp-playground-ui-20251023135343

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