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