@mastra/inngest 0.0.0-mssql-store-20250804200341 → 0.0.0-netlify-no-bundle-20251127120354

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, WritableStream } from 'stream/web';
2
3
  import { subscribe } from '@inngest/realtime';
3
- import { RuntimeContext } from '@mastra/core/di';
4
+ import { RequestContext } from '@mastra/core/di';
5
+ import { SpanType } from '@mastra/core/observability';
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, createTimeTravelExecutionParams, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput, validateStepResumeData, validateStepSuspendData } 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 }) {
12
- const wfs = mastra.getWorkflows();
13
- const functions = Array.from(
15
+ function serve({
16
+ mastra,
17
+ inngest,
18
+ functions: userFunctions = [],
19
+ registerOptions
20
+ }) {
21
+ const wfs = mastra.listWorkflows();
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 {
@@ -47,14 +57,21 @@ var InngestRun = class extends Run {
47
57
  }
48
58
  async getRunOutput(eventId) {
49
59
  let runs = await this.getRuns(eventId);
60
+ const storage = this.#mastra?.getStorage();
50
61
  while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
51
62
  await new Promise((resolve) => setTimeout(resolve, 1e3));
52
63
  runs = await this.getRuns(eventId);
53
64
  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") {
57
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
65
+ const snapshot = await storage?.loadWorkflowSnapshot({
66
+ workflowName: this.workflowId,
67
+ runId: this.runId
68
+ });
69
+ return {
70
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
71
+ };
72
+ }
73
+ if (runs?.[0]?.status === "Cancelled") {
74
+ const snapshot = await storage?.loadWorkflowSnapshot({
58
75
  workflowName: this.workflowId,
59
76
  runId: this.runId
60
77
  });
@@ -63,56 +80,71 @@ var InngestRun = class extends Run {
63
80
  }
64
81
  return runs?.[0];
65
82
  }
66
- async sendEvent(event, data) {
67
- await this.inngest.send({
68
- name: `user-event-${event}`,
69
- data
70
- });
71
- }
72
83
  async cancel() {
84
+ const storage = this.#mastra?.getStorage();
73
85
  await this.inngest.send({
74
86
  name: `cancel.workflow.${this.workflowId}`,
75
87
  data: {
76
88
  runId: this.runId
77
89
  }
78
90
  });
79
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
91
+ const snapshot = await storage?.loadWorkflowSnapshot({
80
92
  workflowName: this.workflowId,
81
93
  runId: this.runId
82
94
  });
83
95
  if (snapshot) {
84
- await this.#mastra?.storage?.persistWorkflowSnapshot({
96
+ await storage?.persistWorkflowSnapshot({
85
97
  workflowName: this.workflowId,
86
98
  runId: this.runId,
99
+ resourceId: this.resourceId,
87
100
  snapshot: {
88
101
  ...snapshot,
89
- status: "canceled"
102
+ status: "canceled",
103
+ value: snapshot.value
90
104
  }
91
105
  });
92
106
  }
93
107
  }
94
- async start({
95
- inputData
108
+ async start(params) {
109
+ return this._start(params);
110
+ }
111
+ async _start({
112
+ inputData,
113
+ initialState,
114
+ outputOptions,
115
+ tracingOptions,
116
+ format
96
117
  }) {
97
118
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
98
119
  workflowName: this.workflowId,
99
120
  runId: this.runId,
121
+ resourceId: this.resourceId,
100
122
  snapshot: {
101
123
  runId: this.runId,
102
124
  serializedStepGraph: this.serializedStepGraph,
125
+ status: "running",
103
126
  value: {},
104
127
  context: {},
105
128
  activePaths: [],
106
129
  suspendedPaths: {},
107
- timestamp: Date.now(),
108
- status: "running"
130
+ activeStepsPath: {},
131
+ resumeLabels: {},
132
+ waitingPaths: {},
133
+ timestamp: Date.now()
109
134
  }
110
135
  });
136
+ const inputDataToUse = await this._validateInput(inputData);
137
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
111
138
  const eventOutput = await this.inngest.send({
112
139
  name: `workflow.${this.workflowId}`,
113
140
  data: {
114
- inputData,
115
- runId: this.runId
141
+ inputData: inputDataToUse,
142
+ initialState: initialStateToUse,
143
+ runId: this.runId,
144
+ resourceId: this.resourceId,
145
+ outputOptions,
146
+ tracingOptions,
147
+ format
116
148
  }
117
149
  });
118
150
  const eventId = eventOutput.ids[0];
@@ -141,26 +173,34 @@ var InngestRun = class extends Run {
141
173
  return p;
142
174
  }
143
175
  async _resume(params) {
144
- const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
145
- (step) => typeof step === "string" ? step : step?.id
146
- );
147
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
176
+ const storage = this.#mastra?.getStorage();
177
+ let steps = [];
178
+ if (typeof params.step === "string") {
179
+ steps = params.step.split(".");
180
+ } else {
181
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
182
+ (step) => typeof step === "string" ? step : step?.id
183
+ );
184
+ }
185
+ const snapshot = await storage?.loadWorkflowSnapshot({
148
186
  workflowName: this.workflowId,
149
187
  runId: this.runId
150
188
  });
189
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
190
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
151
191
  const eventOutput = await this.inngest.send({
152
192
  name: `workflow.${this.workflowId}`,
153
193
  data: {
154
- inputData: params.resumeData,
194
+ inputData: resumeDataToUse,
195
+ initialState: snapshot?.value ?? {},
155
196
  runId: this.runId,
156
197
  workflowId: this.workflowId,
157
198
  stepResults: snapshot?.context,
158
199
  resume: {
159
200
  steps,
160
201
  stepResults: snapshot?.context,
161
- resumePayload: params.resumeData,
162
- // @ts-ignore
163
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
202
+ resumePayload: resumeDataToUse,
203
+ resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
164
204
  }
165
205
  }
166
206
  });
@@ -175,12 +215,103 @@ var InngestRun = class extends Run {
175
215
  }
176
216
  return result;
177
217
  }
178
- watch(cb, type = "watch") {
218
+ async timeTravel(params) {
219
+ const p = this._timeTravel(params).then((result) => {
220
+ if (result.status !== "suspended") {
221
+ this.closeStreamAction?.().catch(() => {
222
+ });
223
+ }
224
+ return result;
225
+ });
226
+ this.executionResults = p;
227
+ return p;
228
+ }
229
+ async _timeTravel(params) {
230
+ if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
231
+ throw new Error("Step is required and must be a valid step or array of steps");
232
+ }
233
+ let steps = [];
234
+ if (typeof params.step === "string") {
235
+ steps = params.step.split(".");
236
+ } else {
237
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
238
+ (step) => typeof step === "string" ? step : step?.id
239
+ );
240
+ }
241
+ if (steps.length === 0) {
242
+ throw new Error("No steps provided to timeTravel");
243
+ }
244
+ const storage = this.#mastra?.getStorage();
245
+ const snapshot = await storage?.loadWorkflowSnapshot({
246
+ workflowName: this.workflowId,
247
+ runId: this.runId
248
+ });
249
+ if (!snapshot) {
250
+ await storage?.persistWorkflowSnapshot({
251
+ workflowName: this.workflowId,
252
+ runId: this.runId,
253
+ resourceId: this.resourceId,
254
+ snapshot: {
255
+ runId: this.runId,
256
+ serializedStepGraph: this.serializedStepGraph,
257
+ status: "pending",
258
+ value: {},
259
+ context: {},
260
+ activePaths: [],
261
+ suspendedPaths: {},
262
+ activeStepsPath: {},
263
+ resumeLabels: {},
264
+ waitingPaths: {},
265
+ timestamp: Date.now()
266
+ }
267
+ });
268
+ }
269
+ if (snapshot?.status === "running") {
270
+ throw new Error("This workflow run is still running, cannot time travel");
271
+ }
272
+ let inputDataToUse = params.inputData;
273
+ if (inputDataToUse && steps.length === 1) {
274
+ inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
275
+ }
276
+ const timeTravelData = createTimeTravelExecutionParams({
277
+ steps,
278
+ inputData: inputDataToUse,
279
+ resumeData: params.resumeData,
280
+ context: params.context,
281
+ nestedStepsContext: params.nestedStepsContext,
282
+ snapshot: snapshot ?? { context: {} },
283
+ graph: this.executionGraph,
284
+ initialState: params.initialState
285
+ });
286
+ const eventOutput = await this.inngest.send({
287
+ name: `workflow.${this.workflowId}`,
288
+ data: {
289
+ initialState: timeTravelData.state,
290
+ runId: this.runId,
291
+ workflowId: this.workflowId,
292
+ stepResults: timeTravelData.stepResults,
293
+ timeTravel: timeTravelData,
294
+ tracingOptions: params.tracingOptions,
295
+ outputOptions: params.outputOptions
296
+ }
297
+ });
298
+ const eventId = eventOutput.ids[0];
299
+ if (!eventId) {
300
+ throw new Error("Event ID is not set");
301
+ }
302
+ const runOutput = await this.getRunOutput(eventId);
303
+ const result = runOutput?.output?.result;
304
+ if (result.status === "failed") {
305
+ result.error = new Error(result.error);
306
+ }
307
+ return result;
308
+ }
309
+ watch(cb) {
179
310
  let active = true;
180
311
  const streamPromise = subscribe(
181
312
  {
182
313
  channel: `workflow:${this.workflowId}:${this.runId}`,
183
- topics: [type],
314
+ topics: ["watch"],
184
315
  app: this.inngest
185
316
  },
186
317
  (message) => {
@@ -198,16 +329,35 @@ var InngestRun = class extends Run {
198
329
  });
199
330
  };
200
331
  }
201
- stream({ inputData, runtimeContext } = {}) {
332
+ streamLegacy({ inputData, requestContext } = {}) {
202
333
  const { readable, writable } = new TransformStream();
203
334
  const writer = writable.getWriter();
335
+ void writer.write({
336
+ // @ts-ignore
337
+ type: "start",
338
+ // @ts-ignore
339
+ payload: { runId: this.runId }
340
+ });
204
341
  const unwatch = this.watch(async (event) => {
205
342
  try {
206
- await writer.write(event);
343
+ const e = {
344
+ ...event,
345
+ type: event.type.replace("workflow-", "")
346
+ };
347
+ if (e.type === "step-output") {
348
+ e.type = e.payload.output.type;
349
+ e.payload = e.payload.output.payload;
350
+ }
351
+ await writer.write(e);
207
352
  } catch {
208
353
  }
209
- }, "watch-v2");
354
+ });
210
355
  this.closeStreamAction = async () => {
356
+ await writer.write({
357
+ type: "finish",
358
+ // @ts-ignore
359
+ payload: { runId: this.runId }
360
+ });
211
361
  unwatch();
212
362
  try {
213
363
  await writer.close();
@@ -217,7 +367,7 @@ var InngestRun = class extends Run {
217
367
  writer.releaseLock();
218
368
  }
219
369
  };
220
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
370
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
221
371
  if (result.status !== "suspended") {
222
372
  this.closeStreamAction?.().catch(() => {
223
373
  });
@@ -229,23 +379,175 @@ var InngestRun = class extends Run {
229
379
  getWorkflowState: () => this.executionResults
230
380
  };
231
381
  }
382
+ stream({
383
+ inputData,
384
+ requestContext,
385
+ tracingOptions,
386
+ closeOnSuspend = true,
387
+ initialState,
388
+ outputOptions
389
+ } = {}) {
390
+ if (this.closeStreamAction && this.streamOutput) {
391
+ return this.streamOutput;
392
+ }
393
+ this.closeStreamAction = async () => {
394
+ };
395
+ const self = this;
396
+ const stream = new ReadableStream({
397
+ async start(controller) {
398
+ const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
399
+ controller.enqueue({
400
+ type,
401
+ runId: self.runId,
402
+ from,
403
+ payload: {
404
+ stepName: payload?.id,
405
+ ...payload
406
+ }
407
+ });
408
+ });
409
+ self.closeStreamAction = async () => {
410
+ unwatch();
411
+ try {
412
+ await controller.close();
413
+ } catch (err) {
414
+ console.error("Error closing stream:", err);
415
+ }
416
+ };
417
+ const executionResultsPromise = self._start({
418
+ inputData,
419
+ requestContext,
420
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
421
+ initialState,
422
+ tracingOptions,
423
+ outputOptions,
424
+ format: "vnext"
425
+ });
426
+ let executionResults;
427
+ try {
428
+ executionResults = await executionResultsPromise;
429
+ if (closeOnSuspend) {
430
+ self.closeStreamAction?.().catch(() => {
431
+ });
432
+ } else if (executionResults.status !== "suspended") {
433
+ self.closeStreamAction?.().catch(() => {
434
+ });
435
+ }
436
+ if (self.streamOutput) {
437
+ self.streamOutput.updateResults(
438
+ executionResults
439
+ );
440
+ }
441
+ } catch (err) {
442
+ self.streamOutput?.rejectResults(err);
443
+ self.closeStreamAction?.().catch(() => {
444
+ });
445
+ }
446
+ }
447
+ });
448
+ this.streamOutput = new WorkflowRunOutput({
449
+ runId: this.runId,
450
+ workflowId: this.workflowId,
451
+ stream
452
+ });
453
+ return this.streamOutput;
454
+ }
455
+ streamVNext(args = {}) {
456
+ return this.stream(args);
457
+ }
458
+ timeTravelStream({
459
+ inputData,
460
+ resumeData,
461
+ initialState,
462
+ step,
463
+ context,
464
+ nestedStepsContext,
465
+ requestContext,
466
+ tracingOptions,
467
+ outputOptions
468
+ }) {
469
+ this.closeStreamAction = async () => {
470
+ };
471
+ const self = this;
472
+ const stream = new ReadableStream({
473
+ async start(controller) {
474
+ const unwatch = self.watch(async ({ type, from = ChunkFrom.WORKFLOW, payload }) => {
475
+ controller.enqueue({
476
+ type,
477
+ runId: self.runId,
478
+ from,
479
+ payload: {
480
+ stepName: payload?.id,
481
+ ...payload
482
+ }
483
+ });
484
+ });
485
+ self.closeStreamAction = async () => {
486
+ unwatch();
487
+ try {
488
+ await controller.close();
489
+ } catch (err) {
490
+ console.error("Error closing stream:", err);
491
+ }
492
+ };
493
+ const executionResultsPromise = self._timeTravel({
494
+ inputData,
495
+ step,
496
+ context,
497
+ nestedStepsContext,
498
+ resumeData,
499
+ initialState,
500
+ requestContext,
501
+ tracingOptions,
502
+ outputOptions
503
+ });
504
+ self.executionResults = executionResultsPromise;
505
+ let executionResults;
506
+ try {
507
+ executionResults = await executionResultsPromise;
508
+ self.closeStreamAction?.().catch(() => {
509
+ });
510
+ if (self.streamOutput) {
511
+ self.streamOutput.updateResults(executionResults);
512
+ }
513
+ } catch (err) {
514
+ self.streamOutput?.rejectResults(err);
515
+ self.closeStreamAction?.().catch(() => {
516
+ });
517
+ }
518
+ }
519
+ });
520
+ this.streamOutput = new WorkflowRunOutput({
521
+ runId: this.runId,
522
+ workflowId: this.workflowId,
523
+ stream
524
+ });
525
+ return this.streamOutput;
526
+ }
232
527
  };
