@mastra/inngest 0.0.0-cloud-storage-adapter-20251106204059 → 0.0.0-cloud-604-map-nested-flow-details-to-side-panel-20251212192149

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,43 +1,463 @@
1
1
  'use strict';
2
2
 
3
- var crypto = require('crypto');
4
- var web = require('stream/web');
5
- var realtime = require('@inngest/realtime');
6
- var di = require('@mastra/core/di');
7
- var observability = require('@mastra/core/observability');
8
- var stream = require('@mastra/core/stream');
9
3
  var tools = require('@mastra/core/tools');
10
4
  var workflows = require('@mastra/core/workflows');
11
5
  var _constants = require('@mastra/core/workflows/_constants');
6
+ var zod = require('zod');
7
+ var crypto$1 = require('crypto');
8
+ var di = require('@mastra/core/di');
12
9
  var inngest = require('inngest');
10
+ var error = require('@mastra/core/error');
11
+ var realtime = require('@inngest/realtime');
12
+ var events = require('@mastra/core/events');
13
+ var web = require('stream/web');
14
+ var stream = require('@mastra/core/stream');
13
15
  var hono = require('inngest/hono');
14
- var zod = require('zod');
15
16
 
16
17
  // src/index.ts
17
- function serve({
18
- mastra,
19
- inngest,
20
- functions: userFunctions = [],
21
- registerOptions
22
- }) {
23
- const wfs = mastra.listWorkflows();
24
- const workflowFunctions = Array.from(
25
- new Set(
26
- Object.values(wfs).flatMap((wf) => {
27
- if (wf instanceof InngestWorkflow) {
28
- wf.__registerMastra(mastra);
29
- return wf.getFunctions();
18
+ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
19
+ inngestStep;
20
+ inngestAttempts;
21
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
22
+ super({ mastra, options });
23
+ this.inngestStep = inngestStep;
24
+ this.inngestAttempts = inngestAttempts;
25
+ }
26
+ // =============================================================================
27
+ // Hook Overrides
28
+ // =============================================================================
29
+ /**
30
+ * Format errors while preserving Error instances and their custom properties.
31
+ * Uses getErrorFromUnknown to ensure all error properties are preserved.
32
+ */
33
+ formatResultError(error$1, lastOutput) {
34
+ const outputError = lastOutput?.error;
35
+ const errorSource = error$1 || outputError;
36
+ const errorInstance = error.getErrorFromUnknown(errorSource, {
37
+ serializeStack: true,
38
+ // Include stack in JSON for better debugging in Inngest
39
+ fallbackMessage: "Unknown workflow error"
40
+ });
41
+ return errorInstance.toJSON();
42
+ }
43
+ /**
44
+ * Detect InngestWorkflow instances for special nested workflow handling
45
+ */
46
+ isNestedWorkflowStep(step) {
47
+ return step instanceof InngestWorkflow;
48
+ }
49
+ /**
50
+ * Inngest requires requestContext serialization for memoization.
51
+ * When steps are replayed, the original function doesn't re-execute,
52
+ * so requestContext modifications must be captured and restored.
53
+ */
54
+ requiresDurableContextSerialization() {
55
+ return true;
56
+ }
57
+ /**
58
+ * Execute a step with retry logic for Inngest.
59
+ * Retries are handled via step-level retry (RetryAfterError thrown INSIDE step.run()).
60
+ * After retries exhausted, error propagates here and we return a failed result.
61
+ */
62
+ async executeStepWithRetry(stepId, runStep, params) {
63
+ try {
64
+ const result = await this.wrapDurableOperation(stepId, runStep, { delay: params.delay });
65
+ return { ok: true, result };
66
+ } catch (e) {
67
+ const cause = e?.cause;
68
+ if (cause?.status === "failed") {
69
+ params.stepSpan?.error({
70
+ error: e,
71
+ attributes: { status: "failed" }
72
+ });
73
+ if (cause.error && !(cause.error instanceof Error)) {
74
+ cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
30
75
  }
31
- return [];
32
- })
33
- )
34
- );
35
- return hono.serve({
36
- ...registerOptions,
37
- client: inngest,
38
- functions: [...workflowFunctions, ...userFunctions]
39
- });
40
- }
76
+ return { ok: false, error: cause };
77
+ }
78
+ const errorInstance = error.getErrorFromUnknown(e, {
79
+ serializeStack: false,
80
+ fallbackMessage: "Unknown step execution error"
81
+ });
82
+ params.stepSpan?.error({
83
+ error: errorInstance,
84
+ attributes: { status: "failed" }
85
+ });
86
+ return {
87
+ ok: false,
88
+ error: {
89
+ status: "failed",
90
+ error: errorInstance,
91
+ endedAt: Date.now()
92
+ }
93
+ };
94
+ }
95
+ }
96
+ /**
97
+ * Use Inngest's sleep primitive for durability
98
+ */
99
+ async executeSleepDuration(duration, sleepId, workflowId) {
100
+ await this.inngestStep.sleep(`workflow.${workflowId}.sleep.${sleepId}`, duration < 0 ? 0 : duration);
101
+ }
102
+ /**
103
+ * Use Inngest's sleepUntil primitive for durability
104
+ */
105
+ async executeSleepUntilDate(date, sleepUntilId, workflowId) {
106
+ await this.inngestStep.sleepUntil(`workflow.${workflowId}.sleepUntil.${sleepUntilId}`, date);
107
+ }
108
+ /**
109
+ * Wrap durable operations in Inngest step.run() for durability.
110
+ * If retryConfig is provided, throws RetryAfterError INSIDE step.run() to trigger
111
+ * Inngest's step-level retry mechanism (not function-level retry).
112
+ */
113
+ async wrapDurableOperation(operationId, operationFn, retryConfig) {
114
+ return this.inngestStep.run(operationId, async () => {
115
+ try {
116
+ return await operationFn();
117
+ } catch (e) {
118
+ if (retryConfig) {
119
+ const errorInstance = error.getErrorFromUnknown(e, {
120
+ serializeStack: false,
121
+ fallbackMessage: "Unknown step execution error"
122
+ });
123
+ throw new inngest.RetryAfterError(errorInstance.message, retryConfig.delay, {
124
+ cause: {
125
+ status: "failed",
126
+ error: errorInstance,
127
+ endedAt: Date.now()
128
+ }
129
+ });
130
+ }
131
+ throw e;
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * Provide Inngest step primitive in engine context
137
+ */
138
+ getEngineContext() {
139
+ return { step: this.inngestStep };
140
+ }
141
+ /**
142
+ * Execute nested InngestWorkflow using inngestStep.invoke() for durability.
143
+ * This MUST be called directly (not inside step.run()) due to Inngest constraints.
144
+ */
145
+ async executeWorkflowStep(params) {
146
+ if (!(params.step instanceof InngestWorkflow)) {
147
+ return null;
148
+ }
149
+ const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, pubsub, startedAt } = params;
150
+ const isResume = !!resume?.steps?.length;
151
+ let result;
152
+ let runId;
153
+ const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
154
+ try {
155
+ if (isResume) {
156
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
157
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
158
+ workflowName: step.id,
159
+ runId
160
+ });
161
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
162
+ function: step.getFunction(),
163
+ data: {
164
+ inputData,
165
+ initialState: executionContext.state ?? snapshot?.value ?? {},
166
+ runId,
167
+ resume: {
168
+ runId,
169
+ steps: resume.steps.slice(1),
170
+ stepResults: snapshot?.context,
171
+ resumePayload: resume.resumePayload,
172
+ resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
173
+ },
174
+ outputOptions: { includeState: true }
175
+ }
176
+ });
177
+ result = invokeResp.result;
178
+ runId = invokeResp.runId;
179
+ executionContext.state = invokeResp.result.state;
180
+ } else if (isTimeTravel) {
181
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
182
+ workflowName: step.id,
183
+ runId: executionContext.runId
184
+ }) ?? { context: {} };
185
+ const timeTravelParams = workflows.createTimeTravelExecutionParams({
186
+ steps: timeTravel.steps.slice(1),
187
+ inputData: timeTravel.inputData,
188
+ resumeData: timeTravel.resumeData,
189
+ context: timeTravel.nestedStepResults?.[step.id] ?? {},
190
+ nestedStepsContext: timeTravel.nestedStepResults ?? {},
191
+ snapshot,
192
+ graph: step.buildExecutionGraph()
193
+ });
194
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
195
+ function: step.getFunction(),
196
+ data: {
197
+ timeTravel: timeTravelParams,
198
+ initialState: executionContext.state ?? {},
199
+ runId: executionContext.runId,
200
+ outputOptions: { includeState: true }
201
+ }
202
+ });
203
+ result = invokeResp.result;
204
+ runId = invokeResp.runId;
205
+ executionContext.state = invokeResp.result.state;
206
+ } else {
207
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
208
+ function: step.getFunction(),
209
+ data: {
210
+ inputData,
211
+ initialState: executionContext.state ?? {},
212
+ outputOptions: { includeState: true }
213
+ }
214
+ });
215
+ result = invokeResp.result;
216
+ runId = invokeResp.runId;
217
+ executionContext.state = invokeResp.result.state;
218
+ }
219
+ } catch (e) {
220
+ const errorCause = e?.cause;
221
+ if (errorCause && typeof errorCause === "object") {
222
+ result = errorCause;
223
+ runId = errorCause.runId || crypto$1.randomUUID();
224
+ } else {
225
+ runId = crypto$1.randomUUID();
226
+ result = {
227
+ status: "failed",
228
+ error: e instanceof Error ? e : new Error(String(e)),
229
+ steps: {},
230
+ input: inputData
231
+ };
232
+ }
233
+ }
234
+ const res = await this.inngestStep.run(
235
+ `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
236
+ async () => {
237
+ if (result.status === "failed") {
238
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
239
+ type: "watch",
240
+ runId: executionContext.runId,
241
+ data: {
242
+ type: "workflow-step-result",
243
+ payload: {
244
+ id: step.id,
245
+ status: "failed",
246
+ error: result?.error,
247
+ payload: prevOutput
248
+ }
249
+ }
250
+ });
251
+ return { executionContext, result: { status: "failed", error: result?.error } };
252
+ } else if (result.status === "suspended") {
253
+ const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
254
+ const stepRes = stepResult;
255
+ return stepRes?.status === "suspended";
256
+ });
257
+ for (const [stepName, stepResult] of suspendedSteps) {
258
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
259
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
260
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
261
+ type: "watch",
262
+ runId: executionContext.runId,
263
+ data: {
264
+ type: "workflow-step-suspended",
265
+ payload: {
266
+ id: step.id,
267
+ status: "suspended"
268
+ }
269
+ }
270
+ });
271
+ return {
272
+ executionContext,
273
+ result: {
274
+ status: "suspended",
275
+ payload: stepResult.payload,
276
+ suspendPayload: {
277
+ ...stepResult?.suspendPayload,
278
+ __workflow_meta: { runId, path: suspendPath }
279
+ }
280
+ }
281
+ };
282
+ }
283
+ return {
284
+ executionContext,
285
+ result: {
286
+ status: "suspended",
287
+ payload: {}
288
+ }
289
+ };
290
+ } else if (result.status === "tripwire") {
291
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
292
+ type: "watch",
293
+ runId: executionContext.runId,
294
+ data: {
295
+ type: "workflow-step-result",
296
+ payload: {
297
+ id: step.id,
298
+ status: "tripwire",
299
+ error: result?.tripwire?.reason,
300
+ payload: prevOutput
301
+ }
302
+ }
303
+ });
304
+ return {
305
+ executionContext,
306
+ result: {
307
+ status: "tripwire",
308
+ tripwire: result?.tripwire
309
+ }
310
+ };
311
+ }
312
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
313
+ type: "watch",
314
+ runId: executionContext.runId,
315
+ data: {
316
+ type: "workflow-step-result",
317
+ payload: {
318
+ id: step.id,
319
+ status: "success",
320
+ output: result?.result
321
+ }
322
+ }
323
+ });
324
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
325
+ type: "watch",
326
+ runId: executionContext.runId,
327
+ data: {
328
+ type: "workflow-step-finish",
329
+ payload: {
330
+ id: step.id,
331
+ metadata: {}
332
+ }
333
+ }
334
+ });
335
+ return { executionContext, result: { status: "success", output: result?.result } };
336
+ }
337
+ );
338
+ Object.assign(executionContext, res.executionContext);
339
+ return {
340
+ ...res.result,
341
+ startedAt,
342
+ endedAt: Date.now(),
343
+ payload: inputData,
344
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
345
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
346
+ };
347
+ }
348
+ };
349
+ var InngestPubSub = class extends events.PubSub {
350
+ inngest;
351
+ workflowId;
352
+ publishFn;
353
+ subscriptions = /* @__PURE__ */ new Map();
354
+ constructor(inngest, workflowId, publishFn) {
355
+ super();
356
+ this.inngest = inngest;
357
+ this.workflowId = workflowId;
358
+ this.publishFn = publishFn;
359
+ }
360
+ /**
361
+ * Publish an event to Inngest's realtime system.
362
+ *
363
+ * Topic format: "workflow.events.v2.{runId}"
364
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
365
+ */
366
+ async publish(topic, event) {
367
+ if (!this.publishFn) {
368
+ return;
369
+ }
370
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
371
+ if (!match) {
372
+ return;
373
+ }
374
+ const runId = match[1];
375
+ try {
376
+ await this.publishFn({
377
+ channel: `workflow:${this.workflowId}:${runId}`,
378
+ topic: "watch",
379
+ data: event.data
380
+ });
381
+ } catch (err) {
382
+ console.error("InngestPubSub publish error:", err?.message ?? err);
383
+ }
384
+ }
385
+ /**
386
+ * Subscribe to events from Inngest's realtime system.
387
+ *
388
+ * Topic format: "workflow.events.v2.{runId}"
389
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
390
+ */
391
+ async subscribe(topic, cb) {
392
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
393
+ if (!match || !match[1]) {
394
+ return;
395
+ }
396
+ const runId = match[1];
397
+ if (this.subscriptions.has(topic)) {
398
+ this.subscriptions.get(topic).callbacks.add(cb);
399
+ return;
400
+ }
401
+ const callbacks = /* @__PURE__ */ new Set([cb]);
402
+ const channel = `workflow:${this.workflowId}:${runId}`;
403
+ const streamPromise = realtime.subscribe(
404
+ {
405
+ channel,
406
+ topics: ["watch"],
407
+ app: this.inngest
408
+ },
409
+ (message) => {
410
+ const event = {
411
+ id: crypto.randomUUID(),
412
+ type: "watch",
413
+ runId,
414
+ data: message.data,
415
+ createdAt: /* @__PURE__ */ new Date()
416
+ };
417
+ for (const callback of callbacks) {
418
+ callback(event);
419
+ }
420
+ }
421
+ );
422
+ this.subscriptions.set(topic, {
423
+ unsubscribe: () => {
424
+ streamPromise.then((stream) => stream.cancel()).catch((err) => {
425
+ console.error("InngestPubSub unsubscribe error:", err);
426
+ });
427
+ },
428
+ callbacks
429
+ });
430
+ }
431
+ /**
432
+ * Unsubscribe a callback from a topic.
433
+ * If no callbacks remain, the underlying Inngest subscription is cancelled.
434
+ */
435
+ async unsubscribe(topic, cb) {
436
+ const sub = this.subscriptions.get(topic);
437
+ if (!sub) {
438
+ return;
439
+ }
440
+ sub.callbacks.delete(cb);
441
+ if (sub.callbacks.size === 0) {
442
+ sub.unsubscribe();
443
+ this.subscriptions.delete(topic);
444
+ }
445
+ }
446
+ /**
447
+ * Flush any pending operations. No-op for Inngest.
448
+ */
449
+ async flush() {
450
+ }
451
+ /**
452
+ * Clean up all subscriptions during graceful shutdown.
453
+ */
454
+ async close() {
455
+ for (const [, sub] of this.subscriptions) {
456
+ sub.unsubscribe();
457
+ }
458
+ this.subscriptions.clear();
459
+ }
460
+ };
41
461
  var InngestRun = class extends workflows.Run {
42
462
  inngest;
43
463
  serializedStepGraph;
@@ -49,27 +469,77 @@ var InngestRun = class extends workflows.Run {
49
469
  this.#mastra = params.mastra;
50
470
  }
51
471
  async getRuns(eventId) {
52
- const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
53
- headers: {
54
- Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
472
+ const maxRetries = 3;
473
+ let lastError = null;
474
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
475
+ try {
476
+ const response = await fetch(
477
+ `${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
478
+ {
479
+ headers: {
480
+ Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
481
+ }
482
+ }
483
+ );
484
+ if (response.status === 429) {
485
+ const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
486
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
487
+ continue;
488
+ }
489
+ if (!response.ok) {
490
+ throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
491
+ }
492
+ const text = await response.text();
493
+ if (!text) {
494
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
495
+ continue;
496
+ }
497
+ const json = JSON.parse(text);
498
+ return json.data;
499
+ } catch (error) {
500
+ lastError = error;
501
+ if (attempt < maxRetries - 1) {
502
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
503
+ }
55
504
  }
