@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.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 { 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,19 +676,19 @@ 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;
@@ -629,7 +740,7 @@ 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 [];
@@ -639,33 +750,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
639
750
  executionSpan?.end();
640
751
  return base;
641
752
  }
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
753
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
670
754
  // await this.inngestStep.sleep(id, duration);
671
755
  // }
@@ -678,54 +762,86 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
678
762
  emitter,
679
763
  abortController,
680
764
  runtimeContext,
681
- writableStream
765
+ executionContext,
766
+ writableStream,
767
+ tracingContext
682
768
  }) {
683
769
  let { duration, fn } = entry;
770
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
771
+ type: AISpanType.WORKFLOW_SLEEP,
772
+ name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
773
+ attributes: {
774
+ durationMs: duration,
775
+ sleepType: fn ? "dynamic" : "fixed"
776
+ },
777
+ tracingPolicy: this.options?.tracingPolicy
778
+ });
684
779
  if (fn) {
685
780
  const stepCallId = randomUUID();
686
781
  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(
782
+ return await fn(
783
+ createDeprecationProxy(
717
784
  {
718
- prefix: "step",
719
- callId: stepCallId,
720
- name: "sleep",
721
- runId
785
+ runId,
786
+ workflowId,
787
+ mastra: this.mastra,
788
+ runtimeContext,
789
+ inputData: prevOutput,
790
+ state: executionContext.state,
791
+ setState: (state) => {
792
+ executionContext.state = state;
793
+ },
794
+ runCount: -1,
795
+ retryCount: -1,
796
+ tracingContext: {
797
+ currentSpan: sleepSpan
798
+ },
799
+ getInitData: () => stepResults?.input,
800
+ getStepResult: getStepResult.bind(this, stepResults),
801
+ // TODO: this function shouldn't have suspend probably?
802
+ suspend: async (_suspendPayload) => {
803
+ },
804
+ bail: () => {
805
+ },
806
+ abort: () => {
807
+ abortController?.abort();
808
+ },
809
+ [EMITTER_SYMBOL]: emitter,
810
+ // TODO: add streamVNext support
811
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
812
+ engine: { step: this.inngestStep },
813
+ abortSignal: abortController?.signal,
814
+ writer: new ToolStream(
815
+ {
816
+ prefix: "workflow-step",
817
+ callId: stepCallId,
818
+ name: "sleep",
819
+ runId
820
+ },
821
+ writableStream
822
+ )
722
823
  },
723
- writableStream
824
+ {
825
+ paramName: "runCount",
826
+ deprecationMessage: runCountDeprecationMessage,
827
+ logger: this.logger
828
+ }
724
829
  )
725
- });
830
+ );
726
831
  });
832
+ sleepSpan?.update({
833
+ attributes: {
834
+ durationMs: duration
835
+ }
836
+ });
837
+ }
838
+ try {
839
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
840
+ sleepSpan?.end();
841
+ } catch (e) {
842
+ sleepSpan?.error({ error: e });
843
+ throw e;
727
844
  }
728
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
729
845
  }