233
528
  var InngestWorkflow = class _InngestWorkflow extends Workflow {
234
529
  #mastra;
235
530
  inngest;
236
531
  function;
532
+ flowControlConfig;
237
533
  constructor(params, inngest) {
238
- super(params);
534
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
535
+ super(workflowParams);
536
+ this.engineType = "inngest";
537
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
538
+ ([_, value]) => value !== void 0
539
+ );
540
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
239
541
  this.#mastra = params.mastra;
240
542
  this.inngest = inngest;
241
543
  }
242
- async getWorkflowRuns(args) {
544
+ async listWorkflowRuns(args) {
243
545
  const storage = this.#mastra?.getStorage();
244
546
  if (!storage) {
245
547
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
246
548
  return { runs: [], total: 0 };
247
549
  }
248
- return storage.getWorkflowRuns({ workflowName: this.id, ...args ?? {} });
550
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
249
551
  }
250
552
  async getWorkflowRunById(runId) {
251
553
  const storage = this.#mastra?.getStorage();
@@ -256,27 +558,6 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
256
558
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
257
559
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
258
560
  }
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
561
  __registerMastra(mastra) {
281
562
  this.#mastra = mastra;
282
563
  this.executionEngine.__registerMastra(mastra);
@@ -295,56 +576,49 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
295
576
  }
296
577
  }
