@mastra/inngest 0.0.0-monorepo-binary-20251013210052 → 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,9 +1,11 @@
1
1
  import { randomUUID } from 'crypto';
2
+ import { ReadableStream, WritableStream } from 'stream/web';
2
3
  import { subscribe } from '@inngest/realtime';
3
- import { wrapMastra, AISpanType } from '@mastra/core/ai-tracing';
4
- 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';
5
7
  import { ToolStream, Tool } from '@mastra/core/tools';
6
- import { Run, Workflow, DefaultExecutionEngine, getStepResult, validateStepInput } from '@mastra/core/workflows';
8
+ import { Run, createTimeTravelExecutionParams, Workflow, DefaultExecutionEngine, createDeprecationProxy, getStepResult, runCountDeprecationMessage, validateStepInput, validateStepResumeData, validateStepSuspendData } from '@mastra/core/workflows';
7
9
  import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
8
10
  import { NonRetriableError, RetryAfterError } from 'inngest';
9
11
  import { serve as serve$1 } from 'inngest/hono';
@@ -16,7 +18,7 @@ function serve({
16
18
  functions: userFunctions = [],
17
19
  registerOptions
18
20
  }) {
19
- const wfs = mastra.getWorkflows();
21
+ const wfs = mastra.listWorkflows();
20
22
  const workflowFunctions = Array.from(
21
23
  new Set(
22
24
  Object.values(wfs).flatMap((wf) => {
@@ -55,11 +57,12 @@ var InngestRun = class extends Run {
55
57
  }
56
58
  async getRunOutput(eventId) {
57
59
  let runs = await this.getRuns(eventId);
60
+ const storage = this.#mastra?.getStorage();
58
61
  while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
59
62
  await new Promise((resolve) => setTimeout(resolve, 1e3));
60
63
  runs = await this.getRuns(eventId);
61
64
  if (runs?.[0]?.status === "Failed") {
62
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
65
+ const snapshot = await storage?.loadWorkflowSnapshot({
63
66
  workflowName: this.workflowId,
64
67
  runId: this.runId
65
68
  });
@@ -68,7 +71,7 @@ var InngestRun = class extends Run {
68
71
  };
69
72
  }
70
73
  if (runs?.[0]?.status === "Cancelled") {
71
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
74
+ const snapshot = await storage?.loadWorkflowSnapshot({
72
75
  workflowName: this.workflowId,
73
76
  runId: this.runId
74
77
  });
@@ -77,38 +80,40 @@ var InngestRun = class extends Run {
77
80
  }
78
81
  return runs?.[0];
79
82
  }
80
- async sendEvent(event, data) {
81
- await this.inngest.send({
82
- name: `user-event-${event}`,
83
- data
84
- });
85
- }
86
83
  async cancel() {
84
+ const storage = this.#mastra?.getStorage();
87
85
  await this.inngest.send({
88
86
  name: `cancel.workflow.${this.workflowId}`,
89
87
  data: {
90
88
  runId: this.runId
91
89
  }
92
90
  });
93
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
91
+ const snapshot = await storage?.loadWorkflowSnapshot({
94
92
  workflowName: this.workflowId,
95
93
  runId: this.runId
96
94
  });
97
95
  if (snapshot) {
98
- await this.#mastra?.storage?.persistWorkflowSnapshot({
96
+ await storage?.persistWorkflowSnapshot({
99
97
  workflowName: this.workflowId,
100
98
  runId: this.runId,
101
99
  resourceId: this.resourceId,
102
100
  snapshot: {
103
101
  ...snapshot,
104
- status: "canceled"
102
+ status: "canceled",
103
+ value: snapshot.value
105
104
  }
106
105
  });
107
106
  }
108
107
  }
109
- async start({
108
+ async start(params) {
109
+ return this._start(params);
110
+ }
111
+ async _start({
110
112
  inputData,
111
- initialState
113
+ initialState,
114
+ outputOptions,
115
+ tracingOptions,
116
+ format
112
117
  }) {
113
118
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
114
119
  workflowName: this.workflowId,
@@ -117,13 +122,15 @@ var InngestRun = class extends Run {
117
122
  snapshot: {
118
123
  runId: this.runId,
119
124
  serializedStepGraph: this.serializedStepGraph,
125
+ status: "running",
120
126
  value: {},
121
127
  context: {},
122
128
  activePaths: [],
123
129
  suspendedPaths: {},
130
+ activeStepsPath: {},
131
+ resumeLabels: {},
124
132
  waitingPaths: {},
125
- timestamp: Date.now(),
126
- status: "running"
133
+ timestamp: Date.now()
127
134
  }
128
135
  });
129
136
  const inputDataToUse = await this._validateInput(inputData);
@@ -134,7 +141,10 @@ var InngestRun = class extends Run {
134
141
  inputData: inputDataToUse,
135
142
  initialState: initialStateToUse,
136
143
  runId: this.runId,
137
- resourceId: this.resourceId
144
+ resourceId: this.resourceId,
145
+ outputOptions,
146
+ tracingOptions,
147
+ format
138
148
  }
139
149
  });
140
150
  const eventId = eventOutput.ids[0];
@@ -163,10 +173,16 @@ var InngestRun = class extends Run {
163
173
  return p;
164
174
  }
165
175
  async _resume(params) {
166
- const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
167
- (step) => typeof step === "string" ? step : step?.id
168
- );
169
- 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({
170
186
  workflowName: this.workflowId,
171
187
  runId: this.runId
172
188
  });
@@ -184,8 +200,7 @@ var InngestRun = class extends Run {
184
200
  steps,
185
201
  stepResults: snapshot?.context,
186
202
  resumePayload: resumeDataToUse,
187
- // @ts-ignore
188
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
203
+ resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
189
204
  }
190
205
  }
191
206
  });
@@ -200,12 +215,103 @@ var InngestRun = class extends Run {
200
215
  }
201
216
  return result;
202
217
  }
203
- 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) {
204
310
  let active = true;
205
311
  const streamPromise = subscribe(
206
312
  {
207
313
  channel: `workflow:${this.workflowId}:${this.runId}`,
208
- topics: [type],
314
+ topics: ["watch"],
209
315
  app: this.inngest
210
316
  },
211
317
  (message) => {
@@ -223,20 +329,35 @@ var InngestRun = class extends Run {
223
329
  });
224
330
  };
225
331
  }
226
- stream({ inputData, runtimeContext } = {}) {
332
+ streamLegacy({ inputData, requestContext } = {}) {
227
333
  const { readable, writable } = new TransformStream();
228
334
  const writer = writable.getWriter();
335
+ void writer.write({
336
+ // @ts-ignore
337
+ type: "start",
338
+ // @ts-ignore
339
+ payload: { runId: this.runId }
340
+ });
229
341
  const unwatch = this.watch(async (event) => {
230
342
  try {
231
343
  const e = {
232
344
  ...event,
233
345
  type: event.type.replace("workflow-", "")
234
346
  };
347
+ if (e.type === "step-output") {
348
+ e.type = e.payload.output.type;
349
+ e.payload = e.payload.output.payload;
350
+ }
235
351
  await writer.write(e);
236
352
  } catch {
237
353
  }
238
- }, "watch-v2");
354
+ });
239
355
  this.closeStreamAction = async () => {
356
+ await writer.write({
357
+ type: "finish",
358
+ // @ts-ignore
359
+ payload: { runId: this.runId }
360
+ });
240
361
  unwatch();
241
362
  try {
242
363
  await writer.close();
@@ -246,7 +367,7 @@ var InngestRun = class extends Run {
246
367
  writer.releaseLock();
247
368
  }
248
369
  };
249
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
370
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
250
371
  if (result.status !== "suspended") {
251
372
  this.closeStreamAction?.().catch(() => {
252
373
  });
@@ -258,6 +379,151 @@ var InngestRun = class extends Run {
258
379
  getWorkflowState: () => this.executionResults
259
380
  };
260
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
+ }
261
527
  };
262
528
  var InngestWorkflow = class _InngestWorkflow extends Workflow {
263
529
  #mastra;
@@ -267,6 +533,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
267
533
  constructor(params, inngest) {
268
534
  const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
269
535
  super(workflowParams);
536
+ this.engineType = "inngest";
270
537
  const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
271
538
  ([_, value]) => value !== void 0
272
539
  );
@@ -274,13 +541,13 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
274
541
  this.#mastra = params.mastra;
275
542
  this.inngest = inngest;
276
543
  }
277
- async getWorkflowRuns(args) {
544
+ async listWorkflowRuns(args) {
278
545
  const storage = this.#mastra?.getStorage();
279
546
  if (!storage) {
280
547
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
281
548
  return { runs: [], total: 0 };
282
549
  }
283
- return storage.getWorkflowRuns({ workflowName: this.id, ...args ?? {} });
550
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
284
551
  }
285
552
  async getWorkflowRunById(runId) {
286
553
  const storage = this.#mastra?.getStorage();
@@ -309,16 +576,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
309
576
  }
310
577
  }
311
578
  }
