@mastra/inngest 0.0.0-taofeeqInngest-20250603090617 → 0.0.0-testing-cloud-studios-20260114234039

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