@mastra/inngest 0.0.0-share-agent-metadata-with-cloud-20250718123411 → 0.0.0-span-scorring-test-20251124132129

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