312
- /**
313
- * @deprecated Use createRunAsync() instead.
314
- * @throws {Error} Always throws an error directing users to use createRunAsync()
315
- */
316
- createRun(_options) {
317
- throw new Error(
318
- "createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
319
- );
320
- }
321
- async createRunAsync(options) {
579
+ async createRun(options) {
322
580
  const runIdToUse = options?.runId || randomUUID();
323
581
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
324
582
  {
@@ -331,7 +589,9 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
331
589
  mastra: this.#mastra,
332
590
  retryConfig: this.retryConfig,
333
591
  cleanup: () => this.runs.delete(runIdToUse),
334
- workflowSteps: this.steps
592
+ workflowSteps: this.steps,
593
+ workflowEngineType: this.engineType,
594
+ validateInputs: this.options.validateInputs
335
595
  },
336
596
  this.inngest
337
597
  );
@@ -352,12 +612,13 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
352
612
  value: {},
353
613
  context: {},
354
614
  activePaths: [],
615
+ activeStepsPath: {},
355
616
  waitingPaths: {},
356
617
  serializedStepGraph: this.serializedStepGraph,
357
618
  suspendedPaths: {},
619
+ resumeLabels: {},
358
620
  result: void 0,
359
621
  error: void 0,
360
- // @ts-ignore
361
622
  timestamp: Date.now()
362
623
  }
363
624
  });
