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