730
846
  async executeSleepUntil({
731
847
  workflowId,
@@ -736,57 +852,95 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
736
852
  emitter,
737
853
  abortController,
738
854
  runtimeContext,
739
- writableStream
855
+ executionContext,
856
+ writableStream,
857
+ tracingContext
740
858
  }) {
741
859
  let { date, fn } = entry;
860
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
861
+ type: AISpanType.WORKFLOW_SLEEP,
862
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
863
+ attributes: {
864
+ untilDate: date,
865
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
866
+ sleepType: fn ? "dynamic" : "fixed"
867
+ },
868
+ tracingPolicy: this.options?.tracingPolicy
869
+ });
742
870
  if (fn) {
743
871
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
744
872
  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(
873
+ return await fn(
874
+ createDeprecationProxy(
775
875
  {
776
- prefix: "step",
777
- callId: stepCallId,
778
- name: "sleep",
779
- runId
876
+ runId,
877
+ workflowId,
878
+ mastra: this.mastra,
879
+ runtimeContext,
880
+ inputData: prevOutput,
881
+ state: executionContext.state,
882
+ setState: (state) => {
883
+ executionContext.state = state;
884
+ },
885
+ runCount: -1,
886
+ retryCount: -1,
887
+ tracingContext: {
888
+ currentSpan: sleepUntilSpan
889
+ },
890
+ getInitData: () => stepResults?.input,
891
+ getStepResult: getStepResult.bind(this, stepResults),
892
+ // TODO: this function shouldn't have suspend probably?
893
+ suspend: async (_suspendPayload) => {
894
+ },
895
+ bail: () => {
896
+ },
897
+ abort: () => {
898
+ abortController?.abort();
899
+ },
900
+ [EMITTER_SYMBOL]: emitter,
901
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
902
+ // TODO: add streamVNext support
903
+ engine: { step: this.inngestStep },
904
+ abortSignal: abortController?.signal,
905
+ writer: new ToolStream(
906
+ {
907
+ prefix: "workflow-step",
908
+ callId: stepCallId,
909
+ name: "sleep",
910
+ runId
911
+ },
912
+ writableStream
913
+ )
780
914
  },
781
- writableStream
915
+ {
916
+ paramName: "runCount",
917
+ deprecationMessage: runCountDeprecationMessage,
918
+ logger: this.logger
919
+ }
782
920
  )
783
- });
921
+ );
922
+ });
923
+ if (date && !(date instanceof Date)) {
924
+ date = new Date(date);
925
+ }
926
+ const time = !date ? 0 : date.getTime() - Date.now();
927
+ sleepUntilSpan?.update({
928
+ attributes: {
929
+ durationMs: Math.max(0, time)
930
+ }
784
931
  });
785
932
  }
786
933
  if (!(date instanceof Date)) {
934
+ sleepUntilSpan?.end();
787
935
  return;
788
936
  }
789
- await this.inngestStep.sleepUntil(entry.id, date);
937
+ try {
938
+ await this.inngestStep.sleepUntil(entry.id, date);
939
+ sleepUntilSpan?.end();
940
+ } catch (e) {
941
+ sleepUntilSpan?.error({ error: e });
942
+ throw e;
943
+ }
790
944
  }
791
945
  async executeWaitForEvent({ event, timeout }) {
792
946
  const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
@@ -807,8 +961,24 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
807
961
  emitter,
808
962
  abortController,
809
963
  runtimeContext,
810
- writableStream
964
+ tracingContext,
965
+ writableStream,
966
+ disableScorers
811
967
  }) {
968
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
969
+ name: `workflow step: '${step.id}'`,
970
+ type: AISpanType.WORKFLOW_STEP,
971
+ input: prevOutput,
972
+ attributes: {
973
+ stepId: step.id
974
+ },
975
+ tracingPolicy: this.options?.tracingPolicy
976
+ });
977
+ const { inputData, validationError } = await validateStepInput({
978
+ prevOutput,
979
+ step,
980
+ validateInputs: this.options?.validateInputs ?? false
981
+ });
812
982
  const startedAt = await this.inngestStep.run(
813
983
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
814
984
  async () => {
@@ -835,11 +1005,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
835
1005
  eventTimestamp: Date.now()
836
1006
  });
837
1007
  await emitter.emit("watch-v2", {
838
- type: "step-start",
1008
+ type: "workflow-step-start",
839
1009
  payload: {
840
1010
  id: step.id,
841
1011
  status: "running",
842
- payload: prevOutput,
1012
+ payload: inputData,
843
1013
  startedAt: startedAt2
844
1014
  }
845
1015
  });
@@ -850,38 +1020,60 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
850
1020
  const isResume = !!resume?.steps?.length;
851
1021
  let result;
852
1022
  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: {
1023
+ try {
1024
+ if (isResume) {
1025
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
1026
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1027
+ workflowName: step.id,
1028
+ runId
1029
+ });
1030
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1031
+ function: step.getFunction(),
1032
+ data: {
1033
+ inputData,
1034
+ initialState: executionContext.state ?? snapshot?.value ?? {},
865
1035
  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]]