297
578
  }
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
312
- );
313
- this.runs.set(runIdToUse, run);
314
- return run;
315
- }
316
- async createRunAsync(options) {
579
+ async createRun(options) {
317
580
  const runIdToUse = options?.runId || randomUUID();
318
581
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
319
582
  {
320
583
  workflowId: this.id,
321
584
  runId: runIdToUse,
585
+ resourceId: options?.resourceId,
322
586
  executionEngine: this.executionEngine,
323
587
  executionGraph: this.executionGraph,
324
588
  serializedStepGraph: this.serializedStepGraph,
325
589
  mastra: this.#mastra,
326
590
  retryConfig: this.retryConfig,
327
- cleanup: () => this.runs.delete(runIdToUse)
591
+ cleanup: () => this.runs.delete(runIdToUse),
592
+ workflowSteps: this.steps,
593
+ workflowEngineType: this.engineType,
594
+ validateInputs: this.options.validateInputs
328
595
  },
329
596
  this.inngest
330
597
  );
331
598
  this.runs.set(runIdToUse, run);
332
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
333
- if (!workflowSnapshotInStorage) {
599
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
600
+ workflowStatus: run.workflowRunStatus,
601
+ stepResults: {}
602
+ });
603
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
604
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
334
605
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
335
606
  workflowName: this.id,
336
607
  runId: runIdToUse,
608
+ resourceId: options?.resourceId,
337
609
  snapshot: {
338
610
  runId: runIdToUse,
339
611
  status: "pending",
340
612
  value: {},
341
613
  context: {},
342
614
  activePaths: [],
615
+ activeStepsPath: {},
616
+ waitingPaths: {},
343
617
  serializedStepGraph: this.serializedStepGraph,
344
618
  suspendedPaths: {},
619
+ resumeLabels: {},
345
620
  result: void 0,
346
621
  error: void 0,
347
- // @ts-ignore
348
622
  timestamp: Date.now()
349
623
  }
350
624
  });
