@mastra/inngest 0.0.0-scorers-api-v2-20250801171841 → 0.0.0-scorers-logs-20251208093427

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,302 @@
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
+ }
271
+ await emitter.emit("watch", {
272
+ type: "workflow-step-result",
273
+ payload: {
274
+ id: step.id,
275
+ status: "success",
276
+ output: result?.result
277
+ }
278
+ });
279
+ await emitter.emit("watch", {
280
+ type: "workflow-step-finish",
281
+ payload: {
282
+ id: step.id,
283
+ metadata: {}
284
+ }
285
+ });
286
+ return { executionContext, result: { status: "success", output: result?.result } };
287
+ }
288
+ );
289
+ Object.assign(executionContext, res.executionContext);
290
+ return {
291
+ ...res.result,
292
+ startedAt,
293
+ endedAt: Date.now(),
294
+ payload: inputData,
295
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
296
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
297
+ };
298
+ }
299
+ };
31
300
  var InngestRun = class extends workflows.Run {
32
301
  inngest;
33
302
  serializedStepGraph;
@@ -49,14 +318,21 @@ var InngestRun = class extends workflows.Run {
49
318
  }
50
319
  async getRunOutput(eventId) {
51
320
  let runs = await this.getRuns(eventId);
321
+ const storage = this.#mastra?.getStorage();
52
322
  while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
53
323
  await new Promise((resolve) => setTimeout(resolve, 1e3));
54
324
  runs = await this.getRuns(eventId);
55
325
  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({
326
+ const snapshot = await storage?.loadWorkflowSnapshot({
327
+ workflowName: this.workflowId,
328
+ runId: this.runId
329
+ });
330
+ return {
331
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
332
+ };
333
+ }
334
+ if (runs?.[0]?.status === "Cancelled") {
335
+ const snapshot = await storage?.loadWorkflowSnapshot({
60
336
  workflowName: this.workflowId,
61
337
  runId: this.runId
62
338
  });
@@ -65,56 +341,73 @@ var InngestRun = class extends workflows.Run {
65
341
  }
66
342
  return runs?.[0];
67
343
  }
68
- async sendEvent(event, data) {
69
- await this.inngest.send({
70
- name: `user-event-${event}`,
71
- data
72
- });
73
- }
74
344
  async cancel() {
345
+ const storage = this.#mastra?.getStorage();
75
346
  await this.inngest.send({
76
347
  name: `cancel.workflow.${this.workflowId}`,
77
348
  data: {
78
349
  runId: this.runId
79
350
  }
80
351
  });
81
- const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
352
+ const snapshot = await storage?.loadWorkflowSnapshot({
82
353
  workflowName: this.workflowId,
83
354
  runId: this.runId
84
355
  });
85
356
  if (snapshot) {
86
- await this.#mastra?.storage?.persistWorkflowSnapshot({
357
+ await storage?.persistWorkflowSnapshot({
87
358
  workflowName: this.workflowId,
88
359
  runId: this.runId,
360
+ resourceId: this.resourceId,
89
361
  snapshot: {
90
362
  ...snapshot,
91
- status: "canceled"
363
+ status: "canceled",
364
+ value: snapshot.value
92
365
  }
93
366
  });
94
367
  }
95
368
  }
96
- async start({
97
- inputData
369
+ async start(params) {
370
+ return this._start(params);
371
+ }
372
+ async _start({
373
+ inputData,
374
+ initialState,
375
+ outputOptions,
376
+ tracingOptions,
377
+ format,
378
+ requestContext
98
379
  }) {
99
380
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
100
381
  workflowName: this.workflowId,
101
382
  runId: this.runId,
383
+ resourceId: this.resourceId,
102
384
  snapshot: {
103
385
  runId: this.runId,
104
386
  serializedStepGraph: this.serializedStepGraph,
387
+ status: "running",
105
388
  value: {},
106
389
  context: {},
107
390
  activePaths: [],
108
391
  suspendedPaths: {},
109
- timestamp: Date.now(),
110
- status: "running"
392
+ activeStepsPath: {},
393
+ resumeLabels: {},
394
+ waitingPaths: {},
395
+ timestamp: Date.now()
111
396
  }
112
397
  });
398
+ const inputDataToUse = await this._validateInput(inputData);
399
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
113
400
  const eventOutput = await this.inngest.send({
114
401
  name: `workflow.${this.workflowId}`,
115
402
  data: {
116
- inputData,
117
- runId: this.runId
403
+ inputData: inputDataToUse,
404
+ initialState: initialStateToUse,
405
+ runId: this.runId,
406
+ resourceId: this.resourceId,
407
+ outputOptions,
408
+ tracingOptions,
409
+ format,
410
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
118
411
  }
119
412
  });
120
413
  const eventId = eventOutput.ids[0];
@@ -143,27 +436,131 @@ var InngestRun = class extends workflows.Run {
143
436
  return p;
144
437
  }
145
438
  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({
439
+ const storage = this.#mastra?.getStorage();
440
+ let steps = [];
441
+ if (typeof params.step === "string") {
442
+ steps = params.step.split(".");
443
+ } else {
444
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
445
+ (step) => typeof step === "string" ? step : step?.id
446
+ );
447
+ }
448
+ const snapshot = await storage?.loadWorkflowSnapshot({
150
449
  workflowName: this.workflowId,
151
450
  runId: this.runId
152
451
  });
452
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
453
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
454
+ const persistedRequestContext = snapshot?.requestContext ?? {};
455
+ const newRequestContext = params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {};
456
+ const mergedRequestContext = { ...persistedRequestContext, ...newRequestContext };
153
457
  const eventOutput = await this.inngest.send({
154
458
  name: `workflow.${this.workflowId}`,
155
459
  data: {
156
- inputData: params.resumeData,
460
+ inputData: resumeDataToUse,
461
+ initialState: snapshot?.value ?? {},
157
462
  runId: this.runId,
158
463
  workflowId: this.workflowId,
159
464
  stepResults: snapshot?.context,
160
465
  resume: {
161
466
  steps,
162
467
  stepResults: snapshot?.context,
163
- resumePayload: params.resumeData,
164
- // @ts-ignore
165
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
468
+ resumePayload: resumeDataToUse,
469
+ resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
470
+ },
471
+ requestContext: mergedRequestContext
472
+ }
473
+ });
474
+ const eventId = eventOutput.ids[0];
475
+ if (!eventId) {
476
+ throw new Error("Event ID is not set");
477
+ }
478
+ const runOutput = await this.getRunOutput(eventId);
479
+ const result = runOutput?.output?.result;
480
+ if (result.status === "failed") {
481
+ result.error = new Error(result.error);
482
+ }
483
+ return result;
484
+ }
485
+ async timeTravel(params) {
486
+ const p = this._timeTravel(params).then((result) => {
487
+ if (result.status !== "suspended") {
488
+ this.closeStreamAction?.().catch(() => {
489
+ });
490
+ }
491
+ return result;
492
+ });
493
+ this.executionResults = p;
494
+ return p;
495
+ }
496
+ async _timeTravel(params) {
497
+ if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
498
+ throw new Error("Step is required and must be a valid step or array of steps");
499
+ }
500
+ let steps = [];
501
+ if (typeof params.step === "string") {
502
+ steps = params.step.split(".");
503
+ } else {
504
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
505
+ (step) => typeof step === "string" ? step : step?.id
506
+ );
507
+ }
508
+ if (steps.length === 0) {
509
+ throw new Error("No steps provided to timeTravel");
510
+ }
511
+ const storage = this.#mastra?.getStorage();
512
+ const snapshot = await storage?.loadWorkflowSnapshot({
513
+ workflowName: this.workflowId,
514
+ runId: this.runId
515
+ });
516
+ if (!snapshot) {
517
+ await storage?.persistWorkflowSnapshot({
518
+ workflowName: this.workflowId,
519
+ runId: this.runId,
520
+ resourceId: this.resourceId,
521
+ snapshot: {
522
+ runId: this.runId,
523
+ serializedStepGraph: this.serializedStepGraph,
524
+ status: "pending",
525
+ value: {},
526
+ context: {},
527
+ activePaths: [],
528
+ suspendedPaths: {},
529
+ activeStepsPath: {},
530
+ resumeLabels: {},
531
+ waitingPaths: {},
532
+ timestamp: Date.now()
166
533
  }
534
+ });
535
+ }
536
+ if (snapshot?.status === "running") {
537
+ throw new Error("This workflow run is still running, cannot time travel");
538
+ }
539
+ let inputDataToUse = params.inputData;
540
+ if (inputDataToUse && steps.length === 1) {
541
+ inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
542
+ }
543
+ const timeTravelData = workflows.createTimeTravelExecutionParams({
544
+ steps,
545
+ inputData: inputDataToUse,
546
+ resumeData: params.resumeData,
547
+ context: params.context,
548
+ nestedStepsContext: params.nestedStepsContext,
549
+ snapshot: snapshot ?? { context: {} },
550
+ graph: this.executionGraph,
551
+ initialState: params.initialState
552
+ });
553
+ const eventOutput = await this.inngest.send({
554
+ name: `workflow.${this.workflowId}`,
555
+ data: {
556
+ initialState: timeTravelData.state,
557
+ runId: this.runId,
558
+ workflowId: this.workflowId,
559
+ stepResults: timeTravelData.stepResults,
560
+ timeTravel: timeTravelData,
561
+ tracingOptions: params.tracingOptions,
562
+ outputOptions: params.outputOptions,
563
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
167
564
  }
168
565
  });
169
566
  const eventId = eventOutput.ids[0];
@@ -177,12 +574,12 @@ var InngestRun = class extends workflows.Run {
177
574
  }
178
575
  return result;
179
576
  }
180
- watch(cb, type = "watch") {
577
+ watch(cb) {
181
578
  let active = true;
182
579
  const streamPromise = realtime.subscribe(
183
580
  {
184
581
  channel: `workflow:${this.workflowId}:${this.runId}`,
185
- topics: [type],
582
+ topics: ["watch"],
186
583
  app: this.inngest
187
584
  },
188
585
  (message) => {
@@ -200,16 +597,35 @@ var InngestRun = class extends workflows.Run {
200
597
  });
201
598
  };
202
599
  }
203
- stream({ inputData, runtimeContext } = {}) {
600
+ streamLegacy({ inputData, requestContext } = {}) {
204
601
  const { readable, writable } = new TransformStream();
205
602
  const writer = writable.getWriter();
603
+ void writer.write({
604
+ // @ts-ignore
605
+ type: "start",
606
+ // @ts-ignore
607
+ payload: { runId: this.runId }
608
+ });
206
609
  const unwatch = this.watch(async (event) => {
207
610
  try {
208
- await writer.write(event);
611
+ const e = {
612
+ ...event,
613
+ type: event.type.replace("workflow-", "")
614
+ };
615
+ if (e.type === "step-output") {
616
+ e.type = e.payload.output.type;
617
+ e.payload = e.payload.output.payload;
618
+ }
619
+ await writer.write(e);
209
620
  } catch {
210
621
  }
211
- }, "watch-v2");
622
+ });
212
623
  this.closeStreamAction = async () => {
624
+ await writer.write({
625
+ type: "finish",
626
+ // @ts-ignore
627
+ payload: { runId: this.runId }
628
+ });
213
629
  unwatch();
214
630
  try {
215
631
  await writer.close();
@@ -219,7 +635,7 @@ var InngestRun = class extends workflows.Run {
219
635
  writer.releaseLock();
220
636
  }
221
637
  };
222
- this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
638
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
223
639
  if (result.status !== "suspended") {
224
640
  this.closeStreamAction?.().catch(() => {
225
641
  });
@@ -231,57 +647,190 @@ var InngestRun = class extends workflows.Run {
231
647
  getWorkflowState: () => this.executionResults
232
648
  };
233
649
  }
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;
650
+ stream({
651
+ inputData,
652
+ requestContext,
653
+ tracingOptions,
654
+ closeOnSuspend = true,
655
+ initialState,
656
+ outputOptions
657
+ } = {}) {
658
+ if (this.closeStreamAction && this.streamOutput) {
659
+ return this.streamOutput;
270
660
  }
271
- if (typeof run.snapshot === "string") {
272
- return null;
273
- }
274
- return {
275
- status: run.snapshot.status,
276
- result: run.snapshot.result,
277
- error: run.snapshot.error,
278
- payload: run.snapshot.context?.input,
279
- steps: run.snapshot.context
661
+ this.closeStreamAction = async () => {
280
662
  };
281
- }
282
- __registerMastra(mastra) {
283
- this.#mastra = mastra;
284
- this.executionEngine.__registerMastra(mastra);
663
+ const self = this;
664
+ const stream$1 = new web.ReadableStream({
665
+ async start(controller) {
666
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
667
+ controller.enqueue({
668
+ type,
669
+ runId: self.runId,
670
+ from,
671
+ payload: {
672
+ stepName: payload?.id,
673
+ ...payload
674
+ }
675
+ });
676
+ });
677
+ self.closeStreamAction = async () => {
678
+ unwatch();
679
+ try {
680
+ await controller.close();
681
+ } catch (err) {
682
+ console.error("Error closing stream:", err);
683
+ }
684
+ };
685
+ const executionResultsPromise = self._start({
686
+ inputData,
687
+ requestContext,
688
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
689
+ initialState,
690
+ tracingOptions,
691
+ outputOptions,
692
+ format: "vnext"
693
+ });
694
+ let executionResults;
695
+ try {
696
+ executionResults = await executionResultsPromise;
697
+ if (closeOnSuspend) {
698
+ self.closeStreamAction?.().catch(() => {
699
+ });
700
+ } else if (executionResults.status !== "suspended") {
701
+ self.closeStreamAction?.().catch(() => {
702
+ });
703
+ }
704
+ if (self.streamOutput) {
705
+ self.streamOutput.updateResults(
706
+ executionResults
707
+ );
708
+ }
709
+ } catch (err) {
710
+ self.streamOutput?.rejectResults(err);
711
+ self.closeStreamAction?.().catch(() => {
712
+ });
713
+ }
714
+ }
715
+ });
716
+ this.streamOutput = new stream.WorkflowRunOutput({
717
+ runId: this.runId,
718
+ workflowId: this.workflowId,
719
+ stream: stream$1
720
+ });
721
+ return this.streamOutput;
722
+ }
723
+ streamVNext(args = {}) {
724
+ return this.stream(args);
725
+ }
726
+ timeTravelStream({
727
+ inputData,
728
+ resumeData,
729
+ initialState,
730
+ step,
731
+ context,
732
+ nestedStepsContext,
733
+ requestContext,
734
+ tracingOptions,
735
+ outputOptions
736
+ }) {
737
+ this.closeStreamAction = async () => {
738
+ };
739
+ const self = this;
740
+ const stream$1 = new web.ReadableStream({
741
+ async start(controller) {
742
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
743
+ controller.enqueue({
744
+ type,
745
+ runId: self.runId,
746
+ from,
747
+ payload: {
748
+ stepName: payload?.id,
749
+ ...payload
750
+ }
751
+ });
752
+ });
753
+ self.closeStreamAction = async () => {
754
+ unwatch();
755
+ try {
756
+ controller.close();
757
+ } catch (err) {
758
+ console.error("Error closing stream:", err);
759
+ }
760
+ };
761
+ const executionResultsPromise = self._timeTravel({
762
+ inputData,
763
+ step,
764
+ context,
765
+ nestedStepsContext,
766
+ resumeData,
767
+ initialState,
768
+ requestContext,
769
+ tracingOptions,
770
+ outputOptions
771
+ });
772
+ self.executionResults = executionResultsPromise;
773
+ let executionResults;
774
+ try {
775
+ executionResults = await executionResultsPromise;
776
+ self.closeStreamAction?.().catch(() => {
777
+ });
778
+ if (self.streamOutput) {
779
+ self.streamOutput.updateResults(executionResults);
780
+ }
781
+ } catch (err) {
782
+ self.streamOutput?.rejectResults(err);
783
+ self.closeStreamAction?.().catch(() => {
784
+ });
785
+ }
786
+ }
787
+ });
788
+ this.streamOutput = new stream.WorkflowRunOutput({
789
+ runId: this.runId,
790
+ workflowId: this.workflowId,
791
+ stream: stream$1
792
+ });
793
+ return this.streamOutput;
794
+ }
795
+ };
796
+
797
+ // src/workflow.ts
798
+ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
799
+ #mastra;
800
+ inngest;
801
+ function;
802
+ flowControlConfig;
803
+ constructor(params, inngest) {
804
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
805
+ super(workflowParams);
806
+ this.engineType = "inngest";
807
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
808
+ ([_, value]) => value !== void 0
809
+ );
810
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
811
+ this.#mastra = params.mastra;
812
+ this.inngest = inngest;
813
+ }
814
+ async listWorkflowRuns(args) {
815
+ const storage = this.#mastra?.getStorage();
816
+ if (!storage) {
817
+ this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
818
+ return { runs: [], total: 0 };
819
+ }
820
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
821
+ }
822
+ async getWorkflowRunById(runId) {
823
+ const storage = this.#mastra?.getStorage();
824
+ if (!storage) {
825
+ this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
826
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
827
+ }
828
+ const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
829
+ return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
830
+ }
831
+ __registerMastra(mastra) {
832
+ this.#mastra = mastra;
833
+ this.executionEngine.__registerMastra(mastra);
285
834
  const updateNested = (step) => {
286
835
  if ((step.type === "step" || step.type === "loop" || step.type === "foreach") && step.step instanceof _InngestWorkflow) {
287
836
  step.step.__registerMastra(mastra);
@@ -297,56 +846,49 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
297
846
  }
298
847
  }
299
848
  }