1036
+ resume: {
1037
+ runId,
1038
+ steps: resume.steps.slice(1),
1039
+ stepResults: snapshot?.context,
1040
+ resumePayload: resume.resumePayload,
1041
+ // @ts-ignore
1042
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1043
+ },
1044
+ outputOptions: { includeState: true }
871
1045
  }
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;
1046
+ });
1047
+ result = invokeResp.result;
1048
+ runId = invokeResp.runId;
1049
+ executionContext.state = invokeResp.result.state;
1050
+ } else {
1051
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1052
+ function: step.getFunction(),
1053
+ data: {
1054
+ inputData,
1055
+ initialState: executionContext.state ?? {},
1056
+ outputOptions: { includeState: true }
1057
+ }
1058
+ });
1059
+ result = invokeResp.result;
1060
+ runId = invokeResp.runId;
1061
+ executionContext.state = invokeResp.result.state;
1062
+ }
1063
+ } catch (e) {
1064
+ const errorCause = e?.cause;
1065
+ if (errorCause && typeof errorCause === "object") {
1066
+ result = errorCause;
1067
+ runId = errorCause.runId || randomUUID();
1068
+ } else {
1069
+ runId = randomUUID();
1070
+ result = {
1071
+ status: "failed",
1072
+ error: e instanceof Error ? e : new Error(String(e)),
1073
+ steps: {},
1074
+ input: inputData
1075
+ };
1076
+ }
885
1077
  }
886
1078
  const res = await this.inngestStep.run(
887
1079
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -905,7 +1097,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
905
1097
  eventTimestamp: Date.now()
906
1098
  });
