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