300
- createRun(options) {
849
+ async createRun(options) {
301
850
  const runIdToUse = options?.runId || crypto.randomUUID();
302
851
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
303
852
  {
304
853
  workflowId: this.id,
305
854
  runId: runIdToUse,
855
+ resourceId: options?.resourceId,
306
856
  executionEngine: this.executionEngine,
307
857
  executionGraph: this.executionGraph,
308
858
  serializedStepGraph: this.serializedStepGraph,
309
859
  mastra: this.#mastra,
310
860
  retryConfig: this.retryConfig,
311
- cleanup: () => this.runs.delete(runIdToUse)
861
+ cleanup: () => this.runs.delete(runIdToUse),
862
+ workflowSteps: this.steps,
863
+ workflowEngineType: this.engineType,
864
+ validateInputs: this.options.validateInputs
312
865
  },
313
866
  this.inngest
314
867
  );
315
868
  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) {
869
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
870
+ workflowStatus: run.workflowRunStatus,
871
+ stepResults: {}
872
+ });
873
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
874
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
336
875
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
337
876
  workflowName: this.id,
338
877
  runId: runIdToUse,
878
+ resourceId: options?.resourceId,
339
879
  snapshot: {
340
880
  runId: runIdToUse,
341
881
  status: "pending",
342
882
  value: {},
343
883
  context: {},
344
884
  activePaths: [],
885
+ activeStepsPath: {},
886
+ waitingPaths: {},
345
887
  serializedStepGraph: this.serializedStepGraph,
346
888
  suspendedPaths: {},
889
+ resumeLabels: {},
347
890
  result: void 0,
348
891
  error: void 0,
349
- // @ts-ignore
350
892
  timestamp: Date.now()
351
893
  }