@@ -358,13 +632,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
358
632
  this.function = this.inngest.createFunction(
359
633
  {
360
634
  id: `workflow.${this.id}`,
361
- // @ts-ignore
362
- retries: this.retryConfig?.attempts ?? 0,
363
- cancelOn: [{ event: `cancel.workflow.${this.id}` }]
635
+ retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
636
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
637
+ // Spread flow control configuration
638
+ ...this.flowControlConfig
364
639
  },
365
640
  { event: `workflow.${this.id}` },
366
641
  async ({ event, step, attempt, publish }) => {
367
- let { inputData, runId, resume } = event.data;
642
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
368
643
  if (!runId) {
369
644
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
370
645
  return randomUUID();
@@ -392,19 +667,39 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
392
667
  once: (_event, _callback) => {
393
668
  }
394
669
  };
395
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
670
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
396
671
  const result = await engine.execute({
397
672
  workflowId: this.id,
398
673
  runId,
674
+ resourceId,
399
675
  graph: this.executionGraph,
400
676
  serializedStepGraph: this.serializedStepGraph,
401
677
  input: inputData,
678
+ initialState,
402
679
  emitter,
403
680
  retryConfig: this.retryConfig,
404
- runtimeContext: new RuntimeContext(),
681
+ requestContext: new RequestContext(),
405
682
  // TODO
406
683
  resume,
407
- abortController: new AbortController()
684
+ timeTravel,
685
+ format,
686
+ abortController: new AbortController(),
687
+ // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
688
+ outputOptions,
689
+ writableStream: new WritableStream({
690
+ write(chunk) {
691
+ void emitter.emit("watch", chunk).catch(() => {
692
+ });
693
+ }
694
+ })
695
+ });
696
+ await step.run(`workflow.${this.id}.finalize`, async () => {
697
+ if (result.status === "failed") {
698
+ throw new NonRetriableError(`Workflow failed`, {
699
+ cause: result
700
+ });
701
+ }
702
+ return result;
408
703
  });
409
704
  return { result, runId };
410
705
  }
@@ -434,21 +729,29 @@ function isAgent(params) {
434
729
  function isTool(params) {
435
730
  return params instanceof Tool;
436
731
  }
437
- function createStep(params) {
732
+ function createStep(params, agentOptions) {
438
733
  if (isAgent(params)) {
439
734
  return {
440
735
  id: params.name,
441
- // @ts-ignore
736
+ description: params.getDescription(),
442
737
  inputSchema: z.object({
443
738
  prompt: z.string()
444
739
  // resourceId: z.string().optional(),
445
740
  // threadId: z.string().optional(),
446
741
  }),
447
- // @ts-ignore
448
742
  outputSchema: z.object({
449
743
  text: z.string()
450
744
  }),
451
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
745
+ execute: async ({
746
+ inputData,
747
+ [EMITTER_SYMBOL]: emitter,
748
+ [STREAM_FORMAT_SYMBOL]: streamFormat,
749
+ requestContext,
750
+ tracingContext,
751
+ abortSignal,
752
+ abort,
753
+ writer
754
+ }) => {
452
755
  let streamPromise = {};
453
756
  streamPromise.promise = new Promise((resolve, reject) => {
454
757
  streamPromise.resolve = resolve;
@@ -458,50 +761,65 @@ function createStep(params) {
458
761
  name: params.name,
459
762
  args: inputData
460
763
  };
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();
764
+ let stream;
765
+ if ((await params.getModel()).specificationVersion === "v1") {
766
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
767
+ ...agentOptions ?? {},
768
+ // resourceId: inputData.resourceId,
769
+ // threadId: inputData.threadId,
770
+ requestContext,
771
+ tracingContext,
772
+ onFinish: (result) => {
773
+ streamPromise.resolve(result.text);
774
+ void agentOptions?.onFinish?.(result);
775
+ },
776
+ abortSignal
777
+ });
778
+ stream = fullStream;
779
+ } else {
780
+ const modelOutput = await params.stream(inputData.prompt, {
781
+ ...agentOptions ?? {},
782
+ requestContext,
783
+ tracingContext,
784
+ onFinish: (result) => {
785
+ streamPromise.resolve(result.text);
786
+ void agentOptions?.onFinish?.(result);
787
+ },
788
+ abortSignal
789
+ });
790
+ stream = modelOutput.fullStream;
476
791
  }
477
- for await (const chunk of fullStream) {
478
- switch (chunk.type) {
479
- case "text-delta":
480
- await emitter.emit("watch-v2", {
792
+ if (streamFormat === "legacy") {
793
+ await emitter.emit("watch", {
794
+ type: "tool-call-streaming-start",
795
+ ...toolData ?? {}
796
+ });
797
+ for await (const chunk of stream) {
798
+ if (chunk.type === "text-delta") {
799
+ await emitter.emit("watch", {
481
800
  type: "tool-call-delta",
482
- ...toolData,
801
+ ...toolData ?? {},
483
802
  argsTextDelta: chunk.textDelta
484
803
  });
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;
804
+ }
805
+ }
806
+ await emitter.emit("watch", {
807
+ type: "tool-call-streaming-finish",
808
+ ...toolData ?? {}
809
+ });
810
+ } else {
811
+ for await (const chunk of stream) {
812
+ await writer.write(chunk);
499
813
  }
500
814
  }
815
+ if (abortSignal.aborted) {
816
+ return abort();
817
+ }
501
818
  return {
502
819
  text: await streamPromise.promise
503
820
  };
504
- }
821
+ },
822
+ component: params.component
505
823
  };
506
824
  }
507
825
  if (isTool(params)) {
@@ -510,17 +828,40 @@ function createStep(params) {
510
828
  }
511
829
  return {
512
830
  // TODO: tool probably should have strong id type
513
- // @ts-ignore
514
831
  id: params.id,
832
+ description: params.description,
515
833
  inputSchema: params.inputSchema,
516
834
  outputSchema: params.outputSchema,
517
- execute: async ({ inputData, mastra, runtimeContext }) => {
518
- return params.execute({
519
- context: inputData,
835
+ suspendSchema: params.suspendSchema,
836
+ resumeSchema: params.resumeSchema,
837
+ execute: async ({
838
+ inputData,
839
+ mastra,
840
+ requestContext,
841
+ tracingContext,
842
+ suspend,
843
+ resumeData,
844
+ runId,
845
+ workflowId,
846
+ state,
847
+ setState
848
+ }) => {
849
+ const toolContext = {
520
850
  mastra,
521
- runtimeContext
522
- });
523
- }
851
+ requestContext,
852
+ tracingContext,
853
+ workflow: {
854
+ runId,
855
+ resumeData,
856
+ suspend,
857
+ workflowId,
858
+ state,
859
+ setState
860
+ }
861
+ };
862
+ return params.execute(inputData, toolContext);
863
+ },
864
+ component: "TOOL"
524
865
  };
525
866
  }
526
867
  return {
@@ -536,7 +877,10 @@ function createStep(params) {
536
877
  function init(inngest) {
537
878
  return {
538
879
  createWorkflow(params) {
539
- return new InngestWorkflow(params, inngest);
880
+ return new InngestWorkflow(
881
+ params,
882
+ inngest
883
+ );
540
884
  },
541
885
  createStep,
542
886
  cloneStep(step, opts) {
@@ -545,7 +889,13 @@ function init(inngest) {
545
889
  description: step.description,
546
890
  inputSchema: step.inputSchema,
547
891
  outputSchema: step.outputSchema,
548
- execute: step.execute
892
+ resumeSchema: step.resumeSchema,
893
+ suspendSchema: step.suspendSchema,
894
+ stateSchema: step.stateSchema,
895
+ execute: step.execute,
896
+ retries: step.retries,
897
+ scorers: step.scorers,
898
+ component: step.component
549
899
  };
550
900
  },
551
901
  cloneWorkflow(workflow, opts) {
@@ -554,7 +904,8 @@ function init(inngest) {
554
904
  inputSchema: workflow.inputSchema,
555
905
  outputSchema: workflow.outputSchema,
556
906
  steps: workflow.stepDefs,
557
- mastra: workflow.mastra
907
+ mastra: workflow.mastra,
908
+ options: workflow.options
558
909
  });
559
910
  wf.setStepFlow(workflow.stepGraph);
560
911
  wf.commit();
@@ -565,107 +916,32 @@ function init(inngest) {
565
916
  var InngestExecutionEngine = class extends DefaultExecutionEngine {
566
917
  inngestStep;
567
918
  inngestAttempts;
568
- constructor(mastra, inngestStep, inngestAttempts = 0) {
569
- super({ mastra });
919
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
920
+ super({ mastra, options });
570
921
  this.inngestStep = inngestStep;
571
922
  this.inngestAttempts = inngestAttempts;
572
923
  }
573
- async execute(params) {
574
- await params.emitter.emit("watch-v2", {
575
- type: "start",
576
- payload: { runId: params.runId }
577
- });
578
- const result = await super.execute(params);
579
- await params.emitter.emit("watch-v2", {
580
- type: "finish",
581
- payload: { runId: params.runId }
582
- });
583
- return result;
584
- }
585
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
924
+ async fmtReturnValue(emitter, stepResults, lastOutput, error) {
586
925
  const base = {
587
926
  status: lastOutput.status,
588
927
  steps: stepResults
589
928
  };
590
929
  if (lastOutput.status === "success") {
591
- await emitter.emit("watch", {
592
- type: "watch",
593
- payload: {
594
- workflowState: {
595
- status: lastOutput.status,
596
- steps: stepResults,
597
- result: lastOutput.output
598
- }
599
- },
600
- eventTimestamp: Date.now()
601
- });
602
930
  base.result = lastOutput.output;
603
931
  } else if (lastOutput.status === "failed") {
604
932
  base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
605
- await emitter.emit("watch", {
606
- type: "watch",
607
- payload: {
608
- workflowState: {
609
- status: lastOutput.status,
610
- steps: stepResults,
611
- result: null,
612
- error: base.error
613
- }
614
- },
615
- eventTimestamp: Date.now()
616
- });
617
933
  } else if (lastOutput.status === "suspended") {
618
- await emitter.emit("watch", {
619
- type: "watch",
620
- payload: {
621
- workflowState: {
622
- status: lastOutput.status,
623
- steps: stepResults,
624
- result: null,
625
- error: null
626
- }
627
- },
628
- eventTimestamp: Date.now()
629
- });
630
934
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
631
935
  if (stepResult?.status === "suspended") {
632
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
936
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
633
937
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
634
938
  }
635
939
  return [];
636
940
  });
637
941
  base.suspended = suspendedStepIds;
638
942
  }
639
- executionSpan?.end();
640
943
  return base;
641
944
  }
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
945
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
670
946
  // await this.inngestStep.sleep(id, duration);
671
947
  // }
@@ -677,55 +953,85 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
677
953
  stepResults,
678
954
  emitter,
679
955
  abortController,
680
- runtimeContext,
681
- writableStream
956
+ requestContext,
957
+ executionContext,
958
+ writableStream,
959
+ tracingContext
682
960
  }) {
683
961
  let { duration, fn } = entry;
962
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
963
+ type: SpanType.WORKFLOW_SLEEP,
964
+ name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
965
+ attributes: {
966
+ durationMs: duration,
967
+ sleepType: fn ? "dynamic" : "fixed"
968
+ },
969
+ tracingPolicy: this.options?.tracingPolicy
970
+ });
684
971
  if (fn) {
685
972
  const stepCallId = randomUUID();
686
973
  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(
974
+ return await fn(
975
+ createDeprecationProxy(
717
976
  {
718
- prefix: "step",
719
- callId: stepCallId,
720
- name: "sleep",
721
- runId
977
+ runId,
978
+ workflowId,
979
+ mastra: this.mastra,
980
+ requestContext,
981
+ inputData: prevOutput,
982
+ state: executionContext.state,
983
+ setState: (state) => {
984
+ executionContext.state = state;
985
+ },
986
+ retryCount: -1,
987
+ tracingContext: {
988
+ currentSpan: sleepSpan
989
+ },
990
+ getInitData: () => stepResults?.input,
991
+ getStepResult: getStepResult.bind(this, stepResults),
992
+ // TODO: this function shouldn't have suspend probably?
993
+ suspend: async (_suspendPayload) => {
994
+ },
995
+ bail: () => {
996
+ },
997
+ abort: () => {
998
+ abortController?.abort();
999
+ },
1000
+ [EMITTER_SYMBOL]: emitter,
1001
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1002
+ engine: { step: this.inngestStep },
1003
+ abortSignal: abortController?.signal,
1004
+ writer: new ToolStream(
1005
+ {
1006
+ prefix: "workflow-step",
1007
+ callId: stepCallId,
1008
+ name: "sleep",
1009
+ runId
1010
+ },
1011
+ writableStream
1012
+ )
722
1013
  },
723
- writableStream
1014
+ {
1015
+ paramName: "runCount",
1016
+ deprecationMessage: runCountDeprecationMessage,
1017
+ logger: this.logger
1018
+ }
724
1019
  )
725
- });
1020
+ );
1021
+ });
1022
+ sleepSpan?.update({
1023
+ attributes: {
1024
+ durationMs: duration
1025
+ }
726
1026
  });
727
1027
  }
728
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
1028
+ try {
1029
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
1030
+ sleepSpan?.end();
1031
+ } catch (e) {
1032
+ sleepSpan?.error({ error: e });
1033
+ throw e;
1034
+ }
729
1035
  }
730
1036
  async executeSleepUntil({
731
1037
  workflowId,
@@ -735,111 +1041,133 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
735
1041
  stepResults,
736
1042
  emitter,
737
1043
  abortController,
738
- runtimeContext,
739
- writableStream
1044
+ requestContext,
1045
+ executionContext,
1046
+ writableStream,
1047
+ tracingContext
740
1048
  }) {
741
1049
  let { date, fn } = entry;
1050
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
1051
+ type: SpanType.WORKFLOW_SLEEP,
1052
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
1053
+ attributes: {
1054
+ untilDate: date,
1055
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
1056
+ sleepType: fn ? "dynamic" : "fixed"
1057
+ },
1058
+ tracingPolicy: this.options?.tracingPolicy
1059
+ });
742
1060
  if (fn) {
743
1061
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
744
1062
  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(
1063
+ return await fn(
1064
+ createDeprecationProxy(
775
1065
  {
776
- prefix: "step",
777
- callId: stepCallId,
778
- name: "sleep",
779
- runId
1066
+ runId,
1067
+ workflowId,
1068
+ mastra: this.mastra,
1069
+ requestContext,
1070
+ inputData: prevOutput,
1071
+ state: executionContext.state,
1072
+ setState: (state) => {
1073
+ executionContext.state = state;
1074
+ },
1075
+ retryCount: -1,
1076
+ tracingContext: {
1077
+ currentSpan: sleepUntilSpan
1078
+ },
1079
+ getInitData: () => stepResults?.input,
1080
+ getStepResult: getStepResult.bind(this, stepResults),
1081
+ // TODO: this function shouldn't have suspend probably?
1082
+ suspend: async (_suspendPayload) => {
1083
+ },
1084
+ bail: () => {
1085
+ },
1086
+ abort: () => {
1087
+ abortController?.abort();
1088
+ },
1089
+ [EMITTER_SYMBOL]: emitter,
1090
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1091
+ engine: { step: this.inngestStep },
1092
+ abortSignal: abortController?.signal,
1093
+ writer: new ToolStream(
1094
+ {
1095
+ prefix: "workflow-step",
1096
+ callId: stepCallId,
1097
+ name: "sleep",
1098
+ runId
1099
+ },
1100
+ writableStream
1101
+ )
780
1102
  },
781
- writableStream
1103
+ {
1104
+ paramName: "runCount",
1105
+ deprecationMessage: runCountDeprecationMessage,
1106
+ logger: this.logger
1107
+ }
782
1108
  )
783
- });
1109
+ );
1110
+ });
1111
+ if (date && !(date instanceof Date)) {
1112
+ date = new Date(date);
1113
+ }
1114
+ const time = !date ? 0 : date.getTime() - Date.now();
1115
+ sleepUntilSpan?.update({
1116
+ attributes: {
1117
+ durationMs: Math.max(0, time)
1118
+ }
784
1119
  });
785
1120
  }