907
1099
  await emitter.emit("watch-v2", {
908
- type: "step-result",
1100
+ type: "workflow-step-result",
909
1101
  payload: {
910
1102
  id: step.id,
911
1103
  status: "failed",
@@ -920,7 +1112,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
920
1112
  return stepRes2?.status === "suspended";
921
1113
  });
922
1114
  for (const [stepName, stepResult] of suspendedSteps) {
923
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1115
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
924
1116
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
925
1117
  await emitter.emit("watch", {
926
1118
  type: "watch",
@@ -928,7 +1120,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
928
1120
  currentStep: {
929
1121
  id: step.id,
930
1122
  status: "suspended",
931
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1123
+ payload: stepResult.payload,
1124
+ suspendPayload: {
1125
+ ...stepResult?.suspendPayload,
1126
+ __workflow_meta: { runId, path: suspendPath }
1127
+ }
932
1128
  },
933
1129
  workflowState: {
934
1130
  status: "running",
@@ -940,7 +1136,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
940
1136
  eventTimestamp: Date.now()
941
1137
  });
942
1138
  await emitter.emit("watch-v2", {
943
- type: "step-suspended",
1139
+ type: "workflow-step-suspended",
944
1140
  payload: {
945
1141
  id: step.id,
946
1142
  status: "suspended"
@@ -950,7 +1146,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
950
1146
  executionContext,
951
1147
  result: {
952
1148
  status: "suspended",
953
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1149
+ payload: stepResult.payload,
1150
+ suspendPayload: {
1151
+ ...stepResult?.suspendPayload,
1152
+ __workflow_meta: { runId, path: suspendPath }
1153
+ }
954
1154
  }
955
1155
  };
956
1156
  }
@@ -997,7 +1197,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
997
1197
  eventTimestamp: Date.now()
998
1198
  });
999
1199
  await emitter.emit("watch-v2", {
1000
- type: "step-result",
1200
+ type: "workflow-step-result",
1001
1201
  payload: {
1002
1202
  id: step.id,
1003
1203
  status: "success",
@@ -1005,7 +1205,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1005
1205
  }
1006
1206
  });
1007
1207
  await emitter.emit("watch-v2", {
1008
- type: "step-finish",
1208
+ type: "workflow-step-finish",
1009
1209
  payload: {
1010
1210
  id: step.id,
1011
1211
  metadata: {}
@@ -1015,136 +1215,202 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1015
1215
  }
1016
1216
  );
1017
1217
  Object.assign(executionContext, res.executionContext);
1018
- return res.result;
1218
+ return {
1219
+ ...res.result,
1220
+ startedAt,
1221
+ endedAt: Date.now(),
1222
+ payload: inputData,
1223
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1224
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1225
+ };
1019
1226
  }
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;
1227
+ let stepRes;
1228
+ try {
1229
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1230
+ let execResults;
1231
+ let suspended;
1232
+ let bailed;
1233
+ try {
1234
+ if (validationError) {
1235
+ throw validationError;
1236
+ }
1237
+ const result = await step.execute({
1238
+ runId: executionContext.runId,
1239
+ mastra: this.mastra,
1240
+ runtimeContext,
1241
+ writableStream,
1242
+ state: executionContext?.state ?? {},
1243
+ setState: (state) => {
1244
+ executionContext.state = state;
1245
+ },
1246
+ inputData,
1247
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1248
+ tracingContext: {
1249
+ currentSpan: stepAISpan
1250
+ },
1251
+ getInitData: () => stepResults?.input,
1252
+ getStepResult: getStepResult.bind(this, stepResults),
1253
+ suspend: async (suspendPayload, suspendOptions) => {
1254
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1255
+ if (suspendOptions?.resumeLabel) {
1256
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1257
+ for (const label of resumeLabel) {
1258
+ executionContext.resumeLabels[label] = {
1259
+ stepId: step.id,
1260
+ foreachIndex: executionContext.foreachIndex
1261
+ };
1262
+ }
1263
+ }
1264
+ suspended = { payload: suspendPayload };
1265
+ },
1266
+ bail: (result2) => {
1267
+ bailed = { payload: result2 };
1268
+ },
1269
+ resume: {
1270
+ steps: resume?.steps?.slice(1) || [],
1271
+ resumePayload: resume?.resumePayload,
1272
+ // @ts-ignore
1273
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1274
+ },
1275
+ [EMITTER_SYMBOL]: emitter,
1276
+ engine: {
1277
+ step: this.inngestStep
1278
+ },
1279
+ abortSignal: abortController.signal
1280
+ });
1281
+ const endedAt = Date.now();
1282
+ execResults = {
1283
+ status: "success",
1284
+ output: result,
1285
+ startedAt,
1286
+ endedAt,
1287
+ payload: inputData,
1288
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1289
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1290
+ };
1291
+ } catch (e) {
1292
+ const stepFailure = {
1293
+ status: "failed",
1294
+ payload: inputData,
1295
+ error: e instanceof Error ? e.message : String(e),
1296
+ endedAt: Date.now(),
1297
+ startedAt,
1298
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1299
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1300
+ };
1301
+ execResults = stepFailure;
1302
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1303
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1304
+ throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1305
+ cause: execResults
1306
+ });
1307
+ }
1308
+ if (suspended) {
1309
+ execResults = {
1310
+ status: "suspended",
1311
+ suspendPayload: suspended.payload,
1312
+ payload: inputData,
1313
+ suspendedAt: Date.now(),
1314
+ startedAt,
1315
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1316
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1317
+ };
1318
+ } else if (bailed) {
1319
+ execResults = {
1320
+ status: "bailed",
1321
+ output: bailed.payload,
1322
+ payload: inputData,
1323
+ endedAt: Date.now(),
1324
+ startedAt
1325
+ };
1326
+ }
1327
+ await emitter.emit("watch", {
1328
+ type: "watch",
1329
+ payload: {
1330
+ currentStep: {
1331
+ id: step.id,
1332
+ ...execResults
1333
+ },
1334
+ workflowState: {
1335
+ status: "running",
1336
+ steps: { ...stepResults, [step.id]: execResults },
1337
+ result: null,
1338
+ error: null
1037
1339
  }
1038
- return null;
1039
- },
1040
- suspend: async (suspendPayload) => {
1041
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1042
- suspended = { payload: suspendPayload };
1043
1340
  },
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
1341
+ eventTimestamp: Date.now()
1058
1342
  });
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;
1343
+ if (execResults.status === "suspended") {
1344
+ await emitter.emit("watch-v2", {
1345
+ type: "workflow-step-suspended",
1346
+ payload: {
1347
+ id: step.id,
1348
+ ...execResults
1349
+ }
1350
+ });
1351
+ } else {
1352
+ await emitter.emit("watch-v2", {
1353
+ type: "workflow-step-result",
1354
+ payload: {
1355
+ id: step.id,
1356
+ ...execResults
1357
+ }
1358
+ });
1359
+ await emitter.emit("watch-v2", {
1360
+ type: "workflow-step-finish",
1361
+ payload: {
1362
+ id: step.id,
1363
+ metadata: {}
1364
+ }
1365
+ });
1096
1366
  }
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()
1367
+ stepAISpan?.end({ output: execResults });
1368
+ return { result: execResults, executionContext, stepResults };
1113
1369
  });
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
- });
1370
+ } catch (e) {
1371
+ const stepFailure = e instanceof Error ? e?.cause : {
1372
+ status: "failed",
1373
+ error: e instanceof Error ? e.message : String(e),
1374
+ payload: inputData,
1375
+ startedAt,
1376
+ endedAt: Date.now()
1377
+ };
1378
+ stepRes = {
1379
+ result: stepFailure,
1380
+ executionContext,
1381
+ stepResults: {
1382
+ ...stepResults,
1383
+ [step.id]: stepFailure
1384
+ }
1385
+ };
1386
+ }
1387
+ if (disableScorers !== false && stepRes.result.status === "success") {
1388
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1389
+ if (step.scorers) {
1390
+ await this.runScorers({
1391
+ scorers: step.scorers,
1392
+ runId: executionContext.runId,
1393
+ input: inputData,
1394
+ output: stepRes.result,
1395
+ workflowId: executionContext.workflowId,
1396
+ stepId: step.id,
1397
+ runtimeContext,
1398
+ disableScorers,
1399
+ tracingContext: { currentSpan: stepAISpan }
1400
+ });
1401
+ }
1402
+ });
1403
+ }
1140
1404
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1141
1405
  Object.assign(stepResults, stepRes.stepResults);
