@mastra/inngest 0.0.0-new-scorer-api-20250801075530 → 0.0.0-playground-studio-cloud-20251031080052

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