786
1121
  if (!(date instanceof Date)) {
1122
+ sleepUntilSpan?.end();
787
1123
  return;
788
1124
  }
789
- await this.inngestStep.sleepUntil(entry.id, date);
790
- }
791
- async executeWaitForEvent({ event, timeout }) {
792
- const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
793
- event: `user-event-${event}`,
794
- timeout: timeout ?? 5e3
795
- });
796
- if (eventData === null) {
797
- throw "Timeout waiting for event";
1125
+ try {
1126
+ await this.inngestStep.sleepUntil(entry.id, date);
1127
+ sleepUntilSpan?.end();
1128
+ } catch (e) {
1129
+ sleepUntilSpan?.error({ error: e });
1130
+ throw e;
798
1131
  }
799
- return eventData?.data;
800
1132
  }
801
1133
  async executeStep({
802
1134
  step,
803
1135
  stepResults,
804
1136
  executionContext,
805
1137
  resume,
1138
+ timeTravel,
806
1139
  prevOutput,
807
1140
  emitter,
808
1141
  abortController,
809
- runtimeContext,
810
- writableStream
1142
+ requestContext,
1143
+ tracingContext,
1144
+ writableStream,
1145
+ disableScorers
811
1146
  }) {
1147
+ const stepSpan = tracingContext?.currentSpan?.createChildSpan({
1148
+ name: `workflow step: '${step.id}'`,
1149
+ type: SpanType.WORKFLOW_STEP,
1150
+ input: prevOutput,
1151
+ attributes: {
1152
+ stepId: step.id
1153
+ },
1154
+ tracingPolicy: this.options?.tracingPolicy
1155
+ });
1156
+ const { inputData, validationError } = await validateStepInput({
1157
+ prevOutput,
1158
+ step,
1159
+ validateInputs: this.options?.validateInputs ?? true
1160
+ });
812
1161
  const startedAt = await this.inngestStep.run(
813
1162
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
814
1163
  async () => {
815
1164
  const startedAt2 = Date.now();
816
1165
  await emitter.emit("watch", {
817
- type: "watch",
818
- payload: {
819
- currentStep: {
820
- id: step.id,
821
- status: "running"
822
- },
823
- workflowState: {
824
- status: "running",
825
- steps: {
826
- ...stepResults,
827
- [step.id]: {
828
- status: "running"
829
- }
830
- },
831
- result: null,
832
- error: null
833
- }
834
- },
835
- eventTimestamp: Date.now()
836
- });
837
- await emitter.emit("watch-v2", {
838
- type: "step-start",
1166
+ type: "workflow-step-start",
839
1167
  payload: {
840
1168
  id: step.id,
841
1169
  status: "running",
842
- payload: prevOutput,
1170
+ payload: inputData,
843
1171
  startedAt: startedAt2
844
1172
  }
845
1173
  });
@@ -850,62 +1178,93 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
850
1178
  const isResume = !!resume?.steps?.length;
851
1179
  let result;
852
1180
  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: {
1181
+ const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
1182
+ try {
1183
+ if (isResume) {
1184
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
1185
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1186
+ workflowName: step.id,
1187
+ runId
1188
+ });
1189
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1190
+ function: step.getFunction(),
1191
+ data: {
1192
+ inputData,
1193
+ initialState: executionContext.state ?? snapshot?.value ?? {},
865
1194
  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]]
1195
+ resume: {
1196
+ runId,
1197
+ steps: resume.steps.slice(1),
1198
+ stepResults: snapshot?.context,
1199
+ resumePayload: resume.resumePayload,
1200
+ resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
1201
+ },
1202
+ outputOptions: { includeState: true }
871
1203
  }
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;
1204
+ });
1205
+ result = invokeResp.result;
1206
+ runId = invokeResp.runId;
1207
+ executionContext.state = invokeResp.result.state;
1208
+ } else if (isTimeTravel) {
1209
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1210
+ workflowName: step.id,
1211
+ runId: executionContext.runId
1212
+ }) ?? { context: {} };
1213
+ const timeTravelParams = createTimeTravelExecutionParams({
1214
+ steps: timeTravel.steps.slice(1),
1215
+ inputData: timeTravel.inputData,
1216
+ resumeData: timeTravel.resumeData,
1217
+ context: timeTravel.nestedStepResults?.[step.id] ?? {},
1218
+ nestedStepsContext: timeTravel.nestedStepResults ?? {},
1219
+ snapshot,
1220
+ graph: step.buildExecutionGraph()
1221
+ });
1222
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1223
+ function: step.getFunction(),
1224
+ data: {
1225
+ timeTravel: timeTravelParams,
1226
+ initialState: executionContext.state ?? {},
1227
+ runId: executionContext.runId,
1228
+ outputOptions: { includeState: true }
1229
+ }
1230
+ });
1231
+ result = invokeResp.result;
1232
+ runId = invokeResp.runId;
1233
+ executionContext.state = invokeResp.result.state;
1234
+ } else {
1235
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1236
+ function: step.getFunction(),
1237
+ data: {
1238
+ inputData,
1239
+ initialState: executionContext.state ?? {},
1240
+ outputOptions: { includeState: true }
1241
+ }
1242
+ });
1243
+ result = invokeResp.result;
1244
+ runId = invokeResp.runId;
1245
+ executionContext.state = invokeResp.result.state;
1246
+ }
1247
+ } catch (e) {
1248
+ const errorCause = e?.cause;
1249
+ if (errorCause && typeof errorCause === "object") {
1250
+ result = errorCause;
1251
+ runId = errorCause.runId || randomUUID();
1252
+ } else {
1253
+ runId = randomUUID();
1254
+ result = {
1255
+ status: "failed",
1256
+ error: e instanceof Error ? e : new Error(String(e)),
1257
+ steps: {},
1258
+ input: inputData
1259
+ };
1260
+ }
885
1261
  }