1406
+ executionContext.state = stepRes.executionContext.state;
1142
1407
  return stepRes.result;
1143
1408
  }
1144
1409
  async persistStepUpdate({
1145
1410
  workflowId,
1146
1411
  runId,
1147
1412
  stepResults,
1413
+ resourceId,
1148
1414
  executionContext,
1149
1415
  serializedStepGraph,
1150
1416
  workflowStatus,
@@ -1154,15 +1420,22 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1154
1420
  await this.inngestStep.run(
1155
1421
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1156
1422
  async () => {
1423
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1424
+ if (!shouldPersistSnapshot) {
1425
+ return;
1426
+ }
1157
1427
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1158
1428
  workflowName: workflowId,
1159
1429
  runId,
1430
+ resourceId,
1160
1431
  snapshot: {
1161
1432
  runId,
1162
- value: {},
1433
+ value: executionContext.state,
1163
1434
  context: stepResults,
1164
1435
  activePaths: [],
1165
1436
  suspendedPaths: executionContext.suspendedPaths,
1437
+ resumeLabels: executionContext.resumeLabels,
1438
+ waitingPaths: {},
1166
1439
  serializedStepGraph,
1167
1440
  status: workflowStatus,
1168
1441
  result,
@@ -1187,84 +1460,138 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1187
1460
  emitter,
1188
1461
  abortController,
1189
1462
  runtimeContext,
1190
- writableStream
1463
+ writableStream,
1464
+ disableScorers,
1465
+ tracingContext
1191
1466
  }) {
1467
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1468
+ type: AISpanType.WORKFLOW_CONDITIONAL,
1469
+ name: `conditional: '${entry.conditions.length} conditions'`,
1470
+ input: prevOutput,
1471
+ attributes: {
1472
+ conditionCount: entry.conditions.length
1473
+ },
1474
+ tracingPolicy: this.options?.tracingPolicy
1475
+ });
1192
1476
  let execResults;
1193
1477
  const truthyIndexes = (await Promise.all(
1194
1478
  entry.conditions.map(
1195
1479
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1480
+ const evalSpan = conditionalSpan?.createChildSpan({
1481
+ type: AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1482
+ name: `condition: '${index}'`,
1483
+ input: prevOutput,
1484
+ attributes: {
1485
+ conditionIndex: index
1486
+ },
1487
+ tracingPolicy: this.options?.tracingPolicy
1488
+ });
1196
1489
  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(
1490
+ const result = await cond(
1491
+ createDeprecationProxy(
1229
1492
  {
1230
- prefix: "step",
1231
- callId: randomUUID(),
1232
- name: "conditional",
1233
- runId
1493
+ runId,
1494
+ workflowId,
1495
+ mastra: this.mastra,
1496
+ runtimeContext,
1497
+ runCount: -1,
1498
+ retryCount: -1,
1499
+ inputData: prevOutput,
1500
+ state: executionContext.state,
1501
+ setState: (state) => {
1502
+ executionContext.state = state;
1503
+ },
1504
+ tracingContext: {
1505
+ currentSpan: evalSpan
1506
+ },
1507
+ getInitData: () => stepResults?.input,
1508
+ getStepResult: getStepResult.bind(this, stepResults),
1509
+ // TODO: this function shouldn't have suspend probably?
1510
+ suspend: async (_suspendPayload) => {
1511
+ },
1512
+ bail: () => {
1513
+ },
1514
+ abort: () => {
1515
+ abortController.abort();
1516
+ },
1517
+ [EMITTER_SYMBOL]: emitter,
1518
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1519
+ // TODO: add streamVNext support
1520
+ engine: {
1521
+ step: this.inngestStep
1522
+ },
1523
+ abortSignal: abortController.signal,
1524
+ writer: new ToolStream(
1525
+ {
1526
+ prefix: "workflow-step",
1527
+ callId: randomUUID(),
1528
+ name: "conditional",
1529
+ runId
1530
+ },
1531
+ writableStream
1532
+ )
1234
1533
  },
1235
- writableStream
1534
+ {
1535
+ paramName: "runCount",
1536
+ deprecationMessage: runCountDeprecationMessage,
1537
+ logger: this.logger
1538
+ }
1236
1539
  )
1540
+ );
1541
+ evalSpan?.end({
1542
+ output: result,
1543
+ attributes: {
1544
+ result: !!result
1545
+ }
1237
1546
  });
1238
1547
  return result ? index : null;
1239
1548
  } catch (e) {
1549
+ evalSpan?.error({
1550
+ error: e instanceof Error ? e : new Error(String(e)),
1551
+ attributes: {
1552
+ result: false
1553
+ }
1554
+ });
1240
1555
  return null;
1241
1556
  }
1242
1557
  })
1243
1558
  )
1244
1559
  )).filter((index) => index !== null);