56
- });
57
- const json = await response.json();
58
- return json.data;
505
+ }
506
+ throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
59
507
  }
60
- async getRunOutput(eventId) {
61
- let runs = await this.getRuns(eventId);
508
+ async getRunOutput(eventId, maxWaitMs = 3e5) {
509
+ const startTime = Date.now();
62
510
  const storage = this.#mastra?.getStorage();
63
- while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
64
- await new Promise((resolve) => setTimeout(resolve, 1e3));
65
- runs = await this.getRuns(eventId);
511
+ while (Date.now() - startTime < maxWaitMs) {
512
+ let runs;
513
+ try {
514
+ runs = await this.getRuns(eventId);
515
+ } catch (error) {
516
+ if (error instanceof inngest.NonRetriableError) {
517
+ throw error;
518
+ }
519
+ throw new inngest.NonRetriableError(
520
+ `Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
521
+ );
522
+ }
523
+ if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
524
+ return runs[0];
525
+ }
66
526
  if (runs?.[0]?.status === "Failed") {
67
527
  const snapshot = await storage?.loadWorkflowSnapshot({
68
528
  workflowName: this.workflowId,
69
529
  runId: this.runId
70
530
  });
531
+ if (snapshot?.context) {
532
+ snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
533
+ }
71
534
  return {
72
- output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
535
+ output: {
536
+ result: {
537
+ steps: snapshot?.context,
538
+ status: "failed",
539
+ // Get the original error from NonRetriableError's cause (which contains the workflow result)
540
+ error: error.getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
541
+ }
542
+ }
73
543
  };
74
544
  }
75
545
  if (runs?.[0]?.status === "Cancelled") {
@@ -79,8 +549,9 @@ var InngestRun = class extends workflows.Run {
79
549
  });
80
550
  return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
81
551
  }
552
+ await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
82
553
  }
83
- return runs?.[0];
554
+ throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
84
555
  }
85
556
  async cancel() {
86
557
  const storage = this.#mastra?.getStorage();
@@ -101,7 +572,8 @@ var InngestRun = class extends workflows.Run {
101
572
  resourceId: this.resourceId,
102
573
  snapshot: {
103
574
  ...snapshot,
104
- status: "canceled"
575
+ status: "canceled",
576
+ value: snapshot.value
105
577
  }
106
578
  });
107
579
  }
@@ -109,12 +581,58 @@ var InngestRun = class extends workflows.Run {
109
581
  async start(params) {
110
582
  return this._start(params);
111
583
  }
584
+ /**
585
+ * Starts the workflow execution without waiting for completion (fire-and-forget).
586
+ * Returns immediately with the runId after sending the event to Inngest.
587
+ * The workflow executes independently in Inngest.
588
+ * Use this when you don't need to wait for the result or want to avoid polling failures.
589
+ */
590
+ async startAsync(params) {
591
+ await this.#mastra.getStorage()?.persistWorkflowSnapshot({
592
+ workflowName: this.workflowId,
593
+ runId: this.runId,
594
+ resourceId: this.resourceId,
595
+ snapshot: {
596
+ runId: this.runId,
597
+ serializedStepGraph: this.serializedStepGraph,
598
+ status: "running",
599
+ value: {},
600
+ context: {},
601
+ activePaths: [],
602
+ suspendedPaths: {},
603
+ activeStepsPath: {},
604
+ resumeLabels: {},
605
+ waitingPaths: {},
606
+ timestamp: Date.now()
607
+ }
608
+ });
609
+ const inputDataToUse = await this._validateInput(params.inputData);
610
+ const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
611
+ const eventOutput = await this.inngest.send({
612
+ name: `workflow.${this.workflowId}`,
613
+ data: {
614
+ inputData: inputDataToUse,
615
+ initialState: initialStateToUse,
616
+ runId: this.runId,
617
+ resourceId: this.resourceId,
618
+ outputOptions: params.outputOptions,
619
+ tracingOptions: params.tracingOptions,
620
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
621
+ }
622
+ });
623
+ const eventId = eventOutput.ids[0];
624
+ if (!eventId) {
625
+ throw new Error("Event ID is not set");
626
+ }
627
+ return { runId: this.runId };
628
+ }
112
629
  async _start({
113
630
  inputData,
114
631
  initialState,
115
632
  outputOptions,
116
633
  tracingOptions,
117
- format
634
+ format,
635
+ requestContext
118
636
  }) {
119
637
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
120
638
  workflowName: this.workflowId,
@@ -123,14 +641,15 @@ var InngestRun = class extends workflows.Run {
123
641
  snapshot: {
124
642
  runId: this.runId,
125
643
  serializedStepGraph: this.serializedStepGraph,
644
+ status: "running",
126
645
  value: {},
127
646
  context: {},
128
647
  activePaths: [],
129
648
  suspendedPaths: {},
649
+ activeStepsPath: {},
130
650
  resumeLabels: {},
131
651
  waitingPaths: {},
132
- timestamp: Date.now(),
133
- status: "running"
652
+ timestamp: Date.now()
134
653
  }
135
654
  });
136
655
  const inputDataToUse = await this._validateInput(inputData);
@@ -144,7 +663,8 @@ var InngestRun = class extends workflows.Run {
144
663
  resourceId: this.resourceId,
145
664
  outputOptions,
146
665
  tracingOptions,
147
- format
666
+ format,
667
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
148
668
  }
149
669
  });
150
670
  const eventId = eventOutput.ids[0];
@@ -153,9 +673,7 @@ var InngestRun = class extends workflows.Run {
153
673
  }
154
674
  const runOutput = await this.getRunOutput(eventId);
155
675
  const result = runOutput?.output?.result;
156
- if (result.status === "failed") {
157
- result.error = new Error(result.error);
158
- }
676
+ this.hydrateFailedResult(result);
159
677
  if (result.status !== "suspended") {
160
678
  this.cleanup?.();
161
679
  }
@@ -174,15 +692,23 @@ var InngestRun = class extends workflows.Run {
174
692
  }
175
693
  async _resume(params) {
176
694
  const storage = this.#mastra?.getStorage();
177
- const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
178
- (step) => typeof step === "string" ? step : step?.id
179
- );
695
+ let steps = [];
696
+ if (typeof params.step === "string") {
697
+ steps = params.step.split(".");
698
+ } else {
699
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
700
+ (step) => typeof step === "string" ? step : step?.id
701
+ );
702
+ }
180
703
  const snapshot = await storage?.loadWorkflowSnapshot({
181
704
  workflowName: this.workflowId,
182
705
  runId: this.runId
183
706
  });
184
707
  const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
185
708
  const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
709
+ const persistedRequestContext = snapshot?.requestContext ?? {};
710
+ const newRequestContext = params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {};
711
+ const mergedRequestContext = { ...persistedRequestContext, ...newRequestContext };
186
712
  const eventOutput = await this.inngest.send({
187
713
  name: `workflow.${this.workflowId}`,
188
714
  data: {
@@ -195,9 +721,9 @@ var InngestRun = class extends workflows.Run {
195
721
  steps,
196
722
  stepResults: snapshot?.context,
197
723
  resumePayload: resumeDataToUse,
198
- // @ts-ignore
199
- resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
200
- }
724
+ resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
725
+ },
726
+ requestContext: mergedRequestContext
201
727
  }
202
728
  });
203
729
  const eventId = eventOutput.ids[0];
@@ -206,20 +732,108 @@ var InngestRun = class extends workflows.Run {
206
732
  }
207
733
  const runOutput = await this.getRunOutput(eventId);
208
734
  const result = runOutput?.output?.result;
209
- if (result.status === "failed") {
210
- result.error = new Error(result.error);
211
- }
735
+ this.hydrateFailedResult(result);
212
736
  return result;
213
737
  }
214
- watch(cb) {
215
- let active = true;
216
- const streamPromise = realtime.subscribe(
217
- {
218
- channel: `workflow:${this.workflowId}:${this.runId}`,
219
- topics: ["watch"],
220
- app: this.inngest
221
- },
222
- (message) => {
738
+ async timeTravel(params) {
739
+ const p = this._timeTravel(params).then((result) => {
740
+ if (result.status !== "suspended") {
741
+ this.closeStreamAction?.().catch(() => {
742
+ });
743
+ }
744
+ return result;
745
+ });
746
+ this.executionResults = p;
747
+ return p;
748
+ }
749
+ async _timeTravel(params) {
750
+ if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
751
+ throw new Error("Step is required and must be a valid step or array of steps");
752
+ }
753
+ let steps = [];
754
+ if (typeof params.step === "string") {
755
+ steps = params.step.split(".");
756
+ } else {
757
+ steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
758
+ (step) => typeof step === "string" ? step : step?.id
759
+ );
760
+ }
761
+ if (steps.length === 0) {
762
+ throw new Error("No steps provided to timeTravel");
763
+ }
764
+ const storage = this.#mastra?.getStorage();
765
+ const snapshot = await storage?.loadWorkflowSnapshot({
766
+ workflowName: this.workflowId,
767
+ runId: this.runId
768
+ });
769
+ if (!snapshot) {
770
+ await storage?.persistWorkflowSnapshot({
771
+ workflowName: this.workflowId,
772
+ runId: this.runId,
773
+ resourceId: this.resourceId,
774
+ snapshot: {
775
+ runId: this.runId,
776
+ serializedStepGraph: this.serializedStepGraph,
777
+ status: "pending",
778
+ value: {},
779
+ context: {},
780
+ activePaths: [],
781
+ suspendedPaths: {},
782
+ activeStepsPath: {},
783
+ resumeLabels: {},
784
+ waitingPaths: {},
785
+ timestamp: Date.now()
786
+ }
787
+ });
788
+ }
789
+ if (snapshot?.status === "running") {
790
+ throw new Error("This workflow run is still running, cannot time travel");
791
+ }
792
+ let inputDataToUse = params.inputData;
793
+ if (inputDataToUse && steps.length === 1) {
794
+ inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
795
+ }
796
+ const timeTravelData = workflows.createTimeTravelExecutionParams({
797
+ steps,
798
+ inputData: inputDataToUse,
799
+ resumeData: params.resumeData,
800
+ context: params.context,
801
+ nestedStepsContext: params.nestedStepsContext,
802
+ snapshot: snapshot ?? { context: {} },
803
+ graph: this.executionGraph,
804
+ initialState: params.initialState
805
+ });
806
+ const eventOutput = await this.inngest.send({
807
+ name: `workflow.${this.workflowId}`,
808
+ data: {
809
+ initialState: timeTravelData.state,
810
+ runId: this.runId,
811
+ workflowId: this.workflowId,
812
+ stepResults: timeTravelData.stepResults,
813
+ timeTravel: timeTravelData,
814
+ tracingOptions: params.tracingOptions,
815
+ outputOptions: params.outputOptions,
816
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
817
+ }
818
+ });
819
+ const eventId = eventOutput.ids[0];
820
+ if (!eventId) {
821
+ throw new Error("Event ID is not set");
822
+ }
823
+ const runOutput = await this.getRunOutput(eventId);
824
+ const result = runOutput?.output?.result;
825
+ this.hydrateFailedResult(result);
826
+ return result;
827
+ }
828
+ watch(cb) {
829
+ let active = true;
830
+ const streamPromise = realtime.subscribe(
831
+ {
832
+ channel: `workflow:${this.workflowId}:${this.runId}`,
833
+ topics: ["watch"],
834
+ app: this.inngest
835
+ },
836
+ (message) => {
223
837
  if (active) {
224
838
  cb(message.data);
225
839
  }
@@ -237,14 +851,14 @@ var InngestRun = class extends workflows.Run {
237
851
  streamLegacy({ inputData, requestContext } = {}) {
238
852
  const { readable, writable } = new TransformStream();
239
853
  const writer = writable.getWriter();
854
+ void writer.write({
855
+ // @ts-ignore
856
+ type: "start",
857
+ // @ts-ignore
858
+ payload: { runId: this.runId }
859
+ });
240
860
  const unwatch = this.watch(async (event) => {
241
861
  try {
242
- await writer.write({
243
- // @ts-ignore
244
- type: "start",
245
- // @ts-ignore
246
- payload: { runId: this.runId }
247
- });
248
862
  const e = {
249
863
  ...event,
250
864
  type: event.type.replace("workflow-", "")
@@ -360,7 +974,90 @@ var InngestRun = class extends workflows.Run {
360
974
  streamVNext(args = {}) {
361
975
  return this.stream(args);
362
976
  }
977
+ timeTravelStream({
978
+ inputData,
979
+ resumeData,
980
+ initialState,
981
+ step,
982
+ context,
983
+ nestedStepsContext,
984
+ requestContext,
985
+ tracingOptions,
986
+ outputOptions
987
+ }) {
988
+ this.closeStreamAction = async () => {
989
+ };
990
+ const self = this;
991
+ const stream$1 = new web.ReadableStream({
992
+ async start(controller) {
993
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
994
+ controller.enqueue({
995
+ type,
996
+ runId: self.runId,
997
+ from,
998
+ payload: {
999
+ stepName: payload?.id,
1000
+ ...payload
1001
+ }
1002
+ });
1003
+ });
1004
+ self.closeStreamAction = async () => {
1005
+ unwatch();
1006
+ try {
1007
+ controller.close();
1008
+ } catch (err) {
1009
+ console.error("Error closing stream:", err);
1010
+ }
1011
+ };
1012
+ const executionResultsPromise = self._timeTravel({
1013
+ inputData,
1014
+ step,
1015
+ context,
1016
+ nestedStepsContext,
1017
+ resumeData,
1018
+ initialState,
1019
+ requestContext,
1020
+ tracingOptions,
1021
+ outputOptions
1022
+ });
1023
+ self.executionResults = executionResultsPromise;
1024
+ let executionResults;
1025
+ try {
1026
+ executionResults = await executionResultsPromise;
1027
+ self.closeStreamAction?.().catch(() => {
1028
+ });
1029
+ if (self.streamOutput) {
1030
+ self.streamOutput.updateResults(executionResults);
1031
+ }
1032
+ } catch (err) {
1033
+ self.streamOutput?.rejectResults(err);
1034
+ self.closeStreamAction?.().catch(() => {
1035
+ });
1036
+ }
1037
+ }
1038
+ });
1039
+ this.streamOutput = new stream.WorkflowRunOutput({
1040
+ runId: this.runId,
1041
+ workflowId: this.workflowId,
1042
+ stream: stream$1
1043
+ });
1044
+ return this.streamOutput;
1045
+ }
1046
+ /**
1047
+ * Hydrates errors in a failed workflow result back to proper Error instances.
1048
+ * This ensures error.cause chains and custom properties are preserved.
1049
+ */
1050
+ hydrateFailedResult(result) {
1051
+ if (result.status === "failed") {
1052
+ result.error = error.getErrorFromUnknown(result.error, { serializeStack: false });
1053
+ if (result.steps) {
1054
+ workflows.hydrateSerializedStepErrors(result.steps);
1055
+ }
1056
+ }
1057
+ }
363
1058
  };
1059
+
1060
+ // src/workflow.ts
364
1061
  var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
365
1062
  #mastra;
366
1063
  inngest;
@@ -369,6 +1066,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
369
1066
  constructor(params, inngest) {
370
1067
  const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
371
1068
  super(workflowParams);
1069
+ this.engineType = "inngest";
372
1070
  const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
373
1071
  ([_, value]) => value !== void 0
374
1072
  );
@@ -394,6 +1092,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
394
1092
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
395
1093
  }
396
1094
  __registerMastra(mastra) {
1095
+ super.__registerMastra(mastra);
397
1096
  this.#mastra = mastra;
398
1097
  this.executionEngine.__registerMastra(mastra);
399
1098
  const updateNested = (step) => {
@@ -412,7 +1111,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
412
1111
  }
413
1112
  }
414
1113
  async createRun(options) {
415
- const runIdToUse = options?.runId || crypto.randomUUID();
1114
+ const runIdToUse = options?.runId || crypto$1.randomUUID();
416
1115
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
417
1116
  {
418
1117
  workflowId: this.id,
@@ -424,7 +1123,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
424
1123
  mastra: this.#mastra,
425
1124
  retryConfig: this.retryConfig,
426
1125
  cleanup: () => this.runs.delete(runIdToUse),
427
- workflowSteps: this.steps
1126
+ workflowSteps: this.steps,
1127
+ workflowEngineType: this.engineType,
1128
+ validateInputs: this.options.validateInputs
428
1129
  },
429
1130
  this.inngest
430
1131
  );
@@ -445,13 +1146,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
445
1146
  value: {},
446
1147
  context: {},
447
1148
  activePaths: [],
1149
+ activeStepsPath: {},
448
1150
  waitingPaths: {},
449
1151
  serializedStepGraph: this.serializedStepGraph,
450
1152
  suspendedPaths: {},
451
1153
  resumeLabels: {},
452
1154
  result: void 0,
453
1155
  error: void 0,
454
- // @ts-ignore
455
1156
  timestamp: Date.now()
456
1157
  }
457
1158
  });
@@ -465,42 +1166,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
465
1166
  this.function = this.inngest.createFunction(
466
1167
  {
467
1168
  id: `workflow.${this.id}`,
468
- // @ts-ignore
469
- retries: this.retryConfig?.attempts ?? 0,
1169
+ retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
470
1170
  cancelOn: [{ event: `cancel.workflow.${this.id}` }],
471
1171
  // Spread flow control configuration
472
1172
  ...this.flowControlConfig
473
1173
  },
474
1174
  { event: `workflow.${this.id}` },
475
1175
  async ({ event, step, attempt, publish }) => {
476
- let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
1176
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
477
1177
  if (!runId) {
478
1178
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
479
- return crypto.randomUUID();
1179
+ return crypto$1.randomUUID();
480
1180
  });
481
1181
  }
482
- const emitter = {
483
- emit: async (event2, data) => {
484
- if (!publish) {
485
- return;
486
- }
487
- try {
488
- await publish({
489
- channel: `workflow:${this.id}:${runId}`,
490
- topic: event2,
491
- data
492
- });
493
- } catch (err) {
494
- this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
495
- }
496
- },
497
- on: (_event, _callback) => {
498
- },
499
- off: (_event, _callback) => {
500
- },
501
- once: (_event, _callback) => {
502
- }
503
- };
1182
+ const pubsub = new InngestPubSub(this.inngest, this.id, publish);
504
1183
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
505
1184
  const result = await engine.execute({
506
1185
  workflowId: this.id,
@@ -510,21 +1189,26 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
510
1189
  serializedStepGraph: this.serializedStepGraph,
511
1190
  input: inputData,
512
1191
  initialState,
513
- emitter,
1192
+ pubsub,
514
1193
  retryConfig: this.retryConfig,
515
- requestContext: new di.RequestContext(),
516
- // TODO
1194
+ requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
517
1195
  resume,
1196
+ timeTravel,
518
1197
  format,
519
1198
  abortController: new AbortController(),
520
1199
  // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
521
1200
  outputOptions,
522
- writableStream: new WritableStream({
523
- write(chunk) {
524
- void emitter.emit("watch", chunk).catch(() => {
1201
+ outputWriter: async (chunk) => {
1202
+ try {
1203
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1204
+ type: "watch",
1205
+ runId,
1206
+ data: chunk
525
1207
  });
1208
+ } catch (err) {
1209
+ this.logger.debug?.("Failed to publish watch event:", err);
526
1210
  }
527
- })
1211
+ }
528
1212
  });
529
1213
  await step.run(`workflow.${this.id}.finalize`, async () => {
530
1214
  if (result.status === "failed") {
@@ -556,30 +1240,63 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
556
1240
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
557
1241
  }
558
1242
  };
1243
+ function serve({
1244
+ mastra,
1245
+ inngest,
1246
+ functions: userFunctions = [],
1247
+ registerOptions
1248
+ }) {
1249
+ const wfs = mastra.listWorkflows();
1250
+ const workflowFunctions = Array.from(
1251
+ new Set(
1252
+ Object.values(wfs).flatMap((wf) => {
1253
+ if (wf instanceof InngestWorkflow) {
1254
+ wf.__registerMastra(mastra);
1255
+ return wf.getFunctions();
1256
+ }
1257
+ return [];
1258
+ })
1259
+ )
1260
+ );
1261
+ return hono.serve({
1262
+ ...registerOptions,
1263
+ client: inngest,
1264
+ functions: [...workflowFunctions, ...userFunctions]
1265
+ });
1266
+ }
1267
+
1268
+ // src/types.ts
1269
+ var _compatibilityCheck = true;
1270
+
1271
+ // src/index.ts
559
1272
  function isAgent(params) {
560
1273
  return params?.component === "AGENT";
561
1274
  }
562
1275
  function isTool(params) {
563
1276
  return params instanceof tools.Tool;
564
1277
  }
1278
+ function isInngestWorkflow(params) {
1279
+ return params instanceof InngestWorkflow;
1280
+ }
565
1281
  function createStep(params, agentOptions) {
1282
+ if (isInngestWorkflow(params)) {
1283
+ return params;
1284
+ }
566
1285
  if (isAgent(params)) {
1286
+ const outputSchema = agentOptions?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
567
1287
  return {
568
1288
  id: params.name,
569
1289
  description: params.getDescription(),
570
- // @ts-ignore
571
1290
  inputSchema: zod.z.object({
572
1291
  prompt: zod.z.string()
573
1292
  // resourceId: z.string().optional(),
574
1293
  // threadId: z.string().optional(),
575
1294
  }),
576
- // @ts-ignore
577
- outputSchema: zod.z.object({
578
- text: zod.z.string()
579
- }),
1295
+ outputSchema,
580
1296
  execute: async ({
581
1297
  inputData,
582
- [_constants.EMITTER_SYMBOL]: emitter,
1298
+ runId,
1299
+ [_constants.PUBSUB_SYMBOL]: pubsub,
583
1300
  [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
584
1301
  requestContext,
585
1302
  tracingContext,
@@ -592,6 +1309,7 @@ function createStep(params, agentOptions) {
592
1309
  streamPromise.resolve = resolve;
593
1310
  streamPromise.reject = reject;
594
1311
  });
1312
+ let structuredResult = null;
595
1313
  const toolData = {
596
1314
  name: params.name,
597
1315
  args: inputData
@@ -605,6 +1323,10 @@ function createStep(params, agentOptions) {
605
1323
  requestContext,
606
1324
  tracingContext,
607
1325
  onFinish: (result) => {
1326
+ const resultWithObject = result;
1327
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1328
+ structuredResult = resultWithObject.object;
1329
+ }
608
1330
  streamPromise.resolve(result.text);
609
1331
  void agentOptions?.onFinish?.(result);
610
1332
  },
@@ -617,6 +1339,10 @@ function createStep(params, agentOptions) {
617
1339
  requestContext,
618
1340
  tracingContext,
619
1341
  onFinish: (result) => {
1342
+ const resultWithObject = result;
1343
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1344
+ structuredResult = resultWithObject.object;
1345
+ }
620
1346
  streamPromise.resolve(result.text);
621
1347
  void agentOptions?.onFinish?.(result);
622
1348
  },
@@ -625,22 +1351,24 @@ function createStep(params, agentOptions) {
625
1351
  stream = modelOutput.fullStream;
626
1352
  }
627
1353
  if (streamFormat === "legacy") {
628
- await emitter.emit("watch", {
629
- type: "tool-call-streaming-start",
630
- ...toolData ?? {}
1354
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1355
+ type: "watch",
1356
+ runId,
1357
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
631
1358
  });
632
1359
  for await (const chunk of stream) {
633
1360
  if (chunk.type === "text-delta") {
634
- await emitter.emit("watch", {
635
- type: "tool-call-delta",
636
- ...toolData ?? {},
637
- argsTextDelta: chunk.textDelta
1361
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1362
+ type: "watch",
1363
+ runId,
1364
+ data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
638
1365
  });
639
1366
  }
640
1367
  }
641
- await emitter.emit("watch", {
642
- type: "tool-call-streaming-finish",
643
- ...toolData ?? {}
1368
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1369
+ type: "watch",
1370
+ runId,
1371
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
644
1372
  });
645
1373
  } else {
646
1374
  for await (const chunk of stream) {
@@ -650,6 +1378,9 @@ function createStep(params, agentOptions) {
650
1378
  if (abortSignal.aborted) {
651
1379
  return abort();
652
1380
  }
1381
+ if (structuredResult !== null) {
1382
+ return structuredResult;
1383
+ }
653
1384
  return {
654
1385
  text: await streamPromise.promise
655
1386
  };
@@ -663,20 +1394,38 @@ function createStep(params, agentOptions) {
663
1394
  }
664
1395
  return {
665
1396
  // TODO: tool probably should have strong id type
666
- // @ts-ignore
667
1397
  id: params.id,
668
1398
  description: params.description,
669
1399
  inputSchema: params.inputSchema,
670
1400
  outputSchema: params.outputSchema,
671
- execute: async ({ inputData, mastra, requestContext, tracingContext, suspend, resumeData }) => {
672
- return params.execute({
673
- context: inputData,
674
- mastra: observability.wrapMastra(mastra, tracingContext),
1401
+ suspendSchema: params.suspendSchema,
1402
+ resumeSchema: params.resumeSchema,
1403
+ execute: async ({
1404
+ inputData,
1405
+ mastra,
1406
+ requestContext,
1407
+ tracingContext,
1408
+ suspend,
1409
+ resumeData,
1410
+ runId,
1411
+ workflowId,
1412
+ state,
1413
+ setState
1414
+ }) => {
1415
+ const toolContext = {
1416
+ mastra,
675
1417
  requestContext,
676
1418
  tracingContext,
677
- suspend,
678
- resumeData
679
- });
1419
+ workflow: {
1420
+ runId,
1421
+ resumeData,
1422
+ suspend,
1423
+ workflowId,
1424
+ state,
1425
+ setState
1426
+ }
1427
+ };
1428
+ return params.execute(inputData, toolContext);
680
1429
  },
681
1430
  component: "TOOL"
682
1431
  };
@@ -710,6 +1459,8 @@ function init(inngest) {
710
1459
  suspendSchema: step.suspendSchema,
711
1460
  stateSchema: step.stateSchema,
712
1461
  execute: step.execute,
1462
+ retries: step.retries,
1463
+ scorers: step.scorers,
713
1464
  component: step.component
714
1465
  };
715
1466
  },
@@ -719,7 +1470,8 @@ function init(inngest) {
719
1470
  inputSchema: workflow.inputSchema,
720
1471
  outputSchema: workflow.outputSchema,
721
1472
  steps: workflow.stepDefs,
722
- mastra: workflow.mastra
1473
+ mastra: workflow.mastra,
1474
+ options: workflow.options
723
1475
  });
724
1476
  wf.setStepFlow(workflow.stepGraph);
725
1477
  wf.commit();
@@ -727,798 +1479,12 @@ function init(inngest) {
727
1479
  }
728
1480
  };
729
1481
  }
730
- var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
731
- inngestStep;
732
- inngestAttempts;
733
- constructor(mastra, inngestStep, inngestAttempts = 0, options) {
734
- super({ mastra, options });
735
- this.inngestStep = inngestStep;
736
- this.inngestAttempts = inngestAttempts;
737
- }
738
- async fmtReturnValue(emitter, stepResults, lastOutput, error) {
739
- const base = {
740
- status: lastOutput.status,
741
- steps: stepResults
742
- };
743
- if (lastOutput.status === "success") {
744
- base.result = lastOutput.output;
745
- } else if (lastOutput.status === "failed") {
746
- base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
747
- } else if (lastOutput.status === "suspended") {
748
- const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
749
- if (stepResult?.status === "suspended") {
750
- const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
751
- return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
752
- }
753
- return [];
754
- });
755
- base.suspended = suspendedStepIds;
756
- }
757
- return base;
758
- }
759
- // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
760
- // await this.inngestStep.sleep(id, duration);
761
- // }
762
- async executeSleep({
763
- workflowId,
764
- runId,
765
- entry,
766
- prevOutput,
767
- stepResults,
768
- emitter,
769
- abortController,
770
- requestContext,
771
- executionContext,
772
- writableStream,
773
- tracingContext
774
- }) {
775
- let { duration, fn } = entry;
776
- const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
777
- type: observability.SpanType.WORKFLOW_SLEEP,
778
- name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
779
- attributes: {
780
- durationMs: duration,
781
- sleepType: fn ? "dynamic" : "fixed"
782
- },
783
- tracingPolicy: this.options?.tracingPolicy
784
- });
785
- if (fn) {
786
- const stepCallId = crypto.randomUUID();
787
- duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
788
- return await fn(
789
- workflows.createDeprecationProxy(
790
- {
791
- runId,
792
- workflowId,
793
- mastra: this.mastra,
794
- requestContext,
795
- inputData: prevOutput,
796
- state: executionContext.state,
797
- setState: (state) => {
798
- executionContext.state = state;
799
- },
800
- retryCount: -1,
801
- tracingContext: {
802
- currentSpan: sleepSpan
803
- },
804
- getInitData: () => stepResults?.input,
805
- getStepResult: workflows.getStepResult.bind(this, stepResults),
806
- // TODO: this function shouldn't have suspend probably?
807
- suspend: async (_suspendPayload) => {
808
- },
809
- bail: () => {
810
- },
811
- abort: () => {
812
- abortController?.abort();
813
- },
814
- [_constants.EMITTER_SYMBOL]: emitter,
815
- [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
816
- engine: { step: this.inngestStep },
817
- abortSignal: abortController?.signal,
818
- writer: new tools.ToolStream(
819
- {
820
- prefix: "workflow-step",
821
- callId: stepCallId,
822
- name: "sleep",
823
- runId
824
- },
825
- writableStream
826
- )
827
- },
828
- {
829
- paramName: "runCount",
830
- deprecationMessage: workflows.runCountDeprecationMessage,
831
- logger: this.logger
832
- }
833
- )
834
- );
835
- });
836
- sleepSpan?.update({
837
- attributes: {
838
- durationMs: duration
839
- }
840
- });
841
- }
842
- try {
843
- await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
844
- sleepSpan?.end();
845
- } catch (e) {
846
- sleepSpan?.error({ error: e });
847
- throw e;
848
- }
849
- }
850
- async executeSleepUntil({
851
- workflowId,
852
- runId,
853
- entry,
854
- prevOutput,
855
- stepResults,
856
- emitter,
857
- abortController,
858
- requestContext,
859
- executionContext,
860
- writableStream,
861
- tracingContext
862
- }) {
863
- let { date, fn } = entry;
864
- const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
865
- type: observability.SpanType.WORKFLOW_SLEEP,
866
- name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
867
- attributes: {
868
- untilDate: date,
869
- durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
870
- sleepType: fn ? "dynamic" : "fixed"
871
- },
872
- tracingPolicy: this.options?.tracingPolicy
873
- });
874
- if (fn) {
875
- date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
876
- const stepCallId = crypto.randomUUID();
877
- return await fn(
878
- workflows.createDeprecationProxy(
879
- {
880
- runId,
881
- workflowId,
882
- mastra: this.mastra,
883
- requestContext,
884
- inputData: prevOutput,
885
- state: executionContext.state,
886
- setState: (state) => {
887
- executionContext.state = state;
888
- },
889
- retryCount: -1,
890
- tracingContext: {
891
- currentSpan: sleepUntilSpan
892
- },
893
- getInitData: () => stepResults?.input,
894
- getStepResult: workflows.getStepResult.bind(this, stepResults),
895
- // TODO: this function shouldn't have suspend probably?
896
- suspend: async (_suspendPayload) => {
897
- },
898
- bail: () => {
899
- },
900
- abort: () => {
901
- abortController?.abort();
902
- },
903
- [_constants.EMITTER_SYMBOL]: emitter,
904
- [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
905
- engine: { step: this.inngestStep },
906
- abortSignal: abortController?.signal,
907
- writer: new tools.ToolStream(
908
- {
909
- prefix: "workflow-step",
910
- callId: stepCallId,
911
- name: "sleep",
912
- runId
913
- },
914
- writableStream
915
- )
916
- },
917
- {
918
- paramName: "runCount",
919
- deprecationMessage: workflows.runCountDeprecationMessage,
920
- logger: this.logger
921
- }
922
- )
923
- );
924
- });
925
- if (date && !(date instanceof Date)) {
926
- date = new Date(date);
927
- }
928
- const time = !date ? 0 : date.getTime() - Date.now();
929
- sleepUntilSpan?.update({
930
- attributes: {
931
- durationMs: Math.max(0, time)
932
- }
933
- });
934
- }
935
- if (!(date instanceof Date)) {
936
- sleepUntilSpan?.end();
937
- return;
938
- }
939
- try {
940
- await this.inngestStep.sleepUntil(entry.id, date);
941
- sleepUntilSpan?.end();
942
- } catch (e) {
943
- sleepUntilSpan?.error({ error: e });
944
- throw e;
945
- }
946
- }
947
- async executeStep({
948
- step,
949
- stepResults,
950
- executionContext,
951
- resume,
952
- prevOutput,
953
- emitter,
954
- abortController,
955
- requestContext,
956
- tracingContext,
957
- writableStream,
958
- disableScorers
959
- }) {
960
- const stepSpan = tracingContext?.currentSpan?.createChildSpan({
961
- name: `workflow step: '${step.id}'`,
962
- type: observability.SpanType.WORKFLOW_STEP,
963
- input: prevOutput,
964
- attributes: {
965
- stepId: step.id
966
- },
967
- tracingPolicy: this.options?.tracingPolicy
968
- });
969
- const { inputData, validationError } = await workflows.validateStepInput({
970
- prevOutput,
971
- step,
972
- validateInputs: this.options?.validateInputs ?? false
973
- });
974
- const startedAt = await this.inngestStep.run(
975
- `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
976
- async () => {
977
- const startedAt2 = Date.now();
978
- await emitter.emit("watch", {
979
- type: "workflow-step-start",
980
- payload: {
981
- id: step.id,
982
- status: "running",
983
- payload: inputData,
984
- startedAt: startedAt2
985
- }
986
- });
987
- return startedAt2;
988
- }
989
- );
990
- if (step instanceof InngestWorkflow) {
991
- const isResume = !!resume?.steps?.length;
992
- let result;
993
- let runId;
994
- try {
995
- if (isResume) {
996
- runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
997
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
998
- workflowName: step.id,
999
- runId
1000
- });
1001
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1002
- function: step.getFunction(),
1003
- data: {
1004
- inputData,
1005
- initialState: executionContext.state ?? snapshot?.value ?? {},
1006
- runId,
1007
- resume: {
1008
- runId,
1009
- steps: resume.steps.slice(1),
1010
- stepResults: snapshot?.context,
1011
- resumePayload: resume.resumePayload,
1012
- // @ts-ignore
1013
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1014
- },
1015
- outputOptions: { includeState: true }
1016
- }
1017
- });
1018
- result = invokeResp.result;
1019
- runId = invokeResp.runId;
1020
- executionContext.state = invokeResp.result.state;
1021
- } else {
1022
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1023
- function: step.getFunction(),
1024
- data: {
1025
- inputData,
1026
- initialState: executionContext.state ?? {},
1027
- outputOptions: { includeState: true }
1028
- }
1029
- });
1030
- result = invokeResp.result;
1031
- runId = invokeResp.runId;
1032
- executionContext.state = invokeResp.result.state;
1033
- }
1034
- } catch (e) {
1035
- const errorCause = e?.cause;
1036
- if (errorCause && typeof errorCause === "object") {
1037
- result = errorCause;
1038
- runId = errorCause.runId || crypto.randomUUID();
1039
- } else {
1040
- runId = crypto.randomUUID();
1041
- result = {
1042
- status: "failed",
1043
- error: e instanceof Error ? e : new Error(String(e)),
1044
- steps: {},
1045
- input: inputData
1046
- };
1047
- }
1048
- }
1049
- const res = await this.inngestStep.run(
1050
- `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
1051
- async () => {
1052
- if (result.status === "failed") {
1053
- await emitter.emit("watch", {
1054
- type: "workflow-step-result",
1055
- payload: {
1056
- id: step.id,
1057
- status: "failed",
1058
- error: result?.error,
1059
- payload: prevOutput
1060
- }
1061
- });
1062
- return { executionContext, result: { status: "failed", error: result?.error } };
1063
- } else if (result.status === "suspended") {
1064
- const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
1065
- const stepRes2 = stepResult;
1066
- return stepRes2?.status === "suspended";
1067
- });
1068
- for (const [stepName, stepResult] of suspendedSteps) {
1069
- const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
1070
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1071
- await emitter.emit("watch", {
1072
- type: "workflow-step-suspended",
1073
- payload: {
1074
- id: step.id,
1075
- status: "suspended"
1076
- }
1077
- });
1078
- return {
1079
- executionContext,
1080
- result: {
1081
- status: "suspended",
1082
- payload: stepResult.payload,
1083
- suspendPayload: {
1084
- ...stepResult?.suspendPayload,
1085
- __workflow_meta: { runId, path: suspendPath }
1086
- }
1087
- }
1088
- };
1089
- }
1090
- return {
1091
- executionContext,
1092
- result: {
1093
- status: "suspended",
1094
- payload: {}
1095
- }
1096
- };
1097
- }
1098
- await emitter.emit("watch", {
1099
- type: "workflow-step-result",
1100
- payload: {
1101
- id: step.id,
1102
- status: "success",
1103
- output: result?.result
1104
- }
1105
- });
1106
- await emitter.emit("watch", {
1107
- type: "workflow-step-finish",
1108
- payload: {
1109
- id: step.id,
1110
- metadata: {}
1111
- }
1112
- });
1113
- return { executionContext, result: { status: "success", output: result?.result } };
1114
- }
1115
- );
1116
- Object.assign(executionContext, res.executionContext);
1117
- return {
1118
- ...res.result,
1119
- startedAt,
1120
- endedAt: Date.now(),
1121
- payload: inputData,
1122
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1123
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1124
- };
1125
- }
1126
- const stepCallId = crypto.randomUUID();
1127
- let stepRes;
1128
- try {
1129
- stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1130
- let execResults;
1131
- let suspended;
1132
- let bailed;
1133
- try {
1134
- if (validationError) {
1135
- throw validationError;
1136
- }
1137
- const result = await step.execute({
1138
- runId: executionContext.runId,
1139
- mastra: this.mastra,
1140
- requestContext,
1141
- writer: new tools.ToolStream(
1142
- {
1143
- prefix: "workflow-step",
1144
- callId: stepCallId,
1145
- name: step.id,
1146
- runId: executionContext.runId
1147
- },
1148
- writableStream
1149
- ),
1150
- state: executionContext?.state ?? {},
1151
- setState: (state) => {
1152
- executionContext.state = state;
1153
- },
1154
- inputData,
1155
- resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1156
- tracingContext: {
1157
- currentSpan: stepSpan
1158
- },
1159
- getInitData: () => stepResults?.input,
1160
- getStepResult: workflows.getStepResult.bind(this, stepResults),
1161
- suspend: async (suspendPayload, suspendOptions) => {
1162
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1163
- if (suspendOptions?.resumeLabel) {
1164
- const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1165
- for (const label of resumeLabel) {
1166
- executionContext.resumeLabels[label] = {
1167
- stepId: step.id,
1168
- foreachIndex: executionContext.foreachIndex
1169
- };
1170
- }
1171
- }
1172
- suspended = { payload: suspendPayload };
1173
- },
1174
- bail: (result2) => {
1175
- bailed = { payload: result2 };
1176
- },
1177
- resume: {
1178
- steps: resume?.steps?.slice(1) || [],
1179
- resumePayload: resume?.resumePayload,
1180
- // @ts-ignore
1181
- runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1182
- },
1183
- [_constants.EMITTER_SYMBOL]: emitter,
1184
- [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1185
- engine: {
1186
- step: this.inngestStep
1187
- },
1188
- abortSignal: abortController.signal
1189
- });
1190
- const endedAt = Date.now();
1191
- execResults = {
1192
- status: "success",
1193
- output: result,
1194
- startedAt,
1195
- endedAt,
1196
- payload: inputData,
1197
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1198
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1199
- };
1200
- } catch (e) {
1201
- const stepFailure = {
1202
- status: "failed",
1203
- payload: inputData,
1204
- error: e instanceof Error ? e.message : String(e),
1205
- endedAt: Date.now(),
1206
- startedAt,
1207
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1208
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1209
- };
1210
- execResults = stepFailure;
1211
- const fallbackErrorMessage = `Step ${step.id} failed`;
1212
- stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1213
- throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1214
- cause: execResults
1215
- });
1216
- }
1217
- if (suspended) {
1218
- execResults = {
1219
- status: "suspended",
1220
- suspendPayload: suspended.payload,
1221
- payload: inputData,
1222
- suspendedAt: Date.now(),
1223
- startedAt,
1224
- resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1225
- resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1226
- };
1227
- } else if (bailed) {
1228
- execResults = {
1229
- status: "bailed",
1230
- output: bailed.payload,
1231
- payload: inputData,
1232
- endedAt: Date.now(),
1233
- startedAt
1234
- };
1235
- }
1236
- if (execResults.status === "suspended") {
1237
- await emitter.emit("watch", {
1238
- type: "workflow-step-suspended",
1239
- payload: {
1240
- id: step.id,
1241
- ...execResults
1242
- }
1243
- });
1244
- } else {
1245
- await emitter.emit("watch", {
1246
- type: "workflow-step-result",
1247
- payload: {
1248
- id: step.id,
1249
- ...execResults
1250
- }
1251
- });
1252
- await emitter.emit("watch", {
1253
- type: "workflow-step-finish",
1254
- payload: {
1255
- id: step.id,
1256
- metadata: {}
1257
- }
1258
- });
1259
- }
1260
- stepSpan?.end({ output: execResults });
1261
- return { result: execResults, executionContext, stepResults };
1262
- });
1263
- } catch (e) {
1264
- const stepFailure = e instanceof Error ? e?.cause : {
1265
- status: "failed",
1266
- error: e instanceof Error ? e.message : String(e),
1267
- payload: inputData,
1268
- startedAt,
1269
- endedAt: Date.now()
1270
- };
1271
- stepRes = {
1272
- result: stepFailure,
1273
- executionContext,
1274
- stepResults: {
1275
- ...stepResults,
1276
- [step.id]: stepFailure
1277
- }
1278
- };
1279
- }
1280
- if (disableScorers !== false && stepRes.result.status === "success") {
1281
- await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1282
- if (step.scorers) {
1283
- await this.runScorers({
1284
- scorers: step.scorers,
1285
- runId: executionContext.runId,
1286
- input: inputData,
1287
- output: stepRes.result,
1288
- workflowId: executionContext.workflowId,
1289
- stepId: step.id,
1290
- requestContext,
1291
- disableScorers,
1292
- tracingContext: { currentSpan: stepSpan }
1293
- });
1294
- }
1295
- });
1296
- }
1297
- Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
1298
- Object.assign(stepResults, stepRes.stepResults);
1299
- executionContext.state = stepRes.executionContext.state;
1300
- return stepRes.result;
1301
- }
1302
- async persistStepUpdate({
1303
- workflowId,
1304
- runId,
1305
- stepResults,
1306
- resourceId,
1307
- executionContext,
1308
- serializedStepGraph,
1309
- workflowStatus,
1310
- result,
1311
- error
1312
- }) {
1313
- await this.inngestStep.run(
1314
- `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
1315
- async () => {
1316
- const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1317
- if (!shouldPersistSnapshot) {
1318
- return;
1319
- }
1320
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1321
- workflowName: workflowId,
1322
- runId,
1323
- resourceId,
1324
- snapshot: {
1325
- runId,
1326
- value: executionContext.state,
1327
- context: stepResults,
1328
- activePaths: [],
1329
- suspendedPaths: executionContext.suspendedPaths,
1330
- resumeLabels: executionContext.resumeLabels,
1331
- waitingPaths: {},
1332
- serializedStepGraph,
1333
- status: workflowStatus,
1334
- result,
1335
- error,
1336
- // @ts-ignore
1337
- timestamp: Date.now()
1338
- }
1339
- });
1340
- }
1341
- );
1342
- }
1343
- async executeConditional({
1344
- workflowId,
1345
- runId,
1346
- entry,
1347
- prevOutput,
1348
- stepResults,
1349
- resume,
1350
- executionContext,
1351
- emitter,
1352
- abortController,
1353
- requestContext,
1354
- writableStream,
1355
- disableScorers,
1356
- tracingContext
1357
- }) {
1358
- const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1359
- type: observability.SpanType.WORKFLOW_CONDITIONAL,
1360
- name: `conditional: '${entry.conditions.length} conditions'`,
1361
- input: prevOutput,
1362
- attributes: {
1363
- conditionCount: entry.conditions.length
1364
- },
1365
- tracingPolicy: this.options?.tracingPolicy
1366
- });
1367
- let execResults;
1368
- const truthyIndexes = (await Promise.all(
1369
- entry.conditions.map(
1370
- (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1371
- const evalSpan = conditionalSpan?.createChildSpan({
1372
- type: observability.SpanType.WORKFLOW_CONDITIONAL_EVAL,
1373
- name: `condition: '${index}'`,
1374
- input: prevOutput,
1375
- attributes: {
1376
- conditionIndex: index
1377
- },
1378
- tracingPolicy: this.options?.tracingPolicy
1379
- });
1380
- try {
1381
- const result = await cond(
1382
- workflows.createDeprecationProxy(
1383
- {
1384
- runId,
1385
- workflowId,
1386
- mastra: this.mastra,
1387
- requestContext,
1388
- retryCount: -1,
1389
- inputData: prevOutput,
1390
- state: executionContext.state,
1391
- setState: (state) => {
1392
- executionContext.state = state;
1393
- },
1394
- tracingContext: {
1395
- currentSpan: evalSpan
1396
- },
1397
- getInitData: () => stepResults?.input,
1398
- getStepResult: workflows.getStepResult.bind(this, stepResults),
1399
- // TODO: this function shouldn't have suspend probably?
1400
- suspend: async (_suspendPayload) => {
1401
- },
1402
- bail: () => {
1403
- },
1404
- abort: () => {
1405
- abortController.abort();
1406
- },
1407
- [_constants.EMITTER_SYMBOL]: emitter,
1408
- [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1409
- engine: {
1410
- step: this.inngestStep
1411
- },
1412
- abortSignal: abortController.signal,
1413
- writer: new tools.ToolStream(
1414
- {
1415
- prefix: "workflow-step",
1416
- callId: crypto.randomUUID(),
1417
- name: "conditional",
1418
- runId
1419
- },
1420
- writableStream
1421
- )
1422
- },
1423
- {
1424
- paramName: "runCount",
1425
- deprecationMessage: workflows.runCountDeprecationMessage,
1426
- logger: this.logger
1427
- }
1428
- )
1429
- );
1430
- evalSpan?.end({
1431
- output: result,
1432
- attributes: {
1433
- result: !!result
1434
- }
1435
- });
1436
- return result ? index : null;
1437
- } catch (e) {
1438
- evalSpan?.error({
1439
- error: e instanceof Error ? e : new Error(String(e)),
1440
- attributes: {
1441
- result: false
1442
- }
1443
- });
1444
- return null;
1445
- }
1446
- })
1447
- )
1448
- )).filter((index) => index !== null);
1449
- const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1450
- conditionalSpan?.update({
1451
- attributes: {
1452
- truthyIndexes,
1453
- selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1454
- }
1455
- });
1456
- const results = await Promise.all(
1457
- stepsToRun.map(async (step, index) => {
1458
- const currStepResult = stepResults[step.step.id];
1459
- if (currStepResult && currStepResult.status === "success") {
1460
- return currStepResult;
1461
- }
1462
- const result = await this.executeStep({
1463
- step: step.step,
1464
- prevOutput,
1465
- stepResults,
1466
- resume,
1467
- executionContext: {
1468
- workflowId,
1469
- runId,
1470
- executionPath: [...executionContext.executionPath, index],
1471
- suspendedPaths: executionContext.suspendedPaths,
1472
- resumeLabels: executionContext.resumeLabels,
1473
- retryConfig: executionContext.retryConfig,
1474
- state: executionContext.state
1475
- },
1476
- emitter,
1477
- abortController,
1478
- requestContext,
1479
- writableStream,
1480
- disableScorers,
1481
- tracingContext: {
1482
- currentSpan: conditionalSpan
1483
- }
1484
- });
1485
- stepResults[step.step.id] = result;
1486
- return result;
1487
- })
1488
- );
1489
- const hasFailed = results.find((result) => result.status === "failed");
1490
- const hasSuspended = results.find((result) => result.status === "suspended");
1491
- if (hasFailed) {
1492
- execResults = { status: "failed", error: hasFailed.error };
1493
- } else if (hasSuspended) {
1494
- execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
1495
- } else {
1496
- execResults = {
1497
- status: "success",
1498
- output: results.reduce((acc, result, index) => {
1499
- if (result.status === "success") {
1500
- acc[stepsToRun[index].step.id] = result.output;
1501
- }
1502
- return acc;
1503
- }, {})
1504
- };
1505
- }
1506
- if (execResults.status === "failed") {
1507
- conditionalSpan?.error({
1508
- error: new Error(execResults.error)
1509
- });
1510
- } else {
1511
- conditionalSpan?.end({
1512
- output: execResults.output || execResults
1513
- });
1514
- }
1515
- return execResults;
1516
- }
1517
- };
1518
1482
 
1519
1483
  exports.InngestExecutionEngine = InngestExecutionEngine;
1484
+ exports.InngestPubSub = InngestPubSub;
1520
1485
  exports.InngestRun = InngestRun;
1521
1486
  exports.InngestWorkflow = InngestWorkflow;
1487
+ exports._compatibilityCheck = _compatibilityCheck;
1522
1488
  exports.createStep = createStep;
1523
1489
  exports.init = init;
1524
1490
  exports.serve = serve;