352
894
  });
@@ -360,13 +902,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
360
902
  this.function = this.inngest.createFunction(
361
903
  {
362
904
  id: `workflow.${this.id}`,
363
- // @ts-ignore
364
- retries: this.retryConfig?.attempts ?? 0,
365
- cancelOn: [{ event: `cancel.workflow.${this.id}` }]
905
+ retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
906
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
907
+ // Spread flow control configuration
908
+ ...this.flowControlConfig
366
909
  },
367
910
  { event: `workflow.${this.id}` },
368
911
  async ({ event, step, attempt, publish }) => {
369
- let { inputData, runId, resume } = event.data;
912
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
370
913
  if (!runId) {
371
914
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
372
915
  return crypto.randomUUID();
@@ -394,19 +937,38 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
394
937
  once: (_event, _callback) => {
395
938
  }
396
939
  };
397
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
940
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
398
941
  const result = await engine.execute({
399
942
  workflowId: this.id,
400
943
  runId,
944
+ resourceId,
401
945
  graph: this.executionGraph,
402
946
  serializedStepGraph: this.serializedStepGraph,
403
947
  input: inputData,
948
+ initialState,
404
949
  emitter,
405
950
  retryConfig: this.retryConfig,
406
- runtimeContext: new di.RuntimeContext(),
407
- // TODO
951
+ requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
408
952
  resume,
409
- abortController: new AbortController()
953
+ timeTravel,
954
+ format,
955
+ abortController: new AbortController(),
956
+ // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
957
+ outputOptions,
958
+ writableStream: new web.WritableStream({
959
+ write(chunk) {
960
+ void emitter.emit("watch", chunk).catch(() => {
961
+ });
962
+ }
963
+ })
964
+ });
965
+ await step.run(`workflow.${this.id}.finalize`, async () => {
966
+ if (result.status === "failed") {
967
+ throw new inngest.NonRetriableError(`Workflow failed`, {
968
+ cause: result
969
+ });
970
+ }
971
+ return result;
410
972
  });
411
973
  return { result, runId };
412
974
  }
@@ -430,27 +992,70 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
430
992
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
431
993
  }