1245
1560
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1561
+ conditionalSpan?.update({
1562
+ attributes: {
1563
+ truthyIndexes,
1564
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1565
+ }
1566
+ });
1246
1567
  const results = await Promise.all(
1247
1568
  stepsToRun.map(
1248
1569
  (step, index) => this.executeEntry({
1249
1570
  workflowId,
1250
1571
  runId,
1251
1572
  entry: step,
1573
+ serializedStepGraph,
1252
1574
  prevStep,
1253
1575
  stepResults,
1254
1576
  resume,
1255
- serializedStepGraph,
1256
1577
  executionContext: {
1257
1578
  workflowId,
1258
1579
  runId,
1259
1580
  executionPath: [...executionContext.executionPath, index],
1260
1581
  suspendedPaths: executionContext.suspendedPaths,
1582
+ resumeLabels: executionContext.resumeLabels,
1261
1583
  retryConfig: executionContext.retryConfig,
1262
- executionSpan: executionContext.executionSpan
1584
+ executionSpan: executionContext.executionSpan,
1585
+ state: executionContext.state
1263
1586
  },
1264
1587
  emitter,
1265
1588
  abortController,
1266
1589
  runtimeContext,
1267
- writableStream
1590
+ writableStream,
1591
+ disableScorers,
1592
+ tracingContext: {
1593
+ currentSpan: conditionalSpan
1594
+ }
1268
1595
  })
1269
1596
  )
1270
1597
  );
@@ -1273,7 +1600,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1273
1600
  if (hasFailed) {
1274
1601
  execResults = { status: "failed", error: hasFailed.result.error };
1275
1602
  } else if (hasSuspended) {
1276
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1603
+ execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1277
1604
  } else {
1278
1605
  execResults = {
1279
1606
  status: "success",
@@ -1285,6 +1612,15 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1285
1612
  }, {})
1286
1613
  };
1287
1614
  }
1615
+ if (execResults.status === "failed") {
1616
+ conditionalSpan?.error({
1617
+ error: new Error(execResults.error)
1618
+ });
1619
+ } else {
1620
+ conditionalSpan?.end({
1621
+ output: execResults.output || execResults
1622
+ });
1623
+ }
1288
1624
  return execResults;
1289
1625
  }
1290
1626
  };