886
1262
  const res = await this.inngestStep.run(
887
1263
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
888
1264
  async () => {
889
1265
  if (result.status === "failed") {
890
1266
  await emitter.emit("watch", {
891
- type: "watch",
892
- payload: {
893
- currentStep: {
894
- id: step.id,
895
- status: "failed",
896
- error: result?.error
897
- },
898
- workflowState: {
899
- status: "running",
900
- steps: stepResults,
901
- result: null,
902
- error: null
903
- }
904
- },
905
- eventTimestamp: Date.now()
906
- });
907
- await emitter.emit("watch-v2", {
908
- type: "step-result",
1267
+ type: "workflow-step-result",
909
1268
  payload: {
910
1269
  id: step.id,
911
1270
  status: "failed",
@@ -920,27 +1279,10 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
920
1279
  return stepRes2?.status === "suspended";
921
1280
  });
922
1281
  for (const [stepName, stepResult] of suspendedSteps) {
923
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1282
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
924
1283
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
925
1284
  await emitter.emit("watch", {
926
- type: "watch",
927
- payload: {
928
- currentStep: {
929
- id: step.id,
930
- status: "suspended",
931
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
932
- },
933
- workflowState: {
934
- status: "running",
935
- steps: stepResults,
936
- result: null,
937
- error: null
938
- }
939
- },
940
- eventTimestamp: Date.now()
941
- });
942
- await emitter.emit("watch-v2", {
943
- type: "step-suspended",
1285
+ type: "workflow-step-suspended",
944
1286
  payload: {
945
1287
  id: step.id,
946
1288
  status: "suspended"
@@ -950,27 +1292,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
950
1292
  executionContext,
951
1293
  result: {
952
1294
  status: "suspended",
953
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1295
+ payload: stepResult.payload,
1296
+ suspendPayload: {
1297
+ ...stepResult?.suspendPayload,
1298
+ __workflow_meta: { runId, path: suspendPath }
1299
+ }
954
1300
  }
955
1301
  };
956
1302
  }
957
- await emitter.emit("watch", {
958
- type: "watch",
959
- payload: {
960
- currentStep: {
961
- id: step.id,
962
- status: "suspended",
963
- payload: {}
964
- },
965
- workflowState: {
966
- status: "running",
967
- steps: stepResults,
968
- result: null,
969
- error: null
970
- }
971
- },
972
- eventTimestamp: Date.now()
973
- });
974
1303
  return {
975
1304
  executionContext,
976
1305
  result: {
@@ -980,32 +1309,15 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
980
1309
  };
981
1310
  }
982
1311
  await emitter.emit("watch", {
983
- type: "watch",
984
- payload: {
985
- currentStep: {
986
- id: step.id,
987
- status: "success",
988
- output: result?.result
989
- },
990
- workflowState: {
991
- status: "running",
992
- steps: stepResults,
993
- result: null,
994
- error: null
995
- }
996
- },
997
- eventTimestamp: Date.now()
998
- });
999
- await emitter.emit("watch-v2", {
1000
- type: "step-result",
1312
+ type: "workflow-step-result",
1001
1313
  payload: {
1002
1314
  id: step.id,
1003
1315
  status: "success",
1004
1316
  output: result?.result
1005
1317
  }
1006
1318
  });
1007
- await emitter.emit("watch-v2", {
1008
- type: "step-finish",
1319
+ await emitter.emit("watch", {
1320
+ type: "workflow-step-finish",
1009
1321
  payload: {
1010
1322
  id: step.id,
1011
1323
  metadata: {}
@@ -1015,136 +1327,232 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1015
1327
  }
1016
1328
  );
1017
1329
  Object.assign(executionContext, res.executionContext);
1018
- return res.result;
1330
+ return {
1331
+ ...res.result,
1332
+ startedAt,
1333
+ endedAt: Date.now(),
1334
+ payload: inputData,
1335
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1336
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1337
+ };
1019
1338
  }
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;
1037
- }
1038
- return null;
1039
- },
1040
- suspend: async (suspendPayload) => {
1041
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1042
- suspended = { payload: suspendPayload };
1043
- },
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
1339
+ const stepCallId = randomUUID();
1340
+ let stepRes;
1341
+ try {
1342
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1343
+ let execResults;
1344
+ let suspended;
1345
+ let bailed;
1346
+ const { resumeData: timeTravelResumeData, validationError: timeTravelResumeValidationError } = await validateStepResumeData({
1347
+ resumeData: timeTravel?.stepResults[step.id]?.status === "suspended" ? timeTravel?.resumeData : void 0,
1348
+ step
1058
1349
  });
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;
1350
+ let resumeDataToUse;
1351
+ if (timeTravelResumeData && !timeTravelResumeValidationError) {
1352
+ resumeDataToUse = timeTravelResumeData;
1353
+ } else if (timeTravelResumeData && timeTravelResumeValidationError) {
1354
+ this.logger.warn("Time travel resume data validation failed", {
1355
+ stepId: step.id,
1356
+ error: timeTravelResumeValidationError.message
1357
+ });
1358
+ } else if (resume?.steps[0] === step.id) {
1359
+ resumeDataToUse = resume?.resumePayload;
1096
1360
  }
1097
- }
1361
+ try {
1362
+ if (validationError) {
1363
+ throw validationError;
1364
+ }
1365
+ const retryCount = this.getOrGenerateRetryCount(step.id);
1366
+ const result = await step.execute({
1367
+ runId: executionContext.runId,
1368
+ workflowId: executionContext.workflowId,
1369
+ mastra: this.mastra,
1370
+ requestContext,
1371
+ retryCount,
1372
+ writer: new ToolStream(
1373
+ {
1374
+ prefix: "workflow-step",
1375
+ callId: stepCallId,
1376
+ name: step.id,
1377
+ runId: executionContext.runId
1378
+ },
1379
+ writableStream
1380
+ ),
1381
+ state: executionContext?.state ?? {},
1382
+ setState: (state) => {
1383
+ executionContext.state = state;
1384
+ },
1385
+ inputData,
1386
+ resumeData: resumeDataToUse,
1387
+ tracingContext: {
1388
+ currentSpan: stepSpan
1389
+ },
1390
+ getInitData: () => stepResults?.input,
1391
+ getStepResult: getStepResult.bind(this, stepResults),
1392
+ suspend: async (suspendPayload, suspendOptions) => {
1393
+ const { suspendData, validationError: validationError2 } = await validateStepSuspendData({
1394
+ suspendData: suspendPayload,
1395
+ step
1396
+ });
1397
+ if (validationError2) {
1398
+ throw validationError2;
1399
+ }
1400
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1401
+ if (suspendOptions?.resumeLabel) {
1402
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1403
+ for (const label of resumeLabel) {
1404
+ executionContext.resumeLabels[label] = {
1405
+ stepId: step.id,
1406
+ foreachIndex: executionContext.foreachIndex
1407
+ };
1408
+ }
1409
+ }
1410
+ suspended = { payload: suspendData };
1411
+ },
1412
+ bail: (result2) => {
1413
+ bailed = { payload: result2 };
1414
+ },
1415
+ abort: () => {
1416
+ abortController?.abort();
1417
+ },
1418
+ [EMITTER_SYMBOL]: emitter,
1419
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1420
+ engine: {
1421
+ step: this.inngestStep
1422
+ },
1423
+ abortSignal: abortController.signal
1424
+ });
1425
+ const endedAt = Date.now();
1426
+ execResults = {
1427
+ status: "success",
1428
+ output: result,
1429
+ startedAt,
1430
+ endedAt,
1431
+ payload: inputData,
1432
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1433
+ resumePayload: resumeDataToUse
1434
+ };
1435
+ } catch (e) {
1436
+ const stepFailure = {
1437
+ status: "failed",
1438
+ payload: inputData,
1439
+ error: e instanceof Error ? e.message : String(e),
1440
+ endedAt: Date.now(),
1441
+ startedAt,
1442
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1443
+ resumePayload: resumeDataToUse
1444
+ };
1445
+ execResults = stepFailure;
1446
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1447
+ stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1448
+ throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1449
+ cause: execResults
1450
+ });
1451
+ }
1452
+ if (suspended) {
1453
+ execResults = {
1454
+ status: "suspended",
1455
+ suspendPayload: suspended.payload,
1456
+ ...execResults.output ? { suspendOutput: execResults.output } : {},
1457
+ payload: inputData,
1458
+ suspendedAt: Date.now(),
1459
+ startedAt,
1460
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1461
+ resumePayload: resumeDataToUse
1462
+ };
1463
+ } else if (bailed) {
1464
+ execResults = {
1465
+ status: "bailed",
1466
+ output: bailed.payload,
1467
+ payload: inputData,
1468
+ endedAt: Date.now(),
1469
+ startedAt
1470
+ };
1471
+ }
1472
+ if (execResults.status === "suspended") {
1473
+ await emitter.emit("watch", {
1474
+ type: "workflow-step-suspended",
1475
+ payload: {
1476
+ id: step.id,
1477
+ ...execResults
1478
+ }
1479
+ });
1480
+ } else {
1481
+ await emitter.emit("watch", {
1482
+ type: "workflow-step-result",
1483
+ payload: {
1484
+ id: step.id,
1485
+ ...execResults
1486
+ }
1487
+ });
1488
+ await emitter.emit("watch", {
1489
+ type: "workflow-step-finish",
1490
+ payload: {
1491
+ id: step.id,
1492
+ metadata: {}
1493
+ }
1494
+ });
1495
+ }
1496
+ stepSpan?.end({ output: execResults });
1497
+ return { result: execResults, executionContext, stepResults };
1498
+ });
1499
+ } catch (e) {
1500
+ const stepFailure = e instanceof Error ? e?.cause : {
1501
+ status: "failed",
1502
+ error: e instanceof Error ? e.message : String(e),
1503
+ payload: inputData,
1504
+ startedAt,
1505
+ endedAt: Date.now()
1506
+ };
1098
1507
  await emitter.emit("watch", {
1099
- type: "watch",
1508
+ type: "workflow-step-result",
1100
1509
  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()
1510
+ id: step.id,
1511
+ ...stepFailure
1512
+ }
1113
1513
  });
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
- });
1514
+ await emitter.emit("watch", {
1515
+ type: "workflow-step-finish",
1516
+ payload: {
1517
+ id: step.id,
1518
+ metadata: {}
1519
+ }
1520
+ });
1521
+ stepRes = {
1522
+ result: stepFailure,
1523
+ executionContext,
1524
+ stepResults: {
1525
+ ...stepResults,
1526
+ [step.id]: stepFailure
1527
+ }
1528
+ };
1529
+ }
1530
+ if (disableScorers !== false && stepRes.result.status === "success") {
1531
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1532
+ if (step.scorers) {
1533
+ await this.runScorers({
1534
+ scorers: step.scorers,
1535
+ runId: executionContext.runId,
1536
+ input: inputData,
1537
+ output: stepRes.result,
1538
+ workflowId: executionContext.workflowId,
1539
+ stepId: step.id,
1540
+ requestContext,
1541
+ disableScorers,
1542
+ tracingContext: { currentSpan: stepSpan }
1543
+ });
1544
+ }
1545
+ });
1546
+ }
1140
1547
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1141
- Object.assign(stepResults, stepRes.stepResults);
1548
+ executionContext.state = stepRes.executionContext.state;
1142
1549
  return stepRes.result;