432
994
  };
995
+ function serve({
996
+ mastra,
997
+ inngest,
998
+ functions: userFunctions = [],
999
+ registerOptions
1000
+ }) {
1001
+ const wfs = mastra.listWorkflows();
1002
+ const workflowFunctions = Array.from(
1003
+ new Set(
1004
+ Object.values(wfs).flatMap((wf) => {
1005
+ if (wf instanceof InngestWorkflow) {
1006
+ wf.__registerMastra(mastra);
1007
+ return wf.getFunctions();
1008
+ }
1009
+ return [];
1010
+ })
1011
+ )
1012
+ );
1013
+ return hono.serve({
1014
+ ...registerOptions,
1015
+ client: inngest,
1016
+ functions: [...workflowFunctions, ...userFunctions]
1017
+ });
1018
+ }
1019
+
1020
+ // src/types.ts
1021
+ var _compatibilityCheck = true;
1022
+
1023
+ // src/index.ts
433
1024
  function isAgent(params) {
434
1025
  return params?.component === "AGENT";
435
1026
  }
436
1027
  function isTool(params) {
437
1028
  return params instanceof tools.Tool;
438
1029
  }
439
- function createStep(params) {
1030
+ function isInngestWorkflow(params) {
1031
+ return params instanceof InngestWorkflow;
1032
+ }
1033
+ function createStep(params, agentOptions) {
1034
+ if (isInngestWorkflow(params)) {
1035
+ return params;
1036
+ }
440
1037
  if (isAgent(params)) {
441
1038
  return {
442
1039
  id: params.name,
443
- // @ts-ignore
1040
+ description: params.getDescription(),
444
1041
  inputSchema: zod.z.object({
445
1042
  prompt: zod.z.string()
446
1043
  // resourceId: z.string().optional(),
447
1044
  // threadId: z.string().optional(),
448
1045
  }),
449
- // @ts-ignore
450
1046
  outputSchema: zod.z.object({
451
1047
  text: zod.z.string()
452
1048
  }),
453
- execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
1049
+ execute: async ({
1050
+ inputData,
1051
+ [_constants.EMITTER_SYMBOL]: emitter,
1052
+ [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1053
+ requestContext,
1054
+ tracingContext,
1055
+ abortSignal,
1056
+ abort,
1057
+ writer
1058
+ }) => {
454
1059
  let streamPromise = {};
455
1060
  streamPromise.promise = new Promise((resolve, reject) => {
456
1061
  streamPromise.resolve = resolve;
@@ -460,50 +1065,65 @@ function createStep(params) {
460
1065
  name: params.name,
461
1066
  args: inputData
462
1067
  };
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();
1068
+ let stream;
1069
+ if ((await params.getModel()).specificationVersion === "v1") {
1070
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
1071
+ ...agentOptions ?? {},
1072
+ // resourceId: inputData.resourceId,
1073
+ // threadId: inputData.threadId,
1074
+ requestContext,
1075
+ tracingContext,
1076
+ onFinish: (result) => {
1077
+ streamPromise.resolve(result.text);
1078
+ void agentOptions?.onFinish?.(result);
1079
+ },
1080
+ abortSignal
1081
+ });
1082
+ stream = fullStream;
1083
+ } else {
1084
+ const modelOutput = await params.stream(inputData.prompt, {
1085
+ ...agentOptions ?? {},
1086
+ requestContext,
1087
+ tracingContext,
1088
+ onFinish: (result) => {
1089
+ streamPromise.resolve(result.text);
1090
+ void agentOptions?.onFinish?.(result);
1091
+ },
1092
+ abortSignal
1093
+ });
1094
+ stream = modelOutput.fullStream;
478
1095
  }
479
- for await (const chunk of fullStream) {
480
- switch (chunk.type) {
481
- case "text-delta":
482
- await emitter.emit("watch-v2", {
1096
+ if (streamFormat === "legacy") {
1097
+ await emitter.emit("watch", {
1098
+ type: "tool-call-streaming-start",
1099
+ ...toolData ?? {}
1100
+ });
1101
+ for await (const chunk of stream) {
1102
+ if (chunk.type === "text-delta") {
1103
+ await emitter.emit("watch", {
483
1104
  type: "tool-call-delta",
484
- ...toolData,
1105
+ ...toolData ?? {},
485
1106
  argsTextDelta: chunk.textDelta
486
1107
  });
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;
1108
+ }
1109
+ }
1110
+ await emitter.emit("watch", {
1111
+ type: "tool-call-streaming-finish",
1112
+ ...toolData ?? {}
1113
+ });
1114
+ } else {
1115
+ for await (const chunk of stream) {
1116
+ await writer.write(chunk);
501
1117
  }
502
1118
  }
1119
+ if (abortSignal.aborted) {
1120
+ return abort();
1121
+ }
503
1122
  return {
504
1123
  text: await streamPromise.promise
505
1124
  };
506
- }
1125
+ },
1126
+ component: params.component
507
1127
  };
508
1128
  }
509
1129
  if (isTool(params)) {
@@ -512,17 +1132,40 @@ function createStep(params) {
512
1132
  }
513
1133
  return {
514
1134
  // TODO: tool probably should have strong id type
515
- // @ts-ignore
516
1135
  id: params.id,
1136
+ description: params.description,
517
1137
  inputSchema: params.inputSchema,
518
1138
  outputSchema: params.outputSchema,
519
- execute: async ({ inputData, mastra, runtimeContext }) => {
520
- return params.execute({
521
- context: inputData,
1139
+ suspendSchema: params.suspendSchema,
1140
+ resumeSchema: params.resumeSchema,
1141
+ execute: async ({
1142
+ inputData,
1143
+ mastra,
1144
+ requestContext,
1145
+ tracingContext,
1146
+ suspend,
1147
+ resumeData,
1148
+ runId,
1149
+ workflowId,
1150
+ state,
1151
+ setState
1152
+ }) => {
1153
+ const toolContext = {
522
1154
  mastra,
523
- runtimeContext
524
- });
525
- }
1155
+ requestContext,
1156
+ tracingContext,
1157
+ workflow: {
1158
+ runId,
1159
+ resumeData,
1160
+ suspend,
1161
+ workflowId,
1162
+ state,
1163
+ setState
1164
+ }
1165
+ };
1166
+ return params.execute(inputData, toolContext);
1167
+ },
1168
+ component: "TOOL"
526
1169
  };
527
1170
  }
528
1171
  return {
@@ -538,7 +1181,10 @@ function createStep(params) {
538
1181
  function init(inngest) {
539
1182
  return {
540
1183
  createWorkflow(params) {
541
- return new InngestWorkflow(params, inngest);
1184
+ return new InngestWorkflow(
1185
+ params,
1186
+ inngest
1187
+ );
542
1188
  },
543
1189
  createStep,
544
1190
  cloneStep(step, opts) {
@@ -547,7 +1193,13 @@ function init(inngest) {
547
1193
  description: step.description,
548
1194
  inputSchema: step.inputSchema,
549
1195
  outputSchema: step.outputSchema,
550
- execute: step.execute
1196
+ resumeSchema: step.resumeSchema,
1197
+ suspendSchema: step.suspendSchema,
1198
+ stateSchema: step.stateSchema,
1199
+ execute: step.execute,
1200
+ retries: step.retries,
1201
+ scorers: step.scorers,
1202
+ component: step.component
551
1203
  };
552
1204
  },
553
1205
  cloneWorkflow(workflow, opts) {
@@ -556,7 +1208,8 @@ function init(inngest) {
556
1208
  inputSchema: workflow.inputSchema,
557
1209
  outputSchema: workflow.outputSchema,
558
1210
  steps: workflow.stepDefs,
559
- mastra: workflow.mastra
1211
+ mastra: workflow.mastra,
1212
+ options: workflow.options
560
1213
  });
561
1214
  wf.setStepFlow(workflow.stepGraph);
562
1215
  wf.commit();
@@ -564,736 +1217,11 @@ function init(inngest) {
564
1217
  }
565
1218
  };
566
1219
  }
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
1220
 
1294
1221
  exports.InngestExecutionEngine = InngestExecutionEngine;
1295
1222
  exports.InngestRun = InngestRun;
1296
1223
  exports.InngestWorkflow = InngestWorkflow;
1224
+ exports._compatibilityCheck = _compatibilityCheck;
1297
1225
  exports.createStep = createStep;
1298
1226
  exports.init = init;
1299
1227
  exports.serve = serve;