@@ -371,15 +632,14 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
371
632
  this.function = this.inngest.createFunction(
372
633
  {
373
634
  id: `workflow.${this.id}`,
374
- // @ts-ignore
375
- retries: this.retryConfig?.attempts ?? 0,
635
+ retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
376
636
  cancelOn: [{ event: `cancel.workflow.${this.id}` }],
377
637
  // Spread flow control configuration
378
638
  ...this.flowControlConfig
379
639
  },
380
640
  { event: `workflow.${this.id}` },
381
641
  async ({ event, step, attempt, publish }) => {
382
- let { inputData, initialState, runId, resourceId, resume, outputOptions } = event.data;
642
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
383
643
  if (!runId) {
384
644
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
385
645
  return randomUUID();
@@ -418,13 +678,20 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
418
678
  initialState,
419
679
  emitter,
420
680
  retryConfig: this.retryConfig,
421
- runtimeContext: new RuntimeContext(),
681
+ requestContext: new RequestContext(),
422
682
  // TODO
423
683
  resume,
684
+ timeTravel,
685
+ format,
424
686
  abortController: new AbortController(),
425
- currentSpan: void 0,
426
- // TODO: Pass actual parent AI span from workflow execution context
427
- outputOptions
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
+ })
428
695
  });
429
696
  await step.run(`workflow.${this.id}.finalize`, async () => {
430
697
  if (result.status === "failed") {
@@ -462,20 +729,29 @@ function isAgent(params) {
462
729
  function isTool(params) {
463
730
  return params instanceof Tool;
464
731
  }
465
- function createStep(params) {
732
+ function createStep(params, agentOptions) {
466
733
  if (isAgent(params)) {
467
734
  return {
468
735
  id: params.name,
469
736
  description: params.getDescription(),
470
- // @ts-ignore
471
737
  inputSchema: z.object({
472
738
  prompt: z.string()
739
+ // resourceId: z.string().optional(),
740
+ // threadId: z.string().optional(),
473
741
  }),
474
- // @ts-ignore
475
742
  outputSchema: z.object({
476
743
  text: z.string()
477
744
  }),
478
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
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
+ }) => {
479
755
  let streamPromise = {};
480
756
  streamPromise.promise = new Promise((resolve, reject) => {
481
757
  streamPromise.resolve = resolve;
@@ -485,61 +761,60 @@ function createStep(params) {
485
761
  name: params.name,
486
762
  args: inputData
487
763
  };
488
- if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
489
- const { fullStream } = await params.stream(inputData.prompt, {
490
- runtimeContext,
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,
491
771
  tracingContext,
492
772
  onFinish: (result) => {
493
773
  streamPromise.resolve(result.text);
774
+ void agentOptions?.onFinish?.(result);
494
775
  },
495
776
  abortSignal
496
777
  });
497
- if (abortSignal.aborted) {
498
- return abort();
499
- }
500
- await emitter.emit("watch-v2", {
501
- type: "tool-call-streaming-start",
502
- ...toolData ?? {}
503
- });
504
- for await (const chunk of fullStream) {
505
- if (chunk.type === "text-delta") {
506
- await emitter.emit("watch-v2", {
507
- type: "tool-call-delta",
508
- ...toolData ?? {},
509
- argsTextDelta: chunk.payload.text
510
- });
511
- }
512
- }
778
+ stream = fullStream;
513
779
  } else {
514
- const { fullStream } = await params.streamLegacy(inputData.prompt, {
515
- runtimeContext,
780
+ const modelOutput = await params.stream(inputData.prompt, {
781
+ ...agentOptions ?? {},
782
+ requestContext,
516
783
  tracingContext,
517
784
  onFinish: (result) => {
518
785
  streamPromise.resolve(result.text);
786
+ void agentOptions?.onFinish?.(result);
519
787
  },
520
788
  abortSignal
521
789
  });
522
- if (abortSignal.aborted) {
523
- return abort();
524
- }
525
- await emitter.emit("watch-v2", {
790
+ stream = modelOutput.fullStream;
791
+ }
792
+ if (streamFormat === "legacy") {
793
+ await emitter.emit("watch", {
526
794
  type: "tool-call-streaming-start",
527
795
  ...toolData ?? {}
528
796
  });
529
- for await (const chunk of fullStream) {
797
+ for await (const chunk of stream) {
530
798
  if (chunk.type === "text-delta") {
531
- await emitter.emit("watch-v2", {
799
+ await emitter.emit("watch", {
532
800
  type: "tool-call-delta",
533
801
  ...toolData ?? {},
534
802
  argsTextDelta: chunk.textDelta
535
803
  });
536
804
  }
537
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);
813
+ }
814
+ }
815
+ if (abortSignal.aborted) {
816
+ return abort();
538
817
  }
539
- await emitter.emit("watch-v2", {
540
- type: "tool-call-streaming-finish",
541
- ...toolData ?? {}
542
- });
543
818
  return {
544
819
  text: await streamPromise.promise
545
820
  };
@@ -553,20 +828,38 @@ function createStep(params) {
553
828
  }
554
829
  return {
555
830
  // TODO: tool probably should have strong id type
556
- // @ts-ignore
557
831
  id: params.id,
558
832
  description: params.description,
559
833
  inputSchema: params.inputSchema,
560
834
  outputSchema: params.outputSchema,
561
- execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
562
- return params.execute({
563
- context: inputData,
564
- mastra: wrapMastra(mastra, tracingContext),
565
- runtimeContext,
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 = {
850
+ mastra,
851
+ requestContext,
566
852
  tracingContext,
567
- suspend,
568
- resumeData
569
- });
853
+ workflow: {
854
+ runId,
855
+ resumeData,
856
+ suspend,
857
+ workflowId,
858
+ state,
859
+ setState
860
+ }
861
+ };
862
+ return params.execute(inputData, toolContext);
570
863
  },
571
864
  component: "TOOL"
572
865
  };
@@ -600,6 +893,8 @@ function init(inngest) {
600
893
  suspendSchema: step.suspendSchema,
601
894
  stateSchema: step.stateSchema,
602
895
  execute: step.execute,
896
+ retries: step.retries,
897
+ scorers: step.scorers,
603
898
  component: step.component
604
899
  };
605
900
  },
@@ -609,7 +904,8 @@ function init(inngest) {
609
904
  inputSchema: workflow.inputSchema,
610
905
  outputSchema: workflow.outputSchema,
611
906
  steps: workflow.stepDefs,
612
- mastra: workflow.mastra
907
+ mastra: workflow.mastra,
908
+ options: workflow.options
613
909
  });
614
910
  wf.setStepFlow(workflow.stepGraph);
615
911
  wf.commit();
@@ -625,63 +921,16 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
625
921
  this.inngestStep = inngestStep;
626
922
  this.inngestAttempts = inngestAttempts;
627
923
  }
628
- async execute(params) {
629
- await params.emitter.emit("watch-v2", {
630
- type: "workflow-start",
631
- payload: { runId: params.runId }
632
- });
633
- const result = await super.execute(params);
634
- await params.emitter.emit("watch-v2", {
635
- type: "workflow-finish",
636
- payload: { runId: params.runId }
637
- });
638
- return result;
639
- }
640
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
924
+ async fmtReturnValue(emitter, stepResults, lastOutput, error) {
641
925
  const base = {
642
926
  status: lastOutput.status,
643
927
  steps: stepResults
644
928
  };
645
929
  if (lastOutput.status === "success") {
646
- await emitter.emit("watch", {
647
- type: "watch",
648
- payload: {
649
- workflowState: {
650
- status: lastOutput.status,
651
- steps: stepResults,
652
- result: lastOutput.output
653
- }
654
- },
655
- eventTimestamp: Date.now()
656
- });
657
930
  base.result = lastOutput.output;
658
931
  } else if (lastOutput.status === "failed") {
659
932
  base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
660
- await emitter.emit("watch", {
661
- type: "watch",
662
- payload: {
663
- workflowState: {
664
- status: lastOutput.status,
665
- steps: stepResults,
666
- result: null,
667
- error: base.error
668
- }
669
- },
670
- eventTimestamp: Date.now()
671
- });
672
933
  } else if (lastOutput.status === "suspended") {
673
- await emitter.emit("watch", {
674
- type: "watch",
675
- payload: {
676
- workflowState: {
677
- status: lastOutput.status,
678
- steps: stepResults,
679
- result: null,
680
- error: null
681
- }
682
- },
683
- eventTimestamp: Date.now()
684
- });
685
934
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
686
935
  if (stepResult?.status === "suspended") {
687
936
  const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
@@ -691,7 +940,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
691
940
  });
692
941
  base.suspended = suspendedStepIds;
693
942
  }
694
- executionSpan?.end();
695
943
  return base;
696
944
  }
697
945
  // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
@@ -705,14 +953,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
705
953
  stepResults,
706
954
  emitter,
707
955
  abortController,
708
- runtimeContext,
956
+ requestContext,
709
957
  executionContext,
710
958
  writableStream,
711
959
  tracingContext
712
960
  }) {
713
961
  let { duration, fn } = entry;
714
962
  const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
715
- type: AISpanType.WORKFLOW_SLEEP,
963
+ type: SpanType.WORKFLOW_SLEEP,
716
964
  name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
717
965
  attributes: {
718
966
  durationMs: duration,
@@ -723,45 +971,53 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
723
971
  if (fn) {
724
972
  const stepCallId = randomUUID();
725
973
  duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
726
- return await fn({
727
- runId,
728
- workflowId,
729
- mastra: this.mastra,
730
- runtimeContext,
731
- inputData: prevOutput,
732
- state: executionContext.state,
733
- setState: (state) => {
734
- executionContext.state = state;
735
- },
736
- runCount: -1,
737
- tracingContext: {
738
- currentSpan: sleepSpan
739
- },
740
- getInitData: () => stepResults?.input,
741
- getStepResult: getStepResult.bind(this, stepResults),
742
- // TODO: this function shouldn't have suspend probably?
743
- suspend: async (_suspendPayload) => {
744
- },
745
- bail: () => {
746
- },
747
- abort: () => {
748
- abortController?.abort();
749
- },
750
- [EMITTER_SYMBOL]: emitter,
751
- // TODO: add streamVNext support
752
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
753
- engine: { step: this.inngestStep },
754
- abortSignal: abortController?.signal,
755
- writer: new ToolStream(
974
+ return await fn(
975
+ createDeprecationProxy(
756
976
  {
757
- prefix: "workflow-step",
758
- callId: stepCallId,
759
- name: "sleep",
760
- 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
+ )
761
1013
  },
762
- writableStream
1014
+ {
1015
+ paramName: "runCount",
1016
+ deprecationMessage: runCountDeprecationMessage,
1017
+ logger: this.logger
1018
+ }
763
1019
  )
764
- });
1020
+ );
765
1021
  });
766
1022
  sleepSpan?.update({
767
1023
  attributes: {
@@ -785,14 +1041,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
785
1041
  stepResults,
786
1042
  emitter,
787
1043
  abortController,
788
- runtimeContext,
1044
+ requestContext,
789
1045
  executionContext,
790
1046
  writableStream,
791
1047
  tracingContext
792
1048
  }) {
793
1049
  let { date, fn } = entry;
794
1050
  const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
795
- type: AISpanType.WORKFLOW_SLEEP,
1051
+ type: SpanType.WORKFLOW_SLEEP,
796
1052
  name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
797
1053
  attributes: {
798
1054
  untilDate: date,
@@ -804,45 +1060,53 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
804
1060
  if (fn) {
805
1061
  date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
806
1062
  const stepCallId = randomUUID();
807
- return await fn({
808
- runId,
809
- workflowId,
810
- mastra: this.mastra,
811
- runtimeContext,
812
- inputData: prevOutput,
813
- state: executionContext.state,
814
- setState: (state) => {
815
- executionContext.state = state;
816
- },
817
- runCount: -1,
818
- tracingContext: {
819
- currentSpan: sleepUntilSpan
820
- },
821
- getInitData: () => stepResults?.input,
822
- getStepResult: getStepResult.bind(this, stepResults),
823
- // TODO: this function shouldn't have suspend probably?
824
- suspend: async (_suspendPayload) => {
825
- },
826
- bail: () => {
827
- },
828
- abort: () => {
829
- abortController?.abort();
830
- },
831
- [EMITTER_SYMBOL]: emitter,
832
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
833
- // TODO: add streamVNext support
834
- engine: { step: this.inngestStep },
835
- abortSignal: abortController?.signal,
836
- writer: new ToolStream(
1063
+ return await fn(
1064
+ createDeprecationProxy(
837
1065
  {
838
- prefix: "workflow-step",
839
- callId: stepCallId,
840
- name: "sleep",
841
- 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
+ )
842
1102
  },
843
- writableStream
1103
+ {
1104
+ paramName: "runCount",
1105
+ deprecationMessage: runCountDeprecationMessage,
1106
+ logger: this.logger
1107
+ }
844
1108
  )
845
- });
1109
+ );
846
1110
  });
847
1111
  if (date && !(date instanceof Date)) {
848
1112
  date = new Date(date);
@@ -866,32 +1130,23 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
866
1130
  throw e;
867
1131
  }
868
1132
  }
869
- async executeWaitForEvent({ event, timeout }) {
870
- const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
871
- event: `user-event-${event}`,
872
- timeout: timeout ?? 5e3
873
- });
874
- if (eventData === null) {
875
- throw "Timeout waiting for event";
876
- }
877
- return eventData?.data;
878
- }
879
1133
  async executeStep({
880
1134
  step,
881
1135
  stepResults,
882
1136
  executionContext,
883
1137
  resume,
1138
+ timeTravel,
884
1139
  prevOutput,
885
1140
  emitter,
886
1141
  abortController,
887
- runtimeContext,
1142
+ requestContext,
888
1143
  tracingContext,
889
1144
  writableStream,
890
1145
  disableScorers
891
1146
  }) {
892
- const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
1147
+ const stepSpan = tracingContext?.currentSpan?.createChildSpan({
893
1148
  name: `workflow step: '${step.id}'`,
894
- type: AISpanType.WORKFLOW_STEP,
1149
+ type: SpanType.WORKFLOW_STEP,
895
1150
  input: prevOutput,
896
1151
  attributes: {
897
1152
  stepId: step.id
@@ -901,34 +1156,13 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
901
1156
  const { inputData, validationError } = await validateStepInput({
902
1157
  prevOutput,
903
1158
  step,
904
- validateInputs: this.options?.validateInputs ?? false
1159
+ validateInputs: this.options?.validateInputs ?? true
905
1160
  });
906
1161
  const startedAt = await this.inngestStep.run(
907
1162
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
908
1163
  async () => {
909
1164
  const startedAt2 = Date.now();
910
1165
  await emitter.emit("watch", {
911
- type: "watch",
912
- payload: {
913
- currentStep: {
914
- id: step.id,
915
- status: "running"
916
- },
917
- workflowState: {
918
- status: "running",
919
- steps: {
920
- ...stepResults,
921
- [step.id]: {
922
- status: "running"
923
- }
924
- },
925
- result: null,
926
- error: null
927
- }
928
- },
929
- eventTimestamp: Date.now()
930
- });
931
- await emitter.emit("watch-v2", {
932
1166
  type: "workflow-step-start",
933
1167
  payload: {
934
1168
  id: step.id,
@@ -944,9 +1178,10 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
944
1178
  const isResume = !!resume?.steps?.length;
945
1179
  let result;
946
1180
  let runId;
1181
+ const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
947
1182
  try {
948
1183
  if (isResume) {
949
- runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
1184
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
950
1185
  const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
951
1186
  workflowName: step.id,
952
1187
  runId
@@ -962,8 +1197,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
962
1197
  steps: resume.steps.slice(1),
963
1198
  stepResults: snapshot?.context,
964
1199
  resumePayload: resume.resumePayload,
965
- // @ts-ignore
966
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1200
+ resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
967
1201
  },
968
1202
  outputOptions: { includeState: true }
969
1203
  }
@@ -971,6 +1205,32 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
971
1205
  result = invokeResp.result;
972
1206
  runId = invokeResp.runId;
973
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;
974
1234
  } else {
975
1235
  const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
976
1236
  function: step.getFunction(),
@@ -1004,23 +1264,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1004
1264
  async () => {
1005
1265
  if (result.status === "failed") {
1006
1266
  await emitter.emit("watch", {
1007
- type: "watch",
1008
- payload: {
1009
- currentStep: {
1010
- id: step.id,
1011
- status: "failed",
1012
- error: result?.error
1013
- },
1014
- workflowState: {
1015
- status: "running",
1016
- steps: stepResults,
1017
- result: null,
1018
- error: null
1019
- }
1020
- },
1021
- eventTimestamp: Date.now()
1022
- });
1023
- await emitter.emit("watch-v2", {
1024
1267
  type: "workflow-step-result",
1025
1268
  payload: {
1026
1269
  id: step.id,
@@ -1039,27 +1282,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1039
1282
  const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
1040
1283
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1041
1284
  await emitter.emit("watch", {
1042
- type: "watch",
1043
- payload: {
1044
- currentStep: {
1045
- id: step.id,
1046
- status: "suspended",
1047
- payload: stepResult.payload,
1048
- suspendPayload: {
1049
- ...stepResult?.suspendPayload,
1050
- __workflow_meta: { runId, path: suspendPath }
1051
- }
1052
- },
1053
- workflowState: {
1054
- status: "running",
1055
- steps: stepResults,
1056
- result: null,
1057
- error: null
1058
- }
1059
- },
1060
- eventTimestamp: Date.now()
1061
- });
1062
- await emitter.emit("watch-v2", {
1063
1285
  type: "workflow-step-suspended",
1064
1286
  payload: {
1065
1287
  id: step.id,
@@ -1078,23 +1300,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1078
1300
  }
1079
1301
  };
1080
1302
  }
1081
- await emitter.emit("watch", {
1082
- type: "watch",
1083
- payload: {
1084
- currentStep: {
1085
- id: step.id,
1086
- status: "suspended",
1087
- payload: {}
1088
- },
1089
- workflowState: {
1090
- status: "running",
1091
- steps: stepResults,
1092
- result: null,
1093
- error: null
1094
- }
1095
- },
1096
- eventTimestamp: Date.now()
1097
- });
1098
1303
  return {
1099
1304
  executionContext,
1100
1305
  result: {
@@ -1104,23 +1309,6 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1104
1309
  };
1105
1310
  }
1106
1311
  await emitter.emit("watch", {
1107
- type: "watch",
1108
- payload: {
1109
- currentStep: {
1110
- id: step.id,
1111
- status: "success",
1112
- output: result?.result
1113
- },
1114
- workflowState: {
1115
- status: "running",
1116
- steps: stepResults,
1117
- result: null,
1118
- error: null
1119
- }
1120
- },
1121
- eventTimestamp: Date.now()
1122
- });
1123
- await emitter.emit("watch-v2", {
1124
1312
  type: "workflow-step-result",
1125
1313
  payload: {
1126
1314
  id: step.id,
@@ -1128,7 +1316,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1128
1316
  output: result?.result
1129
1317
  }
1130
1318
  });
1131
- await emitter.emit("watch-v2", {
1319
+ await emitter.emit("watch", {
1132
1320
  type: "workflow-step-finish",
1133
1321
  payload: {
1134
1322
  id: step.id,
@@ -1148,46 +1336,87 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1148
1336
  resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1149
1337
  };
1150
1338
  }
1339
+ const stepCallId = randomUUID();
1151
1340
  let stepRes;
1152
1341
  try {
1153
1342
  stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1154
1343
  let execResults;
1155
1344
  let suspended;
1156
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
1349
+ });
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;
1360
+ }
1157
1361
  try {
1158
1362
  if (validationError) {
1159
1363
  throw validationError;
1160
1364
  }
1365
+ const retryCount = this.getOrGenerateRetryCount(step.id);
1161
1366
  const result = await step.execute({
1162
1367
  runId: executionContext.runId,
1368
+ workflowId: executionContext.workflowId,
1163
1369
  mastra: this.mastra,
1164
- runtimeContext,
1165
- writableStream,
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
+ ),
1166
1381
  state: executionContext?.state ?? {},
1167
1382
  setState: (state) => {
1168
1383
  executionContext.state = state;
1169
1384
  },
1170
1385
  inputData,
1171
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1386
+ resumeData: resumeDataToUse,
1172
1387
  tracingContext: {
1173
- currentSpan: stepAISpan
1388
+ currentSpan: stepSpan
1174
1389
  },
1175
1390
  getInitData: () => stepResults?.input,
1176
1391
  getStepResult: getStepResult.bind(this, stepResults),
1177
- suspend: async (suspendPayload) => {
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
+ }
1178
1400
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1179
- suspended = { payload: suspendPayload };
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 };
1180
1411
  },
1181
1412
  bail: (result2) => {
1182
1413
  bailed = { payload: result2 };
1183
1414
  },
1184
- resume: {
1185
- steps: resume?.steps?.slice(1) || [],
1186
- resumePayload: resume?.resumePayload,
1187
- // @ts-ignore
1188
- runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1415
+ abort: () => {
1416
+ abortController?.abort();
1189
1417
  },
1190
1418
  [EMITTER_SYMBOL]: emitter,
1419
+ [STREAM_FORMAT_SYMBOL]: executionContext.format,
1191
1420
  engine: {
1192
1421
  step: this.inngestStep
1193
1422
  },
@@ -1200,8 +1429,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1200
1429
  startedAt,
1201
1430
  endedAt,
1202
1431
  payload: inputData,
1203
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1204
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1432
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1433
+ resumePayload: resumeDataToUse
1205
1434
  };
1206
1435
  } catch (e) {
1207
1436
  const stepFailure = {
@@ -1210,12 +1439,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1210
1439
  error: e instanceof Error ? e.message : String(e),
1211
1440
  endedAt: Date.now(),
1212
1441
  startedAt,
1213
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1214
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1442
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1443
+ resumePayload: resumeDataToUse
1215
1444
  };
1216
1445
  execResults = stepFailure;
1217
1446
  const fallbackErrorMessage = `Step ${step.id} failed`;
1218
- stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1447
+ stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1219
1448
  throw new RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1220
1449
  cause: execResults
1221
1450
  });
@@ -1224,11 +1453,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1224
1453
  execResults = {
1225
1454
  status: "suspended",
1226
1455
  suspendPayload: suspended.payload,
1456
+ ...execResults.output ? { suspendOutput: execResults.output } : {},
1227
1457
  payload: inputData,
1228
1458
  suspendedAt: Date.now(),
1229
1459
  startedAt,
1230
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1231
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1460
+ resumedAt: resumeDataToUse ? startedAt : void 0,
1461
+ resumePayload: resumeDataToUse
1232
1462
  };
1233
1463
  } else if (bailed) {
1234
1464
  execResults = {
@@ -1239,24 +1469,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1239
1469
  startedAt
1240
1470
  };
1241
1471
  }
1242
- await emitter.emit("watch", {
1243
- type: "watch",
1244
- payload: {
1245
- currentStep: {
1246
- id: step.id,
1247
- ...execResults
1248
- },
1249
- workflowState: {
1250
- status: "running",
1251
- steps: { ...stepResults, [step.id]: execResults },
1252
- result: null,
1253
- error: null
1254
- }
1255
- },
1256
- eventTimestamp: Date.now()
1257
- });
1258
1472
  if (execResults.status === "suspended") {
1259
- await emitter.emit("watch-v2", {
1473
+ await emitter.emit("watch", {
1260
1474
  type: "workflow-step-suspended",
1261
1475
  payload: {
1262
1476
  id: step.id,
@@ -1264,14 +1478,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1264
1478
  }
1265
1479
  });
1266
1480
  } else {
1267
- await emitter.emit("watch-v2", {
1481
+ await emitter.emit("watch", {
1268
1482
  type: "workflow-step-result",
1269
1483
  payload: {
1270
1484
  id: step.id,
1271
1485
  ...execResults
1272
1486
  }
1273
1487
  });
1274
- await emitter.emit("watch-v2", {
1488
+ await emitter.emit("watch", {
1275
1489
  type: "workflow-step-finish",
1276
1490
  payload: {
1277
1491
  id: step.id,
@@ -1279,7 +1493,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1279
1493
  }
1280
1494
  });
1281
1495
  }
1282
- stepAISpan?.end({ output: execResults });
1496
+ stepSpan?.end({ output: execResults });
1283
1497
  return { result: execResults, executionContext, stepResults };
1284
1498
  });
1285
1499
  } catch (e) {
@@ -1290,6 +1504,20 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1290
1504
  startedAt,
1291
1505
  endedAt: Date.now()
1292
1506
  };
1507
+ await emitter.emit("watch", {
1508
+ type: "workflow-step-result",
1509
+ payload: {
1510
+ id: step.id,
1511
+ ...stepFailure
1512
+ }
1513
+ });
1514
+ await emitter.emit("watch", {
1515
+ type: "workflow-step-finish",
1516
+ payload: {
1517
+ id: step.id,
1518
+ metadata: {}
1519
+ }
1520
+ });
1293
1521
  stepRes = {
1294
1522
  result: stepFailure,
1295
1523
  executionContext,
@@ -1309,15 +1537,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1309
1537
  output: stepRes.result,
1310
1538
  workflowId: executionContext.workflowId,
1311
1539
  stepId: step.id,
1312
- runtimeContext,
1540
+ requestContext,
1313
1541
  disableScorers,
1314
- tracingContext: { currentSpan: stepAISpan }
1542
+ tracingContext: { currentSpan: stepSpan }
1315
1543
  });
1316
1544
  }
1317
1545
  });
1318
1546
  }
1319
1547
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1320
- Object.assign(stepResults, stepRes.stepResults);
1321
1548
  executionContext.state = stepRes.executionContext.state;
1322
1549
  return stepRes.result;
1323
1550
  }
@@ -1345,16 +1572,17 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1345
1572
  resourceId,
1346
1573
  snapshot: {
1347
1574
  runId,
1575
+ status: workflowStatus,
1348
1576
  value: executionContext.state,
1349
1577
  context: stepResults,
1350
- activePaths: [],
1578
+ activePaths: executionContext.executionPath,
1579
+ activeStepsPath: executionContext.activeStepsPath,
1351
1580
  suspendedPaths: executionContext.suspendedPaths,
1581
+ resumeLabels: executionContext.resumeLabels,
1352
1582
  waitingPaths: {},
1353
1583
  serializedStepGraph,
1354
- status: workflowStatus,
1355
1584
  result,
1356
1585
  error,
1357
- // @ts-ignore
1358
1586
  timestamp: Date.now()
1359
1587
  }
1360
1588
  });
@@ -1366,20 +1594,19 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1366
1594
  runId,
1367
1595
  entry,
1368
1596
  prevOutput,
1369
- prevStep,
1370
1597
  stepResults,
1371
- serializedStepGraph,
1598
+ timeTravel,
1372
1599
  resume,
1373
1600
  executionContext,
1374
1601
  emitter,
1375
1602
  abortController,
1376
- runtimeContext,
1603
+ requestContext,
1377
1604
  writableStream,
1378
1605
  disableScorers,
1379
1606
  tracingContext
1380
1607
  }) {
1381
1608
  const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1382
- type: AISpanType.WORKFLOW_CONDITIONAL,
1609
+ type: SpanType.WORKFLOW_CONDITIONAL,
1383
1610
  name: `conditional: '${entry.conditions.length} conditions'`,
1384
1611
  input: prevOutput,
1385
1612
  attributes: {
@@ -1392,7 +1619,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1392
1619
  entry.conditions.map(
1393
1620
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1394
1621
  const evalSpan = conditionalSpan?.createChildSpan({
1395
- type: AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1622
+ type: SpanType.WORKFLOW_CONDITIONAL_EVAL,
1396
1623
  name: `condition: '${index}'`,
1397
1624
  input: prevOutput,
1398
1625
  attributes: {
@@ -1401,47 +1628,55 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1401
1628
  tracingPolicy: this.options?.tracingPolicy
1402
1629
  });
1403
1630
  try {
1404
- const result = await cond({
1405
- runId,
1406
- workflowId,
1407
- mastra: this.mastra,
1408
- runtimeContext,
1409
- runCount: -1,
1410
- inputData: prevOutput,
1411
- state: executionContext.state,
1412
- setState: (state) => {
1413
- executionContext.state = state;
1414
- },
1415
- tracingContext: {
1416
- currentSpan: evalSpan
1417
- },
1418
- getInitData: () => stepResults?.input,
1419
- getStepResult: getStepResult.bind(this, stepResults),
1420
- // TODO: this function shouldn't have suspend probably?
1421
- suspend: async (_suspendPayload) => {
1422
- },
1423
- bail: () => {
1424
- },
1425
- abort: () => {
1426
- abortController.abort();
1427
- },
1428
- [EMITTER_SYMBOL]: emitter,
1429
- [STREAM_FORMAT_SYMBOL]: executionContext.format,
1430
- // TODO: add streamVNext support
1431
- engine: {
1432
- step: this.inngestStep
1433
- },
1434
- abortSignal: abortController.signal,
1435
- writer: new ToolStream(
1631
+ const result = await cond(
1632
+ createDeprecationProxy(
1436
1633
  {
1437
- prefix: "workflow-step",
1438
- callId: randomUUID(),
1439
- name: "conditional",
1440
- 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
+ )
1441
1672
  },
1442
- writableStream
1673
+ {
1674
+ paramName: "runCount",
1675
+ deprecationMessage: runCountDeprecationMessage,
1676
+ logger: this.logger
1677
+ }
1443
1678
  )
1444
- });
1679
+ );
1445
1680
  evalSpan?.end({
1446
1681
  output: result,
1447
1682
  attributes: {
@@ -1469,47 +1704,58 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
1469
1704
  }
1470
1705
  });
1471
1706
  const results = await Promise.all(
1472
- stepsToRun.map(
1473
- (step, index) => this.executeEntry({
1474
- workflowId,
1475
- runId,
1476
- entry: step,
1477
- serializedStepGraph,
1478
- 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,
1479
1715
  stepResults,
1480
1716
  resume,
1717
+ timeTravel,
1481
1718
  executionContext: {
1482
1719
  workflowId,
1483
1720
  runId,
1484
1721
  executionPath: [...executionContext.executionPath, index],
1722
+ activeStepsPath: executionContext.activeStepsPath,
1485
1723
  suspendedPaths: executionContext.suspendedPaths,
1724
+ resumeLabels: executionContext.resumeLabels,
1486
1725
  retryConfig: executionContext.retryConfig,
1487
- executionSpan: executionContext.executionSpan,
1488
1726
  state: executionContext.state
1489
1727
  },
1490
1728
  emitter,
1491
1729
  abortController,
1492
- runtimeContext,
1730
+ requestContext,
1493
1731
  writableStream,
1494
1732
  disableScorers,
1495
1733
  tracingContext: {
1496
1734
  currentSpan: conditionalSpan
1497
1735
  }
1498
- })
1499
- )
1736
+ });
1737
+ stepResults[step.step.id] = result;
1738
+ return result;
1739
+ })
1500
1740
  );
1501
- const hasFailed = results.find((result) => result.result.status === "failed");
1502
- 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");
1503
1743
  if (hasFailed) {
1504
- execResults = { status: "failed", error: hasFailed.result.error };
1744
+ execResults = { status: "failed", error: hasFailed.error };
1505
1745
  } else if (hasSuspended) {
1506
- execResults = { status: "suspended", suspendPayload: hasSuspended.result.suspendPayload };
1746
+ execResults = {
1747
+ status: "suspended",
1748
+ suspendPayload: hasSuspended.suspendPayload,
1749
+ ...hasSuspended.suspendOutput ? { suspendOutput: hasSuspended.suspendOutput } : {}
1750
+ };
1507
1751
  } else {
1508
1752
  execResults = {
1509
1753
  status: "success",
1510
1754
  output: results.reduce((acc, result, index) => {
1511
- if (result.result.status === "success") {
1512
- 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
+ }
1513
1759
  }
1514
1760
  return acc;
1515
1761
  }, {})