1143
1550
  }
1144
1551
  async persistStepUpdate({
1145
1552
  workflowId,
1146
1553
  runId,
1147
1554
  stepResults,
1555
+ resourceId,
1148
1556
  executionContext,
1149
1557
  serializedStepGraph,
1150
1558
  workflowStatus,
@@ -1154,20 +1562,27 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1154
1562
  await this.inngestStep.run(
1155
1563
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1156
1564
  async () => {
1565
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1566
+ if (!shouldPersistSnapshot) {
1567
+ return;
1568
+ }
1157
1569
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1158
1570
  workflowName: workflowId,
1159
1571
  runId,
1572
+ resourceId,
1160
1573
  snapshot: {
1161
1574
  runId,
1162
- value: {},
1575
+ status: workflowStatus,
1576
+ value: executionContext.state,
1163
1577
  context: stepResults,
1164
- activePaths: [],
1578
+ activePaths: executionContext.executionPath,
1579
+ activeStepsPath: executionContext.activeStepsPath,
1165
1580
  suspendedPaths: executionContext.suspendedPaths,
1581
+ resumeLabels: executionContext.resumeLabels,
1582
+ waitingPaths: {},
1166
1583
  serializedStepGraph,
1167
- status: workflowStatus,
1168
1584
  result,
1169
1585
  error,
1170
- // @ts-ignore
1171
1586
  timestamp: Date.now()
1172
1587
  }
1173
1588
  });
@@ -1179,112 +1594,182 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1179
1594
  runId,
1180
1595
  entry,
1181
1596
  prevOutput,
1182
- prevStep,
1183
1597
  stepResults,
1184
- serializedStepGraph,
1598
+ timeTravel,
1185
1599
  resume,
1186
1600
  executionContext,
1187
1601
  emitter,
1188
1602
  abortController,
1189
- runtimeContext,
1190
- writableStream
1603
+ requestContext,
1604
+ writableStream,
1605
+ disableScorers,
1606
+ tracingContext
1191
1607
  }) {
1608
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1609
+ type: SpanType.WORKFLOW_CONDITIONAL,
1610
+ name: `conditional: '${entry.conditions.length} conditions'`,
1611
+ input: prevOutput,
1612
+ attributes: {
1613
+ conditionCount: entry.conditions.length
1614
+ },
1615
+ tracingPolicy: this.options?.tracingPolicy
1616
+ });
1192
1617
  let execResults;
