@mastra/inngest 0.0.0-feat-tool-input-validation-20250731232758 → 0.0.0-feat-improve-processors-20251205191721

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,33 +1,322 @@
1
1
  'use strict';
2
2
 
3
- var crypto = require('crypto');
4
- var realtime = require('@inngest/realtime');
5
- var di = require('@mastra/core/di');
6
3
  var tools = require('@mastra/core/tools');
7
4
  var workflows = require('@mastra/core/workflows');
8
5
  var _constants = require('@mastra/core/workflows/_constants');
9
- var hono = require('inngest/hono');
10
6
  var zod = require('zod');
7
+ var crypto = require('crypto');
8
+ var web = require('stream/web');
9
+ var di = require('@mastra/core/di');
10
+ var inngest = require('inngest');
11
+ var realtime = require('@inngest/realtime');
12
+ var stream = require('@mastra/core/stream');
13
+ var hono = require('inngest/hono');
11
14
 
12
15
  // src/index.ts
13
- function serve({ mastra, inngest }) {
14
- const wfs = mastra.getWorkflows();
15
- const functions = Array.from(
16
- new Set(
17
- Object.values(wfs).flatMap((wf) => {
18
- if (wf instanceof InngestWorkflow) {
19
- wf.__registerMastra(mastra);
20
- return wf.getFunctions();
16
+ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
17
+ inngestStep;
18
+ inngestAttempts;
19
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
20
+ super({ mastra, options });
21
+ this.inngestStep = inngestStep;
22
+ this.inngestAttempts = inngestAttempts;
23
+ }
24
+ // =============================================================================
25
+ // Hook Overrides
26
+ // =============================================================================
27
+ /**
28
+ * Format errors with stack traces for better debugging in Inngest
29
+ */
30
+ formatResultError(error, lastOutput) {
31
+ if (error instanceof Error) {
32
+ return error.stack ?? error.message;
33
+ }
34
+ const outputError = lastOutput?.error;
35
+ if (outputError instanceof Error) {
36
+ return outputError.message;
37
+ }
38
+ return outputError ?? error ?? "Unknown error";
39
+ }
40
+ /**
41
+ * Detect InngestWorkflow instances for special nested workflow handling
42
+ */
43
+ isNestedWorkflowStep(step) {
44
+ return step instanceof InngestWorkflow;
45
+ }
46
+ /**
47
+ * Inngest requires requestContext serialization for memoization.
48
+ * When steps are replayed, the original function doesn't re-execute,
49
+ * so requestContext modifications must be captured and restored.
50
+ */
51
+ requiresDurableContextSerialization() {
52
+ return true;
53
+ }
54
+ /**
55
+ * Execute a step with retry logic for Inngest.
56
+ * Retries are handled via step-level retry (RetryAfterError thrown INSIDE step.run()).
57
+ * After retries exhausted, error propagates here and we return a failed result.
58
+ */
59
+ async executeStepWithRetry(stepId, runStep, params) {
60
+ try {
61
+ const result = await this.wrapDurableOperation(stepId, runStep, { delay: params.delay });
62
+ return { ok: true, result };
63
+ } catch (e) {
64
+ const cause = e?.cause;
65
+ if (cause?.status === "failed") {
66
+ params.stepSpan?.error({
67
+ error: e,
68
+ attributes: { status: "failed" }
69
+ });
70
+ return { ok: false, error: cause };
71
+ }
72
+ const errorMessage = e instanceof Error ? e.message : String(e);
73
+ params.stepSpan?.error({
74
+ error: e,
75
+ attributes: { status: "failed" }
76
+ });
77
+ return {
78
+ ok: false,
79
+ error: {
80
+ status: "failed",
81
+ error: `Error: ${errorMessage}`,
82
+ endedAt: Date.now()
21
83
  }
22
- return [];
23
- })
24
- )
25
- );
26
- return hono.serve({
27
- client: inngest,
28
- functions
29
- });
30
- }
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * Use Inngest's sleep primitive for durability
89
+ */
90
+ async executeSleepDuration(duration, sleepId, workflowId) {
91
+ await this.inngestStep.sleep(`workflow.${workflowId}.sleep.${sleepId}`, duration < 0 ? 0 : duration);
92
+ }
93
+ /**
94
+ * Use Inngest's sleepUntil primitive for durability
95
+ */
96
+ async executeSleepUntilDate(date, sleepUntilId, workflowId) {
97
+ await this.inngestStep.sleepUntil(`workflow.${workflowId}.sleepUntil.${sleepUntilId}`, date);
98
+ }
99
+ /**
100
+ * Wrap durable operations in Inngest step.run() for durability.
101
+ * If retryConfig is provided, throws RetryAfterError INSIDE step.run() to trigger
102
+ * Inngest's step-level retry mechanism (not function-level retry).
103
+ */
104
+ async wrapDurableOperation(operationId, operationFn, retryConfig) {
105
+ return this.inngestStep.run(operationId, async () => {
106
+ try {
107
+ return await operationFn();
108
+ } catch (e) {
109
+ if (retryConfig) {
110
+ const errorMessage = e instanceof Error ? e.message : String(e);
111
+ throw new inngest.RetryAfterError(errorMessage, retryConfig.delay, {
112
+ cause: {
113
+ status: "failed",
114
+ error: `Error: ${errorMessage}`,
115
+ endedAt: Date.now()
116
+ }
117
+ });
118
+ }
119
+ throw e;
120
+ }
121
+ });
122
+ }
123
+ /**
124
+ * Provide Inngest step primitive in engine context
125
+ */
126
+ getEngineContext() {
127
+ return { step: this.inngestStep };
128
+ }
129
+ /**
130
+ * Execute nested InngestWorkflow using inngestStep.invoke() for durability.
131
+ * This MUST be called directly (not inside step.run()) due to Inngest constraints.
132
+ */
133
+ async executeWorkflowStep(params) {
134
+ if (!(params.step instanceof InngestWorkflow)) {
135
+ return null;
136
+ }
137
+ const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, emitter, startedAt } = params;
138
+ const isResume = !!resume?.steps?.length;
139
+ let result;
140
+ let runId;
141
+ const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
142
+ try {
143
+ if (isResume) {
144
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
145
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
146
+ workflowName: step.id,
147
+ runId
148
+ });
149
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
150
+ function: step.getFunction(),
151
+ data: {
152
+ inputData,
153
+ initialState: executionContext.state ?? snapshot?.value ?? {},
154
+ runId,
155
+ resume: {
156
+ runId,
157
+ steps: resume.steps.slice(1),
158
+ stepResults: snapshot?.context,
159
+ resumePayload: resume.resumePayload,
160
+ resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
161
+ },
162
+ outputOptions: { includeState: true }
163
+ }
164
+ });
165
+ result = invokeResp.result;
166
+ runId = invokeResp.runId;
167
+ executionContext.state = invokeResp.result.state;
168
+ } else if (isTimeTravel) {
169
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
170
+ workflowName: step.id,
171
+ runId: executionContext.runId
172
+ }) ?? { context: {} };
173
+ const timeTravelParams = workflows.createTimeTravelExecutionParams({
174
+ steps: timeTravel.steps.slice(1),
175
+ inputData: timeTravel.inputData,
176
+ resumeData: timeTravel.resumeData,
177
+ context: timeTravel.nestedStepResults?.[step.id] ?? {},
178
+ nestedStepsContext: timeTravel.nestedStepResults ?? {},
179
+ snapshot,
180
+ graph: step.buildExecutionGraph()
181
+ });
182
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
183
+ function: step.getFunction(),
184
+ data: {
185
+ timeTravel: timeTravelParams,
186
+ initialState: executionContext.state ?? {},
187
+ runId: executionContext.runId,
188
+ outputOptions: { includeState: true }
189
+ }
190
+ });
191
+ result = invokeResp.result;
192
+ runId = invokeResp.runId;
193
+ executionContext.state = invokeResp.result.state;
194
+ } else {
195
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
196
+ function: step.getFunction(),
197
+ data: {
198
+ inputData,
199
+ initialState: executionContext.state ?? {},
200
+ outputOptions: { includeState: true }
201
+ }
202
+ });
203
+ result = invokeResp.result;
204
+ runId = invokeResp.runId;
205
+ executionContext.state = invokeResp.result.state;
206
+ }
207
+ } catch (e) {
208
+ const errorCause = e?.cause;
209
+ if (errorCause && typeof errorCause === "object") {
210
+ result = errorCause;
211
+ runId = errorCause.runId || crypto.randomUUID();
212
+ } else {
213
+ runId = crypto.randomUUID();
214
+ result = {
215
+ status: "failed",
216
+ error: e instanceof Error ? e : new Error(String(e)),
217
+ steps: {},
218
+ input: inputData
219
+ };
220
+ }
221
+ }
222
+ const res = await this.inngestStep.run(
223
+ `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
224
+ async () => {
225
+ if (result.status === "failed") {
226
+ await emitter.emit("watch", {
227
+ type: "workflow-step-result",
228
+ payload: {
229
+ id: step.id,
230
+ status: "failed",
231
+ error: result?.error,
232
+ payload: prevOutput
233
+ }
234
+ });
235
+ return { executionContext, result: { status: "failed", error: result?.error } };
236
+ } else if (result.status === "suspended") {
237
+ const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
238
+ const stepRes = stepResult;
239
+ return stepRes?.status === "suspended";
240
+ });
241
+ for (const [stepName, stepResult] of suspendedSteps) {
242
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
243
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
244
+ await emitter.emit("watch", {
245
+ type: "workflow-step-suspended",
246
+ payload: {
247
+ id: step.id,
248
+ status: "suspended"
249
+ }
250
+ });
251
+ return {
252
+ executionContext,
253
+ result: {
254
+ status: "suspended",
255
+ payload: stepResult.payload,
256
+ suspendPayload: {
257
+ ...stepResult?.suspendPayload,
258
+ __workflow_meta: { runId, path: suspendPath }
259
+ }
260
+ }
261
+ };
262
+ }
263
+ return {
264
+ executionContext,
265
+ result: {
266
+ status: "suspended",
267
+ payload: {}
268
+ }
269
+ };
270
+ } else if (result.status === "tripwire") {
271
+ await emitter.emit("watch", {
272
+ type: "workflow-step-result",
273
+ payload: {
274
+ id: step.id,
275
+ status: "tripwire",
276
+ error: result?.reason,
277
+ payload: prevOutput
278
+ }
279
+ });
280
+ return {
281
+ executionContext,
282
+ result: {
283
+ status: "tripwire",
284
+ reason: result?.reason,
285
+ retry: result?.retry,
286
+ metadata: result?.metadata,
287
+ processorId: result?.processorId
288
+ }
289
+ };
290
+ }
291
+ await emitter.emit("watch", {
292
+ type: "workflow-step-result",
293
+ payload: {
294
+ id: step.id,
295
+ status: "success",
296
+ output: result?.result
297
+ }
298
+ });
299
+ await emitter.emit("watch", {
300
+ type: "workflow-step-finish",
301
+ payload: {
302
+ id: step.id,
303
+ metadata: {}
304
+ }
305
+ });
306
+ return { executionContext, result: { status: "success", output: result?.result } };
307
+ }
308
+ );
309
+ Object.assign(executionContext, res.executionContext);
310
+ return {
311
+ ...res.result,
312
+ startedAt,
313
+ endedAt: Date.now(),
314
+ payload: inputData,
315
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
316
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
317
+ };
318
+ }
319
+ };
31
320
  var InngestRun = class extends workflows.Run {
32
321
  inngest;
33
322
  serializedStepGraph;
@@ -49,14 +338,21 @@ var InngestRun = class extends workflows.Run {
49
338
  }
50
339
  async getRunOutput(eventId) {
51
340
  let runs = await this.getRuns(eventId);
341
+ const storage = this.#mastra?.getStorage();
52
342
  while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
53
343
  await new Promise((resolve) => setTimeout(resolve, 1e3));
54
344
  runs = await this.getRuns(eventId);
55
345
  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({
346
+ const snapshot = await storage?.loadWorkflowSnapshot({
347
+ workflowName: this.workflowId,
348
+ runId: this.runId
349
+ });
350
+ return {
351
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
352
+ };
353
+ }
354
+ if (runs?.[0]?.status === "Cancelled") {
355
+ const snapshot = await storage?.loadWorkflowSnapshot({
60
356
  workflowName: this.workflowId,
61
357
  runId: this.runId
62
358
  });
@@ -65,56 +361,73 @@ var InngestRun = class extends workflows.Run {
65
361
  }
66
362
  return runs?.[0];
67
363
  }
68
- async sendEvent(event, data) {
69
- await this.inngest.send({
70
- name: `user-event-${event}`,
71
- data
72
- });
73
- }
74
364
  async cancel() {
365
+ const storage = this.#mastra?.getStorage();
75
366
  await this.inngest.send({
76
367
  name: `cancel.workflow.${this.workflowId}`,
77
368
  data: {
78
369
  runId: this.runId
79
370
  }
80
371
  });
81
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
372
+ const snapshot = await storage?.loadWorkflowSnapshot({
82
373
  workflowName: this.workflowId,
83
374
  runId: this.runId
84
375
  });
85
376
  if (snapshot) {
86
- await this.#mastra?.storage?.persistWorkflowSnapshot({
377
+ await storage?.persistWorkflowSnapshot({
87
378
  workflowName: this.workflowId,
88
379
  runId: this.runId,
380
+ resourceId: this.resourceId,
89
381
  snapshot: {
90
382
  ...snapshot,
91
- status: "canceled"
383
+ status: "canceled",
384
+ value: snapshot.value
92
385
  }
93
386
  });
94
387
  }
95
388
  }
96
- async start({
97
- inputData
389
+ async start(params) {
390
+ return this._start(params);
391
+ }
392
+ async _start({
393
+ inputData,
394
+ initialState,
395
+ outputOptions,
396
+ tracingOptions,
397
+ format,
398
+ requestContext
98
399
  }) {
99
400
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
100
401
  workflowName: this.workflowId,
101
402
  runId: this.runId,
403
+ resourceId: this.resourceId,
102
404
  snapshot: {
103
405
  runId: this.runId,
104
406
  serializedStepGraph: this.serializedStepGraph,
407
+ status: "running",
105
408
  value: {},
106
409
  context: {},
107
410
  activePaths: [],
108
411
  suspendedPaths: {},
109
- timestamp: Date.now(),
110
- status: "running"
412
+ activeStepsPath: {},
413
+ resumeLabels: {},
414
+ waitingPaths: {},
415
+ timestamp: Date.now()
111
416
  }
112
417
  });
418
+ const inputDataToUse = await this._validateInput(inputData);
419
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
113
420
  const eventOutput = await this.inngest.send({
114
421
  name: `workflow.${this.workflowId}`,
115
422
  data: {
116
- inputData,
117
- runId: this.runId
423
+ inputData: inputDataToUse,
424
+ initialState: initialStateToUse,
425
+ runId: this.runId,
426
+ resourceId: this.resourceId,
427
+ outputOptions,
428
+ tracingOptions,
429
+ format,
430
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
118
431
  }
119
432
  });
120
433
  const eventId = eventOutput.ids[0];
@@ -143,27 +456,131 @@ var InngestRun = class extends workflows.Run {
143
456
  return p;
144
457
  }
145
458
  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({
459
+ const storage = this.#mastra?.getStorage();
460
+ let steps = [];
461
+ if (typeof params.step === "string") {
462
+ steps = params.step.split(".");
463
+ } else {
464
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
465
+ (step) => typeof step === "string" ? step : step?.id
466
+ );
467
+ }
468
+ const snapshot = await storage?.loadWorkflowSnapshot({
150
469
  workflowName: this.workflowId,
151
470
  runId: this.runId
152
471
  });
472
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
473
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
474
+ const persistedRequestContext = snapshot?.requestContext ?? {};
475
+ const newRequestContext = params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {};
476
+ const mergedRequestContext = { ...persistedRequestContext, ...newRequestContext };
153
477
  const eventOutput = await this.inngest.send({
154
478
  name: `workflow.${this.workflowId}`,
155
479
  data: {
156
- inputData: params.resumeData,
480
+ inputData: resumeDataToUse,
481
+ initialState: snapshot?.value ?? {},
157
482
  runId: this.runId,
158
483
  workflowId: this.workflowId,
159
484
  stepResults: snapshot?.context,
160
485
  resume: {
161
486
  steps,
162
487
  stepResults: snapshot?.context,
163
- resumePayload: params.resumeData,
164
- // @ts-ignore
165
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
488
+ resumePayload: resumeDataToUse,
489
+ resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
490
+ },
491
+ requestContext: mergedRequestContext
492
+ }
493
+ });
494
+ const eventId = eventOutput.ids[0];
495
+ if (!eventId) {
496
+ throw new Error("Event ID is not set");
497
+ }
498
+ const runOutput = await this.getRunOutput(eventId);
499
+ const result = runOutput?.output?.result;
500
+ if (result.status === "failed") {
501
+ result.error = new Error(result.error);
502
+ }
503
+ return result;
504
+ }
505
+ async timeTravel(params) {
506
+ const p = this._timeTravel(params).then((result) => {
507
+ if (result.status !== "suspended") {
508
+ this.closeStreamAction?.().catch(() => {
509
+ });
510
+ }
511
+ return result;
512
+ });
513
+ this.executionResults = p;
514
+ return p;
515
+ }
516
+ async _timeTravel(params) {
517
+ if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
518
+ throw new Error("Step is required and must be a valid step or array of steps");
519
+ }
520
+ let steps = [];
521
+ if (typeof params.step === "string") {
522
+ steps = params.step.split(".");
523
+ } else {
524
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
525
+ (step) => typeof step === "string" ? step : step?.id
526
+ );
527
+ }
528
+ if (steps.length === 0) {
529
+ throw new Error("No steps provided to timeTravel");
530
+ }
531
+ const storage = this.#mastra?.getStorage();
532
+ const snapshot = await storage?.loadWorkflowSnapshot({
533
+ workflowName: this.workflowId,
534
+ runId: this.runId
535
+ });
536
+ if (!snapshot) {
537
+ await storage?.persistWorkflowSnapshot({
538
+ workflowName: this.workflowId,
539
+ runId: this.runId,
540
+ resourceId: this.resourceId,
541
+ snapshot: {
542
+ runId: this.runId,
543
+ serializedStepGraph: this.serializedStepGraph,
544
+ status: "pending",
545
+ value: {},
546
+ context: {},
547
+ activePaths: [],
548
+ suspendedPaths: {},
549
+ activeStepsPath: {},
550
+ resumeLabels: {},
551
+ waitingPaths: {},
552
+ timestamp: Date.now()
166
553
  }
554
+ });
555
+ }
556
+ if (snapshot?.status === "running") {
557
+ throw new Error("This workflow run is still running, cannot time travel");
558
+ }
559
+ let inputDataToUse = params.inputData;
560
+ if (inputDataToUse && steps.length === 1) {
561
+ inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
562
+ }
563
+ const timeTravelData = workflows.createTimeTravelExecutionParams({
564
+ steps,
565
+ inputData: inputDataToUse,
566
+ resumeData: params.resumeData,
567
+ context: params.context,
568
+ nestedStepsContext: params.nestedStepsContext,
569
+ snapshot: snapshot ?? { context: {} },
570
+ graph: this.executionGraph,
571
+ initialState: params.initialState
572
+ });
573
+ const eventOutput = await this.inngest.send({
574
+ name: `workflow.${this.workflowId}`,
575
+ data: {
576
+ initialState: timeTravelData.state,
577
+ runId: this.runId,
578
+ workflowId: this.workflowId,
579
+ stepResults: timeTravelData.stepResults,
580
+ timeTravel: timeTravelData,
581
+ tracingOptions: params.tracingOptions,
582
+ outputOptions: params.outputOptions,
583
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
167
584
  }
168
585
  });
169
586
  const eventId = eventOutput.ids[0];
@@ -177,12 +594,12 @@ var InngestRun = class extends workflows.Run {
177
594
  }
178
595
  return result;
179
596
  }
180
- watch(cb, type = "watch") {
597
+ watch(cb) {
181
598
  let active = true;
182
599
  const streamPromise = realtime.subscribe(
183
600
  {
184
601
  channel: `workflow:${this.workflowId}:${this.runId}`,
185
- topics: [type],
602
+ topics: ["watch"],
186
603
  app: this.inngest
187
604
  },
188
605
  (message) => {
@@ -200,16 +617,35 @@ var InngestRun = class extends workflows.Run {
200
617
  });
201
618
  };
202
619
  }
203
- stream({ inputData, runtimeContext } = {}) {
620
+ streamLegacy({ inputData, requestContext } = {}) {
204
621
  const { readable, writable } = new TransformStream();
205
622
  const writer = writable.getWriter();
623
+ void writer.write({
624
+ // @ts-ignore
625
+ type: "start",
626
+ // @ts-ignore
627
+ payload: { runId: this.runId }
628
+ });
206
629
  const unwatch = this.watch(async (event) => {
207
630
  try {
208
- await writer.write(event);
631
+ const e = {
632
+ ...event,
633
+ type: event.type.replace("workflow-", "")
634
+ };
635
+ if (e.type === "step-output") {
636
+ e.type = e.payload.output.type;
637
+ e.payload = e.payload.output.payload;
638
+ }
639
+ await writer.write(e);
209
640
  } catch {
210
641
  }
211
- }, "watch-v2");
642
+ });
212
643
  this.closeStreamAction = async () => {
644
+ await writer.write({
645
+ type: "finish",
646
+ // @ts-ignore
647
+ payload: { runId: this.runId }
648
+ });
213
649
  unwatch();
214
650
  try {
215
651
  await writer.close();
@@ -219,7 +655,7 @@ var InngestRun = class extends workflows.Run {
219
655
  writer.releaseLock();
220
656
  }
221
657
  };
222
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
658
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
223
659
  if (result.status !== "suspended") {
224
660
  this.closeStreamAction?.().catch(() => {
225
661
  });
@@ -231,53 +667,186 @@ var InngestRun = class extends workflows.Run {
231
667
  getWorkflowState: () => this.executionResults
232
668
  };
233
669
  }
234
- };
235
- var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
236
- #mastra;
237
- inngest;
238
- function;
239
- constructor(params, inngest) {
240
- super(params);
241
- this.#mastra = params.mastra;
242
- this.inngest = inngest;
243
- }
244
- async getWorkflowRuns(args) {
245
- const storage = this.#mastra?.getStorage();
246
- if (!storage) {
247
- this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
248
- return { runs: [], total: 0 };
249
- }
250
- return storage.getWorkflowRuns({ workflowName: this.id, ...args ?? {} });
251
- }
252
- async getWorkflowRunById(runId) {
253
- const storage = this.#mastra?.getStorage();
254
- if (!storage) {
255
- this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
256
- return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
257
- }
258
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
259
- return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
260
- }
261
- async getWorkflowRunExecutionResult(runId) {
262
- const storage = this.#mastra?.getStorage();
263
- if (!storage) {
264
- this.logger.debug("Cannot get workflow run execution result. Mastra storage is not initialized");
265
- return null;
266
- }
267
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
268
- if (!run?.snapshot) {
269
- return null;
270
- }
271
- if (typeof run.snapshot === "string") {
272
- return null;
670
+ stream({
671
+ inputData,
672
+ requestContext,
673
+ tracingOptions,
674
+ closeOnSuspend = true,
675
+ initialState,
676
+ outputOptions
677
+ } = {}) {
678
+ if (this.closeStreamAction && this.streamOutput) {
679
+ return this.streamOutput;
273
680
  }
274
- return {
275
- status: run.snapshot.status,
276
- result: run.snapshot.result,
277
- error: run.snapshot.error,
278
- payload: run.snapshot.context?.input,
279
- steps: run.snapshot.context
681
+ this.closeStreamAction = async () => {
682
+ };
683
+ const self = this;
684
+ const stream$1 = new web.ReadableStream({
685
+ async start(controller) {
686
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
687
+ controller.enqueue({
688
+ type,
689
+ runId: self.runId,
690
+ from,
691
+ payload: {
692
+ stepName: payload?.id,
693
+ ...payload
694
+ }
695
+ });
696
+ });
697
+ self.closeStreamAction = async () => {
698
+ unwatch();
699
+ try {
700
+ await controller.close();
701
+ } catch (err) {
702
+ console.error("Error closing stream:", err);
703
+ }
704
+ };
705
+ const executionResultsPromise = self._start({
706
+ inputData,
707
+ requestContext,
708
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
709
+ initialState,
710
+ tracingOptions,
711
+ outputOptions,
712
+ format: "vnext"
713
+ });
714
+ let executionResults;
715
+ try {
716
+ executionResults = await executionResultsPromise;
717
+ if (closeOnSuspend) {
718
+ self.closeStreamAction?.().catch(() => {
719
+ });
720
+ } else if (executionResults.status !== "suspended") {
721
+ self.closeStreamAction?.().catch(() => {
722
+ });
723
+ }
724
+ if (self.streamOutput) {
725
+ self.streamOutput.updateResults(
726
+ executionResults
727
+ );
728
+ }
729
+ } catch (err) {
730
+ self.streamOutput?.rejectResults(err);
731
+ self.closeStreamAction?.().catch(() => {
732
+ });
733
+ }
734
+ }
735
+ });
736
+ this.streamOutput = new stream.WorkflowRunOutput({
737
+ runId: this.runId,
738
+ workflowId: this.workflowId,
739
+ stream: stream$1
740
+ });
741
+ return this.streamOutput;
742
+ }
743
+ streamVNext(args = {}) {
744
+ return this.stream(args);
745
+ }
746
+ timeTravelStream({
747
+ inputData,
748
+ resumeData,
749
+ initialState,
750
+ step,
751
+ context,
752
+ nestedStepsContext,
753
+ requestContext,
754
+ tracingOptions,
755
+ outputOptions
756
+ }) {
757
+ this.closeStreamAction = async () => {
280
758
  };
759
+ const self = this;
760
+ const stream$1 = new web.ReadableStream({
761
+ async start(controller) {
762
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
763
+ controller.enqueue({
764
+ type,
765
+ runId: self.runId,
766
+ from,
767
+ payload: {
768
+ stepName: payload?.id,
769
+ ...payload
770
+ }
771
+ });
772
+ });
773
+ self.closeStreamAction = async () => {
774
+ unwatch();
775
+ try {
776
+ controller.close();
777
+ } catch (err) {
778
+ console.error("Error closing stream:", err);
779
+ }
780
+ };
781
+ const executionResultsPromise = self._timeTravel({
782
+ inputData,
783
+ step,
784
+ context,
785
+ nestedStepsContext,
786
+ resumeData,
787
+ initialState,
788
+ requestContext,
789
+ tracingOptions,
790
+ outputOptions
791
+ });
792
+ self.executionResults = executionResultsPromise;
793
+ let executionResults;
794
+ try {
795
+ executionResults = await executionResultsPromise;
796
+ self.closeStreamAction?.().catch(() => {
797
+ });
798
+ if (self.streamOutput) {
799
+ self.streamOutput.updateResults(executionResults);
800
+ }
801
+ } catch (err) {
802
+ self.streamOutput?.rejectResults(err);
803
+ self.closeStreamAction?.().catch(() => {
804
+ });
805
+ }
806
+ }
807
+ });
808
+ this.streamOutput = new stream.WorkflowRunOutput({
809
+ runId: this.runId,
810
+ workflowId: this.workflowId,
811
+ stream: stream$1
812
+ });
813
+ return this.streamOutput;
814
+ }
815
+ };
816
+
817
+ // src/workflow.ts
818
+ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
819
+ #mastra;
820
+ inngest;
821
+ function;
822
+ flowControlConfig;
823
+ constructor(params, inngest) {
824
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
825
+ super(workflowParams);
826
+ this.engineType = "inngest";
827
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
828
+ ([_, value]) => value !== void 0
829
+ );
830
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
831
+ this.#mastra = params.mastra;
832
+ this.inngest = inngest;
833
+ }
834
+ async listWorkflowRuns(args) {
835
+ const storage = this.#mastra?.getStorage();
836
+ if (!storage) {
837
+ this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
838
+ return { runs: [], total: 0 };
839
+ }
840
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
841
+ }
842
+ async getWorkflowRunById(runId) {
843
+ const storage = this.#mastra?.getStorage();
844
+ if (!storage) {
845
+ this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
846
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
847
+ }
848
+ const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
849
+ return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
281
850
  }
282
851
  __registerMastra(mastra) {
283
852
  this.#mastra = mastra;
@@ -297,56 +866,49 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
297
866
  }
298
867
  }
299
868
  }
300
- createRun(options) {
869
+ async createRun(options) {
301
870
  const runIdToUse = options?.runId || crypto.randomUUID();
302
871
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
303
872
  {
304
873
  workflowId: this.id,
305
874
  runId: runIdToUse,
875
+ resourceId: options?.resourceId,
306
876
  executionEngine: this.executionEngine,
307
877
  executionGraph: this.executionGraph,
308
878
  serializedStepGraph: this.serializedStepGraph,
309
879
  mastra: this.#mastra,
310
880
  retryConfig: this.retryConfig,
311
- cleanup: () => this.runs.delete(runIdToUse)
881
+ cleanup: () => this.runs.delete(runIdToUse),
882
+ workflowSteps: this.steps,
883
+ workflowEngineType: this.engineType,
884
+ validateInputs: this.options.validateInputs
312
885
  },
313
886
  this.inngest
314
887
  );
315
888
  this.runs.set(runIdToUse, run);
316
- return run;
317
- }
318
- async createRunAsync(options) {
319
- const runIdToUse = options?.runId || crypto.randomUUID();
320
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
321
- {
322
- workflowId: this.id,
323
- runId: runIdToUse,
324
- executionEngine: this.executionEngine,
325
- executionGraph: this.executionGraph,
326
- serializedStepGraph: this.serializedStepGraph,
327
- mastra: this.#mastra,
328
- retryConfig: this.retryConfig,
329
- cleanup: () => this.runs.delete(runIdToUse)
330
- },
331
- this.inngest
332
- );
333
- this.runs.set(runIdToUse, run);
334
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
335
- if (!workflowSnapshotInStorage) {
889
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
890
+ workflowStatus: run.workflowRunStatus,
891
+ stepResults: {}
892
+ });
893
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
894
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
336
895
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
337
896
  workflowName: this.id,
338
897
  runId: runIdToUse,
898
+ resourceId: options?.resourceId,
339
899
  snapshot: {
340
900
  runId: runIdToUse,
341
901
  status: "pending",
342
902
  value: {},
343
903
  context: {},
344
904
  activePaths: [],
905
+ activeStepsPath: {},
906
+ waitingPaths: {},
345
907
  serializedStepGraph: this.serializedStepGraph,
346
908
  suspendedPaths: {},
909
+ resumeLabels: {},
347
910
  result: void 0,
348
911
  error: void 0,
349
- // @ts-ignore
350
912
  timestamp: Date.now()
351
913
  }
352
914
  });
@@ -360,13 +922,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
360
922
  this.function = this.inngest.createFunction(
361
923
  {
362
924
  id: `workflow.${this.id}`,
363
- // @ts-ignore
364
- retries: this.retryConfig?.attempts ?? 0,
365
- cancelOn: [{ event: `cancel.workflow.${this.id}` }]
925
+ retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
926
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
927
+ // Spread flow control configuration
928
+ ...this.flowControlConfig
366
929
  },
367
930
  { event: `workflow.${this.id}` },
368
931
  async ({ event, step, attempt, publish }) => {
369
- let { inputData, runId, resume } = event.data;
932
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
370
933
  if (!runId) {
371
934
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
372
935
  return crypto.randomUUID();
@@ -394,19 +957,38 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
394
957
  once: (_event, _callback) => {
395
958
  }
396
959
  };
397
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
960
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
398
961
  const result = await engine.execute({
399
962
  workflowId: this.id,
400
963
  runId,
964
+ resourceId,
401
965
  graph: this.executionGraph,
402
966
  serializedStepGraph: this.serializedStepGraph,
403
967
  input: inputData,
968
+ initialState,
404
969
  emitter,
405
970
  retryConfig: this.retryConfig,
406
- runtimeContext: new di.RuntimeContext(),
407
- // TODO
971
+ requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
408
972
  resume,
409
- abortController: new AbortController()
973
+ timeTravel,
974
+ format,
975
+ abortController: new AbortController(),
976
+ // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
977
+ outputOptions,
978
+ writableStream: new web.WritableStream({
979
+ write(chunk) {
980
+ void emitter.emit("watch", chunk).catch(() => {
981
+ });
982
+ }
983
+ })
984
+ });
985
+ await step.run(`workflow.${this.id}.finalize`, async () => {
986
+ if (result.status === "failed") {
987
+ throw new inngest.NonRetriableError(`Workflow failed`, {
988
+ cause: result
989
+ });
990
+ }
991
+ return result;
410
992
  });
411
993
  return { result, runId };
412
994
  }
@@ -430,27 +1012,70 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
430
1012
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
431
1013
  }
432
1014
  };
1015
+ function serve({
1016
+ mastra,
1017
+ inngest,
1018
+ functions: userFunctions = [],
1019
+ registerOptions
1020
+ }) {
1021
+ const wfs = mastra.listWorkflows();
1022
+ const workflowFunctions = Array.from(
1023
+ new Set(
1024
+ Object.values(wfs).flatMap((wf) => {
1025
+ if (wf instanceof InngestWorkflow) {
1026
+ wf.__registerMastra(mastra);
1027
+ return wf.getFunctions();
1028
+ }
1029
+ return [];
1030
+ })
1031
+ )
1032
+ );
1033
+ return hono.serve({
1034
+ ...registerOptions,
1035
+ client: inngest,
1036
+ functions: [...workflowFunctions, ...userFunctions]
1037
+ });
1038
+ }
1039
+
1040
+ // src/types.ts
1041
+ var _compatibilityCheck = true;
1042
+
1043
+ // src/index.ts
433
1044
  function isAgent(params) {
434
1045
  return params?.component === "AGENT";
435
1046
  }
436
1047
  function isTool(params) {
437
1048
  return params instanceof tools.Tool;
438
1049
  }
439
- function createStep(params) {
1050
+ function isInngestWorkflow(params) {
1051
+ return params instanceof InngestWorkflow;
1052
+ }
1053
+ function createStep(params, agentOptions) {
1054
+ if (isInngestWorkflow(params)) {
1055
+ return params;
1056
+ }
440
1057
  if (isAgent(params)) {
441
1058
  return {
442
1059
  id: params.name,
443
- // @ts-ignore
1060
+ description: params.getDescription(),
444
1061
  inputSchema: zod.z.object({
445
1062
  prompt: zod.z.string()
446
1063
  // resourceId: z.string().optional(),
447
1064
  // threadId: z.string().optional(),
448
1065
  }),
449
- // @ts-ignore
450
1066
  outputSchema: zod.z.object({
451
1067
  text: zod.z.string()
452
1068
  }),
453
- execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
1069
+ execute: async ({
1070
+ inputData,
1071
+ [_constants.EMITTER_SYMBOL]: emitter,
1072
+ [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1073
+ requestContext,
1074
+ tracingContext,
1075
+ abortSignal,
1076
+ abort,
1077
+ writer
1078
+ }) => {
454
1079
  let streamPromise = {};
455
1080
  streamPromise.promise = new Promise((resolve, reject) => {
456
1081
  streamPromise.resolve = resolve;
@@ -460,50 +1085,65 @@ function createStep(params) {
460
1085
  name: params.name,
461
1086
  args: inputData
462
1087
  };
463
- await emitter.emit("watch-v2", {
464
- type: "tool-call-streaming-start",
465
- ...toolData
466
- });
467
- const { fullStream } = await params.stream(inputData.prompt, {
468
- // resourceId: inputData.resourceId,
469
- // threadId: inputData.threadId,
470
- runtimeContext,
471
- onFinish: (result) => {
472
- streamPromise.resolve(result.text);
473
- },
474
- abortSignal
475
- });
476
- if (abortSignal.aborted) {
477
- return abort();
1088
+ let stream;
1089
+ if ((await params.getModel()).specificationVersion === "v1") {
1090
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
1091
+ ...agentOptions ?? {},
1092
+ // resourceId: inputData.resourceId,
1093
+ // threadId: inputData.threadId,
1094
+ requestContext,
1095
+ tracingContext,
1096
+ onFinish: (result) => {
1097
+ streamPromise.resolve(result.text);
1098
+ void agentOptions?.onFinish?.(result);
1099
+ },
1100
+ abortSignal
1101
+ });
1102
+ stream = fullStream;
1103
+ } else {
1104
+ const modelOutput = await params.stream(inputData.prompt, {
1105
+ ...agentOptions ?? {},
1106
+ requestContext,
1107
+ tracingContext,
1108
+ onFinish: (result) => {
1109
+ streamPromise.resolve(result.text);
1110
+ void agentOptions?.onFinish?.(result);
1111
+ },
1112
+ abortSignal
1113
+ });
1114
+ stream = modelOutput.fullStream;
478
1115
  }
479
- for await (const chunk of fullStream) {
480
- switch (chunk.type) {
481
- case "text-delta":
482
- await emitter.emit("watch-v2", {
1116
+ if (streamFormat === "legacy") {
1117
+ await emitter.emit("watch", {
1118
+ type: "tool-call-streaming-start",
1119
+ ...toolData ?? {}
1120
+ });
1121
+ for await (const chunk of stream) {
1122
+ if (chunk.type === "text-delta") {
1123
+ await emitter.emit("watch", {
483
1124
  type: "tool-call-delta",
484
- ...toolData,
1125
+ ...toolData ?? {},
485
1126
  argsTextDelta: chunk.textDelta
486
1127
  });
487
- break;
488
- case "step-start":
489
- case "step-finish":
490
- case "finish":
491
- break;
492
- case "tool-call":
493
- case "tool-result":
494
- case "tool-call-streaming-start":
495
- case "tool-call-delta":
496
- case "source":
497
- case "file":
498
- default:
499
- await emitter.emit("watch-v2", chunk);
500
- break;
1128
+ }
1129
+ }
1130
+ await emitter.emit("watch", {
1131
+ type: "tool-call-streaming-finish",
1132
+ ...toolData ?? {}
1133
+ });
1134
+ } else {
1135
+ for await (const chunk of stream) {
1136
+ await writer.write(chunk);
501
1137
  }
502
1138
  }
1139
+ if (abortSignal.aborted) {
1140
+ return abort();
1141
+ }
503
1142
  return {
504
1143
  text: await streamPromise.promise
505
1144
  };
506
- }
1145
+ },
1146
+ component: params.component
507
1147
  };
508
1148
  }
509
1149
  if (isTool(params)) {
@@ -512,17 +1152,40 @@ function createStep(params) {
512
1152
  }
513
1153
  return {
514
1154
  // TODO: tool probably should have strong id type
515
- // @ts-ignore
516
1155
  id: params.id,
1156
+ description: params.description,
517
1157
  inputSchema: params.inputSchema,
518
1158
  outputSchema: params.outputSchema,
519
- execute: async ({ inputData, mastra, runtimeContext }) => {
520
- return params.execute({
521
- context: inputData,
1159
+ suspendSchema: params.suspendSchema,
1160
+ resumeSchema: params.resumeSchema,
1161
+ execute: async ({
1162
+ inputData,
1163
+ mastra,
1164
+ requestContext,
1165
+ tracingContext,
1166
+ suspend,
1167
+ resumeData,
1168
+ runId,
1169
+ workflowId,
1170
+ state,
1171
+ setState
1172
+ }) => {
1173
+ const toolContext = {
522
1174
  mastra,
523
- runtimeContext
524
- });
525
- }
1175
+ requestContext,
1176
+ tracingContext,
1177
+ workflow: {
1178
+ runId,
1179
+ resumeData,
1180
+ suspend,
1181
+ workflowId,
1182
+ state,
1183
+ setState
1184
+ }
1185
+ };
1186
+ return params.execute(inputData, toolContext);
1187
+ },
1188
+ component: "TOOL"
526
1189
  };
527
1190
  }
528
1191
  return {
@@ -538,7 +1201,10 @@ function createStep(params) {
538
1201
  function init(inngest) {
539
1202
  return {
540
1203
  createWorkflow(params) {
541
- return new InngestWorkflow(params, inngest);
1204
+ return new InngestWorkflow(
1205
+ params,
1206
+ inngest
1207
+ );
542
1208
  },
543
1209
  createStep,
544
1210
  cloneStep(step, opts) {
@@ -547,7 +1213,13 @@ function init(inngest) {
547
1213
  description: step.description,
548
1214
  inputSchema: step.inputSchema,
549
1215
  outputSchema: step.outputSchema,
550
- execute: step.execute
1216
+ resumeSchema: step.resumeSchema,
1217
+ suspendSchema: step.suspendSchema,
1218
+ stateSchema: step.stateSchema,
1219
+ execute: step.execute,
1220
+ retries: step.retries,
1221
+ scorers: step.scorers,
1222
+ component: step.component
551
1223
  };
552
1224
  },
553
1225
  cloneWorkflow(workflow, opts) {
@@ -556,7 +1228,8 @@ function init(inngest) {
556
1228
  inputSchema: workflow.inputSchema,
557
1229
  outputSchema: workflow.outputSchema,
558
1230
  steps: workflow.stepDefs,
559
- mastra: workflow.mastra
1231
+ mastra: workflow.mastra,
1232
+ options: workflow.options
560
1233
  });
561
1234
  wf.setStepFlow(workflow.stepGraph);
562
1235
  wf.commit();
@@ -564,736 +1237,13 @@ function init(inngest) {
564
1237
  }
565
1238
  };
566
1239
  }
567
- var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
568
- inngestStep;
569
- inngestAttempts;
570
- constructor(mastra, inngestStep, inngestAttempts = 0) {
571
- super({ mastra });
572
- this.inngestStep = inngestStep;
573
- this.inngestAttempts = inngestAttempts;
574
- }
575
- async execute(params) {
576
- await params.emitter.emit("watch-v2", {
577
- type: "start",
578
- payload: { runId: params.runId }
579
- });
580
- const result = await super.execute(params);
581
- await params.emitter.emit("watch-v2", {
582
- type: "finish",
583
- payload: { runId: params.runId }
584
- });
585
- return result;
586
- }
587
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
588
- const base = {
589
- status: lastOutput.status,
590
- steps: stepResults
591
- };
592
- if (lastOutput.status === "success") {
593
- await emitter.emit("watch", {
594
- type: "watch",
595
- payload: {
596
- workflowState: {
597
- status: lastOutput.status,
598
- steps: stepResults,
599
- result: lastOutput.output
600
- }
601
- },
602
- eventTimestamp: Date.now()
603
- });
604
- base.result = lastOutput.output;
605
- } else if (lastOutput.status === "failed") {
606
- base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
607
- await emitter.emit("watch", {
608
- type: "watch",
609
- payload: {
610
- workflowState: {
611
- status: lastOutput.status,
612
- steps: stepResults,
613
- result: null,
614
- error: base.error
615
- }
616
- },
617
- eventTimestamp: Date.now()
618
- });
619
- } else if (lastOutput.status === "suspended") {
620
- await emitter.emit("watch", {
621
- type: "watch",
622
- payload: {
623
- workflowState: {
624
- status: lastOutput.status,
625
- steps: stepResults,
626
- result: null,
627
- error: null
628
- }
629
- },
630
- eventTimestamp: Date.now()
631
- });
632
- const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
633
- if (stepResult?.status === "suspended") {
634
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
635
- return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
636
- }
637
- return [];
638
- });
639
- base.suspended = suspendedStepIds;
640
- }
641
- executionSpan?.end();
642
- return base;
643
- }
644
- async superExecuteStep({
645
- workflowId,
646
- runId,
647
- step,
648
- stepResults,
649
- executionContext,
650
- resume,
651
- prevOutput,
652
- emitter,
653
- abortController,
654
- runtimeContext,
655
- writableStream
656
- }) {
657
- return super.executeStep({
658
- workflowId,
659
- runId,
660
- step,
661
- stepResults,
662
- executionContext,
663
- resume,
664
- prevOutput,
665
- emitter,
666
- abortController,
667
- runtimeContext,
668
- writableStream
669
- });
670
- }
671
- // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
672
- // await this.inngestStep.sleep(id, duration);
673
- // }
674
- async executeSleep({
675
- workflowId,
676
- runId,
677
- entry,
678
- prevOutput,
679
- stepResults,
680
- emitter,
681
- abortController,
682
- runtimeContext,
683
- writableStream
684
- }) {
685
- let { duration, fn } = entry;
686
- if (fn) {
687
- const stepCallId = crypto.randomUUID();
688
- duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
689
- return await fn({
690
- runId,
691
- workflowId,
692
- mastra: this.mastra,
693
- runtimeContext,
694
- inputData: prevOutput,
695
- runCount: -1,
696
- getInitData: () => stepResults?.input,
697
- getStepResult: (step) => {
698
- if (!step?.id) {
699
- return null;
700
- }
701
- const result = stepResults[step.id];
702
- if (result?.status === "success") {
703
- return result.output;
704
- }
705
- return null;
706
- },
707
- // TODO: this function shouldn't have suspend probably?
708
- suspend: async (_suspendPayload) => {
709
- },
710
- bail: () => {
711
- },
712
- abort: () => {
713
- abortController?.abort();
714
- },
715
- [_constants.EMITTER_SYMBOL]: emitter,
716
- engine: { step: this.inngestStep },
717
- abortSignal: abortController?.signal,
718
- writer: new tools.ToolStream(
719
- {
720
- prefix: "step",
721
- callId: stepCallId,
722
- name: "sleep",
723
- runId
724
- },
725
- writableStream
726
- )
727
- });
728
- });
729
- }
730
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
731
- }
732
- async executeSleepUntil({
733
- workflowId,
734
- runId,
735
- entry,
736
- prevOutput,
737
- stepResults,
738
- emitter,
739
- abortController,
740
- runtimeContext,
741
- writableStream
742
- }) {
743
- let { date, fn } = entry;
744
- if (fn) {
745
- date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
746
- const stepCallId = crypto.randomUUID();
747
- return await fn({
748
- runId,
749
- workflowId,
750
- mastra: this.mastra,
751
- runtimeContext,
752
- inputData: prevOutput,
753
- runCount: -1,
754
- getInitData: () => stepResults?.input,
755
- getStepResult: (step) => {
756
- if (!step?.id) {
757
- return null;
758
- }
759
- const result = stepResults[step.id];
760
- if (result?.status === "success") {
761
- return result.output;
762
- }
763
- return null;
764
- },
765
- // TODO: this function shouldn't have suspend probably?
766
- suspend: async (_suspendPayload) => {
767
- },
768
- bail: () => {
769
- },
770
- abort: () => {
771
- abortController?.abort();
772
- },
773
- [_constants.EMITTER_SYMBOL]: emitter,
774
- engine: { step: this.inngestStep },
775
- abortSignal: abortController?.signal,
776
- writer: new tools.ToolStream(
777
- {
778
- prefix: "step",
779
- callId: stepCallId,
780
- name: "sleep",
781
- runId
782
- },
783
- writableStream
784
- )
785
- });
786
- });
787
- }
788
- if (!(date instanceof Date)) {
789
- return;
790
- }
791
- await this.inngestStep.sleepUntil(entry.id, date);
792
- }
793
- async executeWaitForEvent({ event, timeout }) {
794
- const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
795
- event: `user-event-${event}`,
796
- timeout: timeout ?? 5e3
797
- });
798
- if (eventData === null) {
799
- throw "Timeout waiting for event";
800
- }
801
- return eventData?.data;
802
- }
803
- async executeStep({
804
- step,
805
- stepResults,
806
- executionContext,
807
- resume,
808
- prevOutput,
809
- emitter,
810
- abortController,
811
- runtimeContext,
812
- writableStream
813
- }) {
814
- const startedAt = await this.inngestStep.run(
815
- `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
816
- async () => {
817
- const startedAt2 = Date.now();
818
- await emitter.emit("watch", {
819
- type: "watch",
820
- payload: {
821
- currentStep: {
822
- id: step.id,
823
- status: "running"
824
- },
825
- workflowState: {
826
- status: "running",
827
- steps: {
828
- ...stepResults,
829
- [step.id]: {
830
- status: "running"
831
- }
832
- },
833
- result: null,
834
- error: null
835
- }
836
- },
837
- eventTimestamp: Date.now()
838
- });
839
- await emitter.emit("watch-v2", {
840
- type: "step-start",
841
- payload: {
842
- id: step.id,
843
- status: "running",
844
- payload: prevOutput,
845
- startedAt: startedAt2
846
- }
847
- });
848
- return startedAt2;
849
- }
850
- );
851
- if (step instanceof InngestWorkflow) {
852
- const isResume = !!resume?.steps?.length;
853
- let result;
854
- let runId;
855
- if (isResume) {
856
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
857
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
858
- workflowName: step.id,
859
- runId
860
- });
861
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
862
- function: step.getFunction(),
863
- data: {
864
- inputData: prevOutput,
865
- runId,
866
- resume: {
867
- runId,
868
- steps: resume.steps.slice(1),
869
- stepResults: snapshot?.context,
870
- resumePayload: resume.resumePayload,
871
- // @ts-ignore
872
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
873
- }
874
- }
875
- });
876
- result = invokeResp.result;
877
- runId = invokeResp.runId;
878
- } else {
879
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
880
- function: step.getFunction(),
881
- data: {
882
- inputData: prevOutput
883
- }
884
- });
885
- result = invokeResp.result;
886
- runId = invokeResp.runId;
887
- }
888
- const res = await this.inngestStep.run(
889
- `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
890
- async () => {
891
- if (result.status === "failed") {
892
- await emitter.emit("watch", {
893
- type: "watch",
894
- payload: {
895
- currentStep: {
896
- id: step.id,
897
- status: "failed",
898
- error: result?.error
899
- },
900
- workflowState: {
901
- status: "running",
902
- steps: stepResults,
903
- result: null,
904
- error: null
905
- }
906
- },
907
- eventTimestamp: Date.now()
908
- });
909
- await emitter.emit("watch-v2", {
910
- type: "step-result",
911
- payload: {
912
- id: step.id,
913
- status: "failed",
914
- error: result?.error,
915
- payload: prevOutput
916
- }
917
- });
918
- return { executionContext, result: { status: "failed", error: result?.error } };
919
- } else if (result.status === "suspended") {
920
- const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
921
- const stepRes2 = stepResult;
922
- return stepRes2?.status === "suspended";
923
- });
924
- for (const [stepName, stepResult] of suspendedSteps) {
925
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
926
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
927
- await emitter.emit("watch", {
928
- type: "watch",
929
- payload: {
930
- currentStep: {
931
- id: step.id,
932
- status: "suspended",
933
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
934
- },
935
- workflowState: {
936
- status: "running",
937
- steps: stepResults,
938
- result: null,
939
- error: null
940
- }
941
- },
942
- eventTimestamp: Date.now()
943
- });
944
- await emitter.emit("watch-v2", {
945
- type: "step-suspended",
946
- payload: {
947
- id: step.id,
948
- status: "suspended"
949
- }
950
- });
951
- return {
952
- executionContext,
953
- result: {
954
- status: "suspended",
955
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
956
- }
957
- };
958
- }
959
- await emitter.emit("watch", {
960
- type: "watch",
961
- payload: {
962
- currentStep: {
963
- id: step.id,
964
- status: "suspended",
965
- payload: {}
966
- },
967
- workflowState: {
968
- status: "running",
969
- steps: stepResults,
970
- result: null,
971
- error: null
972
- }
973
- },
974
- eventTimestamp: Date.now()
975
- });
976
- return {
977
- executionContext,
978
- result: {
979
- status: "suspended",
980
- payload: {}
981
- }
982
- };
983
- }
984
- await emitter.emit("watch", {
985
- type: "watch",
986
- payload: {
987
- currentStep: {
988
- id: step.id,
989
- status: "success",
990
- output: result?.result
991
- },
992
- workflowState: {
993
- status: "running",
994
- steps: stepResults,
995
- result: null,
996
- error: null
997
- }
998
- },
999
- eventTimestamp: Date.now()
1000
- });
1001
- await emitter.emit("watch-v2", {
1002
- type: "step-result",
1003
- payload: {
1004
- id: step.id,
1005
- status: "success",
1006
- output: result?.result
1007
- }
1008
- });
1009
- await emitter.emit("watch-v2", {
1010
- type: "step-finish",
1011
- payload: {
1012
- id: step.id,
1013
- metadata: {}
1014
- }
1015
- });
1016
- return { executionContext, result: { status: "success", output: result?.result } };
1017
- }
1018
- );
1019
- Object.assign(executionContext, res.executionContext);
1020
- return res.result;
1021
- }
1022
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1023
- let execResults;
1024
- let suspended;
1025
- let bailed;
1026
- try {
1027
- const result = await step.execute({
1028
- runId: executionContext.runId,
1029
- mastra: this.mastra,
1030
- runtimeContext,
1031
- writableStream,
1032
- inputData: prevOutput,
1033
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1034
- getInitData: () => stepResults?.input,
1035
- getStepResult: (step2) => {
1036
- const result2 = stepResults[step2.id];
1037
- if (result2?.status === "success") {
1038
- return result2.output;
1039
- }
1040
- return null;
1041
- },
1042
- suspend: async (suspendPayload) => {
1043
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1044
- suspended = { payload: suspendPayload };
1045
- },
1046
- bail: (result2) => {
1047
- bailed = { payload: result2 };
1048
- },
1049
- resume: {
1050
- steps: resume?.steps?.slice(1) || [],
1051
- resumePayload: resume?.resumePayload,
1052
- // @ts-ignore
1053
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
1054
- },
1055
- [_constants.EMITTER_SYMBOL]: emitter,
1056
- engine: {
1057
- step: this.inngestStep
1058
- },
1059
- abortSignal: abortController.signal
1060
- });
1061
- const endedAt = Date.now();
1062
- execResults = {
1063
- status: "success",
1064
- output: result,
1065
- startedAt,
1066
- endedAt,
1067
- payload: prevOutput,
1068
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1069
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1070
- };
1071
- } catch (e) {
1072
- execResults = {
1073
- status: "failed",
1074
- payload: prevOutput,
1075
- error: e instanceof Error ? e.message : String(e),
1076
- endedAt: Date.now(),
1077
- startedAt,
1078
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1079
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1080
- };
1081
- }
1082
- if (suspended) {
1083
- execResults = {
1084
- status: "suspended",
1085
- suspendedPayload: suspended.payload,
1086
- payload: prevOutput,
1087
- suspendedAt: Date.now(),
1088
- startedAt,
1089
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1090
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1091
- };
1092
- } else if (bailed) {
1093
- execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
1094
- }
1095
- if (execResults.status === "failed") {
1096
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
1097
- throw execResults.error;
1098
- }
1099
- }
1100
- await emitter.emit("watch", {
1101
- type: "watch",
1102
- payload: {
1103
- currentStep: {
1104
- id: step.id,
1105
- ...execResults
1106
- },
1107
- workflowState: {
1108
- status: "running",
1109
- steps: { ...stepResults, [step.id]: execResults },
1110
- result: null,
1111
- error: null
1112
- }
1113
- },
1114
- eventTimestamp: Date.now()
1115
- });
1116
- if (execResults.status === "suspended") {
1117
- await emitter.emit("watch-v2", {
1118
- type: "step-suspended",
1119
- payload: {
1120
- id: step.id,
1121
- ...execResults
1122
- }
1123
- });
1124
- } else {
1125
- await emitter.emit("watch-v2", {
1126
- type: "step-result",
1127
- payload: {
1128
- id: step.id,
1129
- ...execResults
1130
- }
1131
- });
1132
- await emitter.emit("watch-v2", {
1133
- type: "step-finish",
1134
- payload: {
1135
- id: step.id,
1136
- metadata: {}
1137
- }
1138
- });
1139
- }
1140
- return { result: execResults, executionContext, stepResults };
1141
- });
1142
- Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1143
- Object.assign(stepResults, stepRes.stepResults);
1144
- return stepRes.result;
1145
- }
1146
- async persistStepUpdate({
1147
- workflowId,
1148
- runId,
1149
- stepResults,
1150
- executionContext,
1151
- serializedStepGraph,
1152
- workflowStatus,
1153
- result,
1154
- error
1155
- }) {
1156
- await this.inngestStep.run(
1157
- `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1158
- async () => {
1159
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1160
- workflowName: workflowId,
1161
- runId,
1162
- snapshot: {
1163
- runId,
1164
- value: {},
1165
- context: stepResults,
1166
- activePaths: [],
1167
- suspendedPaths: executionContext.suspendedPaths,
1168
- serializedStepGraph,
1169
- status: workflowStatus,
1170
- result,
1171
- error,
1172
- // @ts-ignore
1173
- timestamp: Date.now()
1174
- }
1175
- });
1176
- }
1177
- );
1178
- }
1179
- async executeConditional({
1180
- workflowId,
1181
- runId,
1182
- entry,
1183
- prevOutput,
1184
- prevStep,
1185
- stepResults,
1186
- serializedStepGraph,
1187
- resume,
1188
- executionContext,
1189
- emitter,
1190
- abortController,
1191
- runtimeContext,
1192
- writableStream
1193
- }) {
1194
- let execResults;
1195
- const truthyIndexes = (await Promise.all(
1196
- entry.conditions.map(
1197
- (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1198
- try {
1199
- const result = await cond({
1200
- runId,
1201
- workflowId,
1202
- mastra: this.mastra,
1203
- runtimeContext,
1204
- runCount: -1,
1205
- inputData: prevOutput,
1206
- getInitData: () => stepResults?.input,
1207
- getStepResult: (step) => {
1208
- if (!step?.id) {
1209
- return null;
1210
- }
1211
- const result2 = stepResults[step.id];
1212
- if (result2?.status === "success") {
1213
- return result2.output;
1214
- }
1215
- return null;
1216
- },
1217
- // TODO: this function shouldn't have suspend probably?
1218
- suspend: async (_suspendPayload) => {
1219
- },
1220
- bail: () => {
1221
- },
1222
- abort: () => {
1223
- abortController.abort();
1224
- },
1225
- [_constants.EMITTER_SYMBOL]: emitter,
1226
- engine: {
1227
- step: this.inngestStep
1228
- },
1229
- abortSignal: abortController.signal,
1230
- writer: new tools.ToolStream(
1231
- {
1232
- prefix: "step",
1233
- callId: crypto.randomUUID(),
1234
- name: "conditional",
1235
- runId
1236
- },
1237
- writableStream
1238
- )
1239
- });
1240
- return result ? index : null;
1241
- } catch (e) {
1242
- return null;
1243
- }
1244
- })
1245
- )
1246
- )).filter((index) => index !== null);
1247
- const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1248
- const results = await Promise.all(
1249
- stepsToRun.map(
1250
- (step, index) => this.executeEntry({
1251
- workflowId,
1252
- runId,
1253
- entry: step,
1254
- prevStep,
1255
- stepResults,
1256
- resume,
1257
- serializedStepGraph,
1258
- executionContext: {
1259
- workflowId,
1260
- runId,
1261
- executionPath: [...executionContext.executionPath, index],
1262
- suspendedPaths: executionContext.suspendedPaths,
1263
- retryConfig: executionContext.retryConfig,
1264
- executionSpan: executionContext.executionSpan
1265
- },
1266
- emitter,
1267
- abortController,
1268
- runtimeContext,
1269
- writableStream
1270
- })
1271
- )
1272
- );
1273
- const hasFailed = results.find((result) => result.result.status === "failed");
1274
- const hasSuspended = results.find((result) => result.result.status === "suspended");
1275
- if (hasFailed) {
1276
- execResults = { status: "failed", error: hasFailed.result.error };
1277
- } else if (hasSuspended) {
1278
- execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
1279
- } else {
1280
- execResults = {
1281
- status: "success",
1282
- output: results.reduce((acc, result, index) => {
1283
- if (result.result.status === "success") {
1284
- acc[stepsToRun[index].step.id] = result.output;
1285
- }
1286
- return acc;
1287
- }, {})
1288
- };
1289
- }
1290
- return execResults;
1291
- }
1292
- };
1293
1240
 
1294
1241
  exports.InngestExecutionEngine = InngestExecutionEngine;
1295
1242
  exports.InngestRun = InngestRun;
1296
1243
  exports.InngestWorkflow = InngestWorkflow;
1244
+ exports._compatibilityCheck = _compatibilityCheck;
1297
1245
  exports.createStep = createStep;
1298
1246
  exports.init = init;
1299
1247
  exports.serve = serve;
1248
+ //# sourceMappingURL=index.cjs.map
1249
+ //# sourceMappingURL=index.cjs.map