1193
1618
  const truthyIndexes = (await Promise.all(
1194
1619
  entry.conditions.map(
1195
1620
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1621
+ const evalSpan = conditionalSpan?.createChildSpan({
1622
+ type: SpanType.WORKFLOW_CONDITIONAL_EVAL,
1623
+ name: `condition: '${index}'`,
1624
+ input: prevOutput,
1625
+ attributes: {
1626
+ conditionIndex: index
1627
+ },
1628
+ tracingPolicy: this.options?.tracingPolicy
1629
+ });
1196
1630
  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(
1631
+ const result = await cond(
1632
+ createDeprecationProxy(
1229
1633
  {
1230
- prefix: "step",
1231
- callId: randomUUID(),
1232
- name: "conditional",
1233
- runId
1634
+ runId,
1635
+ workflowId,
1636
+ mastra: this.mastra,
1637
+ requestContext,
1638
+ retryCount: -1,
1639
+ inputData: prevOutput,
1640
+ state: executionContext.state,
1641
+ setState: (state) => {
1642
+ executionContext.state = state;
1643
+ },
1644
+ tracingContext: {
1645
+ currentSpan: evalSpan
1646
+ },
1647
+ getInitData: () => stepResults?.input,
1648
+ getStepResult: getStepResult.bind(this, stepResults),
1649
+ // TODO: this function shouldn't have suspend probably?
1650
+ suspend: async (_suspendPayload) => {
1651
+ },
1652
+ bail: () => {
1653
+ },
1654
+ abort: () => {
1655
+ abortController.abort();
1656
+ },
1657
+ [EMITTER_SYMBOL]: emitter,
1658
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1659
+ engine: {
1660
+ step: this.inngestStep
1661
+ },
1662
+ abortSignal: abortController.signal,
1663
+ writer: new ToolStream(
1664
+ {
1665
+ prefix: "workflow-step",
1666
+ callId: randomUUID(),
1667
+ name: "conditional",
1668
+ runId
1669
+ },
1670
+ writableStream
1671
+ )
1234
1672
  },
1235
- writableStream
1673
+ {
1674
+ paramName: "runCount",
1675
+ deprecationMessage: runCountDeprecationMessage,
1676
+ logger: this.logger
1677
+ }
1236
1678
  )
1679
+ );
1680
+ evalSpan?.end({
1681
+ output: result,
1682
+ attributes: {
1683
+ result: !!result
1684
+ }
1237
1685
  });
1238
1686
  return result ? index : null;
1239
1687
  } catch (e) {
1688
+ evalSpan?.error({
1689
+ error: e instanceof Error ? e : new Error(String(e)),
1690
+ attributes: {
1691
+ result: false
1692
+ }
1693
+ });
1240
1694
  return null;
1241
1695
  }
1242
1696
  })
1243
1697
  )
1244
1698
  )).filter((index) => index !== null);
1245
1699
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1700
+ conditionalSpan?.update({
1701
+ attributes: {
1702
+ truthyIndexes,
1703
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1704
+ }
1705
+ });
1246
1706
  const results = await Promise.all(
1247
- stepsToRun.map(
1248
- (step, index) => this.executeEntry({
1249
- workflowId,
1250
- runId,
1251
- entry: step,
1252
- prevStep,
1707
+ stepsToRun.map(async (step, index) => {
1708
+ const currStepResult = stepResults[step.step.id];
1709
+ if (currStepResult && currStepResult.status === "success") {
1710
+ return currStepResult;
1711
+ }
1712
+ const result = await this.executeStep({
1713
+ step: step.step,
1714
+ prevOutput,
1253
1715
  stepResults,
1254
1716
  resume,
1255
- serializedStepGraph,
1717
+ timeTravel,
1256
1718
  executionContext: {
1257
1719
  workflowId,
1258
1720
  runId,
1259
1721
  executionPath: [...executionContext.executionPath, index],
1722
+ activeStepsPath: executionContext.activeStepsPath,
1260
1723
  suspendedPaths: executionContext.suspendedPaths,
1724
+ resumeLabels: executionContext.resumeLabels,
1261
1725
  retryConfig: executionContext.retryConfig,
1262
- executionSpan: executionContext.executionSpan
1726
+ state: executionContext.state
1263
1727
  },
1264
1728
  emitter,
1265
1729
  abortController,
1266
- runtimeContext,
1267
- writableStream
1268
- })
1269
- )
1730
+ requestContext,
1731
+ writableStream,
1732
+ disableScorers,
1733
+ tracingContext: {
1734
+ currentSpan: conditionalSpan
1735
+ }
1736
+ });
1737
+ stepResults[step.step.id] = result;
1738
+ return result;
1739
+ })
1270
1740
  );
1271
- const hasFailed = results.find((result) => result.result.status === "failed");
1272
- const hasSuspended = results.find((result) => result.result.status === "suspended");
1741
+ const hasFailed = results.find((result) => result.status === "failed");
1742
+ const hasSuspended = results.find((result) => result.status === "suspended");
1273
1743
  if (hasFailed) {
1274
- execResults = { status: "failed", error: hasFailed.result.error };
1744
+ execResults = { status: "failed", error: hasFailed.error };
1275
1745
  } else if (hasSuspended) {
1276
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1746
+ execResults = {
1747
+ status: "suspended",
1748
+ suspendPayload: hasSuspended.suspendPayload,
1749
+ ...hasSuspended.suspendOutput ? { suspendOutput: hasSuspended.suspendOutput } : {}
1750
+ };
1277
1751
  } else {
1278
1752
  execResults = {
1279
1753
  status: "success",
1280
1754
  output: results.reduce((acc, result, index) => {
1281
- if (result.result.status === "success") {
1282
- acc[stepsToRun[index].step.id] = result.output;
1755
+ if (result.status === "success") {
1756
+ if ("step" in stepsToRun[index]) {
1757
+ acc[stepsToRun[index].step.id] = result.output;
1758
+ }
1283
1759
  }
1284
1760
  return acc;
1285
1761
  }, {})
1286
1762
  };
1287
1763
  }
1764
+ if (execResults.status === "failed") {
1765
+ conditionalSpan?.error({
1766
+ error: new Error(execResults.error)
1767
+ });
1768
+ } else {
1769
+ conditionalSpan?.end({
1770
+ output: execResults.output || execResults
1771
+ });
1772
+ }
1288
1773
  return execResults;
1289
1774
  }
1290
1775
  };