@mastra/inngest 1.0.0-beta.8 → 1.0.0

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,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var agent = require('@mastra/core/agent');
4
+ var error = require('@mastra/core/error');
5
+ var observability = require('@mastra/core/observability');
6
+ var processors = require('@mastra/core/processors');
3
7
  var tools = require('@mastra/core/tools');
4
8
  var workflows = require('@mastra/core/workflows');
5
9
  var _constants = require('@mastra/core/workflows/_constants');
@@ -7,7 +11,6 @@ var zod = require('zod');
7
11
  var crypto$1 = require('crypto');
8
12
  var di = require('@mastra/core/di');
9
13
  var inngest = require('inngest');
10
- var error = require('@mastra/core/error');
11
14
  var realtime = require('@inngest/realtime');
12
15
  var events = require('@mastra/core/events');
13
16
  var web = require('stream/web');
@@ -60,38 +63,46 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
60
63
  * After retries exhausted, error propagates here and we return a failed result.
61
64
  */
62
65
  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 });
75
- }
76
- return { ok: false, error: cause };
66
+ for (let i = 0; i < params.retries + 1; i++) {
67
+ if (i > 0 && params.delay) {
68
+ await new Promise((resolve) => setTimeout(resolve, params.delay));
77
69
  }
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()
70
+ try {
71
+ const result = await this.wrapDurableOperation(stepId, runStep);
72
+ return { ok: true, result };
73
+ } catch (e) {
74
+ if (i === params.retries) {
75
+ const cause = e?.cause;
76
+ if (cause?.status === "failed") {
77
+ params.stepSpan?.error({
78
+ error: e,
79
+ attributes: { status: "failed" }
80
+ });
81
+ if (cause.error && !(cause.error instanceof Error)) {
82
+ cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
83
+ }
84
+ return { ok: false, error: cause };
85
+ }
86
+ const errorInstance = error.getErrorFromUnknown(e, {
87
+ serializeStack: false,
88
+ fallbackMessage: "Unknown step execution error"
89
+ });
90
+ params.stepSpan?.error({
91
+ error: errorInstance,
92
+ attributes: { status: "failed" }
93
+ });
94
+ return {
95
+ ok: false,
96
+ error: {
97
+ status: "failed",
98
+ error: errorInstance,
99
+ endedAt: Date.now()
100
+ }
101
+ };
92
102
  }
93
- };
103
+ }
94
104
  }
105
+ return { ok: false, error: { status: "failed", error: new Error("Unknown error"), endedAt: Date.now() } };
95
106
  }
96
107
  /**
97
108
  * Use Inngest's sleep primitive for durability
@@ -107,28 +118,32 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
107
118
  }
108
119
  /**
109
120
  * 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).
121
+ *
122
+ * IMPORTANT: Errors are wrapped with a cause structure before throwing.
123
+ * This is necessary because Inngest's error serialization (serialize-error-cjs)
124
+ * only captures standard Error properties (message, name, stack, code, cause).
125
+ * Custom properties like statusCode, responseHeaders from AI SDK errors would
126
+ * be lost. By putting our serialized error (via getErrorFromUnknown with toJSON())
127
+ * in the cause property, we ensure custom properties survive serialization.
128
+ * The cause property is in serialize-error-cjs's allowlist, and when the cause
129
+ * object is finally JSON.stringify'd, our error's toJSON() is called.
112
130
  */
113
- async wrapDurableOperation(operationId, operationFn, retryConfig) {
131
+ async wrapDurableOperation(operationId, operationFn) {
114
132
  return this.inngestStep.run(operationId, async () => {
115
133
  try {
116
134
  return await operationFn();
117
135
  } 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;
136
+ const errorInstance = error.getErrorFromUnknown(e, {
137
+ serializeStack: false,
138
+ fallbackMessage: "Unknown step execution error"
139
+ });
140
+ throw new Error(errorInstance.message, {
141
+ cause: {
142
+ status: "failed",
143
+ error: errorInstance,
144
+ endedAt: Date.now()
145
+ }
146
+ });
132
147
  }
133
148
  });
134
149
  }
@@ -150,6 +165,96 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
150
165
  async invokeLifecycleCallbacksInternal(result) {
151
166
  return super.invokeLifecycleCallbacks(result);
152
167
  }
168
+ // =============================================================================
169
+ // Durable Span Lifecycle Hooks
170
+ // =============================================================================
171
+ /**
172
+ * Create a step span durably - on first execution, creates and exports span.
173
+ * On replay, returns cached span data without re-creating.
174
+ */
175
+ async createStepSpan(params) {
176
+ const { executionContext, operationId, options, parentSpan } = params;
177
+ const parentSpanId = parentSpan?.id ?? executionContext.tracingIds?.workflowSpanId;
178
+ const exportedSpan = await this.wrapDurableOperation(operationId, async () => {
179
+ const observability = this.mastra?.observability?.getSelectedInstance({});
180
+ if (!observability) return void 0;
181
+ const span = observability.startSpan({
182
+ ...options,
183
+ entityType: options.entityType,
184
+ traceId: executionContext.tracingIds?.traceId,
185
+ parentSpanId
186
+ });
187
+ return span?.exportSpan();
188
+ });
189
+ if (exportedSpan) {
190
+ const observability = this.mastra?.observability?.getSelectedInstance({});
191
+ return observability?.rebuildSpan(exportedSpan);
192
+ }
193
+ return void 0;
194
+ }
195
+ /**
196
+ * End a step span durably.
197
+ */
198
+ async endStepSpan(params) {
199
+ const { span, operationId, endOptions } = params;
200
+ if (!span) return;
201
+ await this.wrapDurableOperation(operationId, async () => {
202
+ span.end(endOptions);
203
+ });
204
+ }
205
+ /**
206
+ * Record error on step span durably.
207
+ */
208
+ async errorStepSpan(params) {
209
+ const { span, operationId, errorOptions } = params;
210
+ if (!span) return;
211
+ await this.wrapDurableOperation(operationId, async () => {
212
+ span.error(errorOptions);
213
+ });
214
+ }
215
+ /**
216
+ * Create a generic child span durably (for control-flow operations).
217
+ * On first execution, creates and exports span. On replay, returns cached span data.
218
+ */
219
+ async createChildSpan(params) {
220
+ const { executionContext, operationId, options, parentSpan } = params;
221
+ const parentSpanId = parentSpan?.id ?? executionContext.tracingIds?.workflowSpanId;
222
+ const exportedSpan = await this.wrapDurableOperation(operationId, async () => {
223
+ const observability = this.mastra?.observability?.getSelectedInstance({});
224
+ if (!observability) return void 0;
225
+ const span = observability.startSpan({
226
+ ...options,
227
+ traceId: executionContext.tracingIds?.traceId,
228
+ parentSpanId
229
+ });
230
+ return span?.exportSpan();
231
+ });
232
+ if (exportedSpan) {
233
+ const observability = this.mastra?.observability?.getSelectedInstance({});
234
+ return observability?.rebuildSpan(exportedSpan);
235
+ }
236
+ return void 0;
237
+ }
238
+ /**
239
+ * End a generic child span durably (for control-flow operations).
240
+ */
241
+ async endChildSpan(params) {
242
+ const { span, operationId, endOptions } = params;
243
+ if (!span) return;
244
+ await this.wrapDurableOperation(operationId, async () => {
245
+ span.end(endOptions);
246
+ });
247
+ }
248
+ /**
249
+ * Record error on a generic child span durably (for control-flow operations).
250
+ */
251
+ async errorChildSpan(params) {
252
+ const { span, operationId, errorOptions } = params;
253
+ if (!span) return;
254
+ await this.wrapDurableOperation(operationId, async () => {
255
+ span.error(errorOptions);
256
+ });
257
+ }
153
258
  /**
154
259
  * Execute nested InngestWorkflow using inngestStep.invoke() for durability.
155
260
  * This MUST be called directly (not inside step.run()) due to Inngest constraints.
@@ -158,7 +263,23 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
158
263
  if (!(params.step instanceof InngestWorkflow)) {
159
264
  return null;
160
265
  }
161
- const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, pubsub, startedAt } = params;
266
+ const {
267
+ step,
268
+ stepResults,
269
+ executionContext,
270
+ resume,
271
+ timeTravel,
272
+ prevOutput,
273
+ inputData,
274
+ pubsub,
275
+ startedAt,
276
+ perStep,
277
+ stepSpan
278
+ } = params;
279
+ const nestedTracingContext = executionContext.tracingIds?.traceId ? {
280
+ traceId: executionContext.tracingIds.traceId,
281
+ parentSpanId: stepSpan?.id
282
+ } : void 0;
162
283
  const isResume = !!resume?.steps?.length;
163
284
  let result;
164
285
  let runId;
@@ -166,7 +287,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
166
287
  try {
167
288
  if (isResume) {
168
289
  runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
169
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
290
+ const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
291
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
170
292
  workflowName: step.id,
171
293
  runId
172
294
  });
@@ -183,14 +305,17 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
183
305
  resumePayload: resume.resumePayload,
184
306
  resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
185
307
  },
186
- outputOptions: { includeState: true }
308
+ outputOptions: { includeState: true },
309
+ perStep,
310
+ tracingOptions: nestedTracingContext
187
311
  }
188
312
  });
189
313
  result = invokeResp.result;
190
314
  runId = invokeResp.runId;
191
315
  executionContext.state = invokeResp.result.state;
192
316
  } else if (isTimeTravel) {
193
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
317
+ const workflowsStoreForTimeTravel = await this.mastra?.getStorage()?.getStore("workflows");
318
+ const snapshot = await workflowsStoreForTimeTravel?.loadWorkflowSnapshot({
194
319
  workflowName: step.id,
195
320
  runId: executionContext.runId
196
321
  }) ?? { context: {} };
@@ -209,7 +334,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
209
334
  timeTravel: timeTravelParams,
210
335
  initialState: executionContext.state ?? {},
211
336
  runId: executionContext.runId,
212
- outputOptions: { includeState: true }
337
+ outputOptions: { includeState: true },
338
+ perStep,
339
+ tracingOptions: nestedTracingContext
213
340
  }
214
341
  });
215
342
  result = invokeResp.result;
@@ -221,7 +348,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
221
348
  data: {
222
349
  inputData,
223
350
  initialState: executionContext.state ?? {},
224
- outputOptions: { includeState: true }
351
+ outputOptions: { includeState: true },
352
+ perStep,
353
+ tracingOptions: nestedTracingContext
225
354
  }
226
355
  });
227
356
  result = invokeResp.result;
@@ -260,7 +389,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
260
389
  }
261
390
  }
262
391
  });
263
- return { executionContext, result: { status: "failed", error: result?.error } };
392
+ return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
264
393
  } else if (result.status === "suspended") {
265
394
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
266
395
  const stepRes = stepResult;
@@ -284,6 +413,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
284
413
  executionContext,
285
414
  result: {
286
415
  status: "suspended",
416
+ suspendedAt: Date.now(),
287
417
  payload: stepResult.payload,
288
418
  suspendPayload: {
289
419
  ...stepResult?.suspendPayload,
@@ -296,6 +426,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
296
426
  executionContext,
297
427
  result: {
298
428
  status: "suspended",
429
+ suspendedAt: Date.now(),
299
430
  payload: {}
300
431
  }
301
432
  };
@@ -317,9 +448,34 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
317
448
  executionContext,
318
449
  result: {
319
450
  status: "tripwire",
320
- tripwire: result?.tripwire
451
+ tripwire: result?.tripwire,
452
+ endedAt: Date.now()
321
453
  }
322
454
  };
455
+ } else if (perStep || result.status === "paused") {
456
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
457
+ type: "watch",
458
+ runId: executionContext.runId,
459
+ data: {
460
+ type: "workflow-step-result",
461
+ payload: {
462
+ id: step.id,
463
+ status: "paused"
464
+ }
465
+ }
466
+ });
467
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
468
+ type: "watch",
469
+ runId: executionContext.runId,
470
+ data: {
471
+ type: "workflow-step-finish",
472
+ payload: {
473
+ id: step.id,
474
+ metadata: {}
475
+ }
476
+ }
477
+ });
478
+ return { executionContext, result: { status: "paused" } };
323
479
  }
324
480
  await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
325
481
  type: "watch",
@@ -344,14 +500,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
344
500
  }
345
501
  }
346
502
  });
347
- return { executionContext, result: { status: "success", output: result?.result } };
503
+ return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
348
504
  }
349
505
  );
350
506
  Object.assign(executionContext, res.executionContext);
351
507
  return {
352
508
  ...res.result,
353
509
  startedAt,
354
- endedAt: Date.now(),
355
510
  payload: inputData,
356
511
  resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
357
512
  resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
@@ -520,6 +675,7 @@ var InngestRun = class extends workflows.Run {
520
675
  async getRunOutput(eventId, maxWaitMs = 3e5) {
521
676
  const startTime = Date.now();
522
677
  const storage = this.#mastra?.getStorage();
678
+ const workflowsStore = await storage?.getStore("workflows");
523
679
  while (Date.now() - startTime < maxWaitMs) {
524
680
  let runs;
525
681
  try {
@@ -536,7 +692,7 @@ var InngestRun = class extends workflows.Run {
536
692
  return runs[0];
537
693
  }
538
694
  if (runs?.[0]?.status === "Failed") {
539
- const snapshot = await storage?.loadWorkflowSnapshot({
695
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
540
696
  workflowName: this.workflowId,
541
697
  runId: this.runId
542
698
  });
@@ -555,7 +711,7 @@ var InngestRun = class extends workflows.Run {
555
711
  };
556
712
  }
557
713
  if (runs?.[0]?.status === "Cancelled") {
558
- const snapshot = await storage?.loadWorkflowSnapshot({
714
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
559
715
  workflowName: this.workflowId,
560
716
  runId: this.runId
561
717
  });
@@ -573,12 +729,13 @@ var InngestRun = class extends workflows.Run {
573
729
  runId: this.runId
574
730
  }
575
731
  });
576
- const snapshot = await storage?.loadWorkflowSnapshot({
732
+ const workflowsStore = await storage?.getStore("workflows");
733
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
577
734
  workflowName: this.workflowId,
578
735
  runId: this.runId
579
736
  });
580
737
  if (snapshot) {
581
- await storage?.persistWorkflowSnapshot({
738
+ await workflowsStore?.persistWorkflowSnapshot({
582
739
  workflowName: this.workflowId,
583
740
  runId: this.runId,
584
741
  resourceId: this.resourceId,
@@ -590,8 +747,8 @@ var InngestRun = class extends workflows.Run {
590
747
  });
591
748
  }
592
749
  }
593
- async start(params) {
594
- return this._start(params);
750
+ async start(args) {
751
+ return this._start(args);
595
752
  }
596
753
  /**
597
754
  * Starts the workflow execution without waiting for completion (fire-and-forget).
@@ -599,8 +756,9 @@ var InngestRun = class extends workflows.Run {
599
756
  * The workflow executes independently in Inngest.
600
757
  * Use this when you don't need to wait for the result or want to avoid polling failures.
601
758
  */
602
- async startAsync(params) {
603
- await this.#mastra.getStorage()?.persistWorkflowSnapshot({
759
+ async startAsync(args) {
760
+ const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
761
+ await workflowsStore?.persistWorkflowSnapshot({
604
762
  workflowName: this.workflowId,
605
763
  runId: this.runId,
606
764
  resourceId: this.resourceId,
@@ -618,8 +776,8 @@ var InngestRun = class extends workflows.Run {
618
776
  timestamp: Date.now()
619
777
  }
620
778
  });
621
- const inputDataToUse = await this._validateInput(params.inputData);
622
- const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
779
+ const inputDataToUse = await this._validateInput(args.inputData);
780
+ const initialStateToUse = await this._validateInitialState(args.initialState ?? {});
623
781
  const eventOutput = await this.inngest.send({
624
782
  name: `workflow.${this.workflowId}`,
625
783
  data: {
@@ -627,9 +785,10 @@ var InngestRun = class extends workflows.Run {
627
785
  initialState: initialStateToUse,
628
786
  runId: this.runId,
629
787
  resourceId: this.resourceId,
630
- outputOptions: params.outputOptions,
631
- tracingOptions: params.tracingOptions,
632
- requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
788
+ outputOptions: args.outputOptions,
789
+ tracingOptions: args.tracingOptions,
790
+ requestContext: args.requestContext ? Object.fromEntries(args.requestContext.entries()) : {},
791
+ perStep: args.perStep
633
792
  }
634
793
  });
635
794
  const eventId = eventOutput.ids[0];
@@ -644,9 +803,11 @@ var InngestRun = class extends workflows.Run {
644
803
  outputOptions,
645
804
  tracingOptions,
646
805
  format,
647
- requestContext
806
+ requestContext,
807
+ perStep
648
808
  }) {
649
- await this.#mastra.getStorage()?.persistWorkflowSnapshot({
809
+ const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
810
+ await workflowsStore?.persistWorkflowSnapshot({
650
811
  workflowName: this.workflowId,
651
812
  runId: this.runId,
652
813
  resourceId: this.resourceId,
@@ -676,7 +837,8 @@ var InngestRun = class extends workflows.Run {
676
837
  outputOptions,
677
838
  tracingOptions,
678
839
  format,
679
- requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
840
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
841
+ perStep
680
842
  }
681
843
  });
682
844
  const eventId = eventOutput.ids[0];
@@ -712,7 +874,8 @@ var InngestRun = class extends workflows.Run {
712
874
  (step) => typeof step === "string" ? step : step?.id
713
875
  );
714
876
  }
715
- const snapshot = await storage?.loadWorkflowSnapshot({
877
+ const workflowsStore = await storage?.getStore("workflows");
878
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
716
879
  workflowName: this.workflowId,
717
880
  runId: this.runId
718
881
  });
@@ -735,7 +898,8 @@ var InngestRun = class extends workflows.Run {
735
898
  resumePayload: resumeDataToUse,
736
899
  resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
737
900
  },
738
- requestContext: mergedRequestContext
901
+ requestContext: mergedRequestContext,
902
+ perStep: params.perStep
739
903
  }
740
904
  });
741
905
  const eventId = eventOutput.ids[0];
@@ -774,12 +938,13 @@ var InngestRun = class extends workflows.Run {
774
938
  throw new Error("No steps provided to timeTravel");
775
939
  }
776
940
  const storage = this.#mastra?.getStorage();
777
- const snapshot = await storage?.loadWorkflowSnapshot({
941
+ const workflowsStore = await storage?.getStore("workflows");
942
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
778
943
  workflowName: this.workflowId,
779
944
  runId: this.runId
780
945
  });
781
946
  if (!snapshot) {
782
- await storage?.persistWorkflowSnapshot({
947
+ await workflowsStore?.persistWorkflowSnapshot({
783
948
  workflowName: this.workflowId,
784
949
  runId: this.runId,
785
950
  resourceId: this.resourceId,
@@ -813,7 +978,8 @@ var InngestRun = class extends workflows.Run {
813
978
  nestedStepsContext: params.nestedStepsContext,
814
979
  snapshot: snapshot ?? { context: {} },
815
980
  graph: this.executionGraph,
816
- initialState: params.initialState
981
+ initialState: params.initialState,
982
+ perStep: params.perStep
817
983
  });
818
984
  const eventOutput = await this.inngest.send({
819
985
  name: `workflow.${this.workflowId}`,
@@ -825,7 +991,8 @@ var InngestRun = class extends workflows.Run {
825
991
  timeTravel: timeTravelData,
826
992
  tracingOptions: params.tracingOptions,
827
993
  outputOptions: params.outputOptions,
828
- requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
994
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
995
+ perStep: params.perStep
829
996
  }
830
997
  });
831
998
  const eventId = eventOutput.ids[0];
@@ -916,7 +1083,8 @@ var InngestRun = class extends workflows.Run {
916
1083
  tracingOptions,
917
1084
  closeOnSuspend = true,
918
1085
  initialState,
919
- outputOptions
1086
+ outputOptions,
1087
+ perStep
920
1088
  } = {}) {
921
1089
  if (this.closeStreamAction && this.streamOutput) {
922
1090
  return this.streamOutput;
@@ -952,7 +1120,8 @@ var InngestRun = class extends workflows.Run {
952
1120
  initialState,
953
1121
  tracingOptions,
954
1122
  outputOptions,
955
- format: "vnext"
1123
+ format: "vnext",
1124
+ perStep
956
1125
  });
957
1126
  let executionResults;
958
1127
  try {
@@ -983,9 +1152,6 @@ var InngestRun = class extends workflows.Run {
983
1152
  });
984
1153
  return this.streamOutput;
985
1154
  }
986
- streamVNext(args = {}) {
987
- return this.stream(args);
988
- }
989
1155
  timeTravelStream({
990
1156
  inputData,
991
1157
  resumeData,
@@ -994,8 +1160,10 @@ var InngestRun = class extends workflows.Run {
994
1160
  context,
995
1161
  nestedStepsContext,
996
1162
  requestContext,
1163
+ // tracingContext,
997
1164
  tracingOptions,
998
- outputOptions
1165
+ outputOptions,
1166
+ perStep
999
1167
  }) {
1000
1168
  this.closeStreamAction = async () => {
1001
1169
  };
@@ -1030,7 +1198,8 @@ var InngestRun = class extends workflows.Run {
1030
1198
  initialState,
1031
1199
  requestContext,
1032
1200
  tracingOptions,
1033
- outputOptions
1201
+ outputOptions,
1202
+ perStep
1034
1203
  });
1035
1204
  self.executionResults = executionResultsPromise;
1036
1205
  let executionResults;
@@ -1074,9 +1243,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1074
1243
  #mastra;
1075
1244
  inngest;
1076
1245
  function;
1246
+ cronFunction;
1077
1247
  flowControlConfig;
1248
+ cronConfig;
1078
1249
  constructor(params, inngest) {
1079
- const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
1250
+ const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
1080
1251
  super(workflowParams);
1081
1252
  this.engineType = "inngest";
1082
1253
  const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
@@ -1085,6 +1256,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1085
1256
  this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
1086
1257
  this.#mastra = params.mastra;
1087
1258
  this.inngest = inngest;
1259
+ if (cron) {
1260
+ this.cronConfig = { cron, inputData, initialState };
1261
+ }
1088
1262
  }
1089
1263
  async listWorkflowRuns(args) {
1090
1264
  const storage = this.#mastra?.getStorage();
@@ -1092,16 +1266,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1092
1266
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
1093
1267
  return { runs: [], total: 0 };
1094
1268
  }
1095
- return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
1096
- }
1097
- async getWorkflowRunById(runId) {
1098
- const storage = this.#mastra?.getStorage();
1099
- if (!storage) {
1100
- this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
1101
- return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
1269
+ const workflowsStore = await storage.getStore("workflows");
1270
+ if (!workflowsStore) {
1271
+ return { runs: [], total: 0 };
1102
1272
  }
1103
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
1104
- return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
1273
+ return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
1105
1274
  }
1106
1275
  __registerMastra(mastra) {
1107
1276
  super.__registerMastra(mastra);
@@ -1124,7 +1293,8 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1124
1293
  }
1125
1294
  async createRun(options) {
1126
1295
  const runIdToUse = options?.runId || crypto$1.randomUUID();
1127
- const run = this.runs.get(runIdToUse) ?? new InngestRun(
1296
+ const existingInMemoryRun = this.runs.get(runIdToUse);
1297
+ const newRun = new InngestRun(
1128
1298
  {
1129
1299
  workflowId: this.id,
1130
1300
  runId: runIdToUse,
@@ -1141,14 +1311,19 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1141
1311
  },
1142
1312
  this.inngest
1143
1313
  );
1314
+ const run = existingInMemoryRun ?? newRun;
1144
1315
  this.runs.set(runIdToUse, run);
1145
1316
  const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
1146
1317
  workflowStatus: run.workflowRunStatus,
1147
1318
  stepResults: {}
1148
1319
  });
1149
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
1150
- if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
1151
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1320
+ const existingStoredRun = await this.getWorkflowRunById(runIdToUse, {
1321
+ withNestedWorkflows: false
1322
+ });
1323
+ const existsInStorage = existingStoredRun && !existingStoredRun.isFromInMemory;
1324
+ if (!existsInStorage && shouldPersistSnapshot) {
1325
+ const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
1326
+ await workflowsStore?.persistWorkflowSnapshot({
1152
1327
  workflowName: this.id,
1153
1328
  runId: runIdToUse,
1154
1329
  resourceId: options?.resourceId,
@@ -1171,6 +1346,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1171
1346
  }
1172
1347
  return run;
1173
1348
  }
1349
+ //createCronFunction is only called if cronConfig.cron is defined.
1350
+ createCronFunction() {
1351
+ if (this.cronFunction) {
1352
+ return this.cronFunction;
1353
+ }
1354
+ this.cronFunction = this.inngest.createFunction(
1355
+ {
1356
+ id: `workflow.${this.id}.cron`,
1357
+ retries: 0,
1358
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
1359
+ ...this.flowControlConfig
1360
+ },
1361
+ { cron: this.cronConfig?.cron ?? "" },
1362
+ async () => {
1363
+ const run = await this.createRun();
1364
+ const result = await run.start({
1365
+ inputData: this.cronConfig?.inputData,
1366
+ initialState: this.cronConfig?.initialState
1367
+ });
1368
+ return { result, runId: run.runId };
1369
+ }
1370
+ );
1371
+ return this.cronFunction;
1372
+ }
1174
1373
  getFunction() {
1175
1374
  if (this.function) {
1176
1375
  return this.function;
@@ -1178,52 +1377,128 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1178
1377
  this.function = this.inngest.createFunction(
1179
1378
  {
1180
1379
  id: `workflow.${this.id}`,
1181
- retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
1380
+ retries: 0,
1182
1381
  cancelOn: [{ event: `cancel.workflow.${this.id}` }],
1183
1382
  // Spread flow control configuration
1184
1383
  ...this.flowControlConfig
1185
1384
  },
1186
1385
  { event: `workflow.${this.id}` },
1187
1386
  async ({ event, step, attempt, publish }) => {
1188
- let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
1387
+ let {
1388
+ inputData,
1389
+ initialState,
1390
+ runId,
1391
+ resourceId,
1392
+ resume,
1393
+ outputOptions,
1394
+ format,
1395
+ timeTravel,
1396
+ perStep,
1397
+ tracingOptions
1398
+ } = event.data;
1189
1399
  if (!runId) {
1190
1400
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
1191
1401
  return crypto$1.randomUUID();
1192
1402
  });
1193
1403
  }
1194
1404
  const pubsub = new InngestPubSub(this.inngest, this.id, publish);
1405
+ const requestContext = new di.RequestContext(Object.entries(event.data.requestContext ?? {}));
1406
+ const mastra = this.#mastra;
1407
+ const tracingPolicy = this.options.tracingPolicy;
1408
+ const workflowSpanData = await step.run(`workflow.${this.id}.span.start`, async () => {
1409
+ const observability$1 = mastra?.observability?.getSelectedInstance({ requestContext });
1410
+ if (!observability$1) return void 0;
1411
+ const span = observability$1.startSpan({
1412
+ type: observability.SpanType.WORKFLOW_RUN,
1413
+ name: `workflow run: '${this.id}'`,
1414
+ entityType: observability.EntityType.WORKFLOW_RUN,
1415
+ entityId: this.id,
1416
+ input: inputData,
1417
+ metadata: {
1418
+ resourceId,
1419
+ runId
1420
+ },
1421
+ tracingPolicy,
1422
+ tracingOptions,
1423
+ requestContext
1424
+ });
1425
+ return span?.exportSpan();
1426
+ });
1195
1427
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
1196
- const result = await engine.execute({
1197
- workflowId: this.id,
1198
- runId,
1199
- resourceId,
1200
- graph: this.executionGraph,
1201
- serializedStepGraph: this.serializedStepGraph,
1202
- input: inputData,
1203
- initialState,
1204
- pubsub,
1205
- retryConfig: this.retryConfig,
1206
- requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
1207
- resume,
1208
- timeTravel,
1209
- format,
1210
- abortController: new AbortController(),
1211
- // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
1212
- outputOptions,
1213
- outputWriter: async (chunk) => {
1214
- try {
1215
- await pubsub.publish(`workflow.events.v2.${runId}`, {
1216
- type: "watch",
1217
- runId,
1218
- data: chunk
1219
- });
1220
- } catch (err) {
1221
- this.logger.debug?.("Failed to publish watch event:", err);
1428
+ let result;
1429
+ try {
1430
+ result = await engine.execute({
1431
+ workflowId: this.id,
1432
+ runId,
1433
+ resourceId,
1434
+ graph: this.executionGraph,
1435
+ serializedStepGraph: this.serializedStepGraph,
1436
+ input: inputData,
1437
+ initialState,
1438
+ pubsub,
1439
+ retryConfig: this.retryConfig,
1440
+ requestContext,
1441
+ resume,
1442
+ timeTravel,
1443
+ perStep,
1444
+ format,
1445
+ abortController: new AbortController(),
1446
+ // For Inngest, we don't pass workflowSpan - step spans use tracingIds instead
1447
+ workflowSpan: void 0,
1448
+ // Pass tracing IDs for durable span operations
1449
+ tracingIds: workflowSpanData ? {
1450
+ traceId: workflowSpanData.traceId,
1451
+ workflowSpanId: workflowSpanData.id
1452
+ } : void 0,
1453
+ outputOptions,
1454
+ outputWriter: async (chunk) => {
1455
+ try {
1456
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1457
+ type: "watch",
1458
+ runId,
1459
+ data: chunk
1460
+ });
1461
+ } catch (err) {
1462
+ this.logger.debug?.("Failed to publish watch event:", err);
1463
+ }
1222
1464
  }
1223
- }
1224
- });
1465
+ });
1466
+ } catch (error) {
1467
+ throw error;
1468
+ }
1225
1469
  await step.run(`workflow.${this.id}.finalize`, async () => {
1226
- await engine.invokeLifecycleCallbacksInternal(result);
1470
+ if (result.status !== "paused") {
1471
+ await engine.invokeLifecycleCallbacksInternal({
1472
+ status: result.status,
1473
+ result: "result" in result ? result.result : void 0,
1474
+ error: "error" in result ? result.error : void 0,
1475
+ steps: result.steps,
1476
+ tripwire: "tripwire" in result ? result.tripwire : void 0,
1477
+ runId,
1478
+ workflowId: this.id,
1479
+ resourceId,
1480
+ input: inputData,
1481
+ requestContext,
1482
+ state: result.state ?? initialState ?? {}
1483
+ });
1484
+ }
1485
+ if (workflowSpanData) {
1486
+ const observability = mastra?.observability?.getSelectedInstance({ requestContext });
1487
+ if (observability) {
1488
+ const workflowSpan = observability.rebuildSpan(workflowSpanData);
1489
+ if (result.status === "failed") {
1490
+ workflowSpan.error({
1491
+ error: result.error instanceof Error ? result.error : new Error(String(result.error)),
1492
+ attributes: { status: "failed" }
1493
+ });
1494
+ } else {
1495
+ workflowSpan.end({
1496
+ output: result.status === "success" ? result.result : void 0,
1497
+ attributes: { status: result.status }
1498
+ });
1499
+ }
1500
+ }
1501
+ }
1227
1502
  if (result.status === "failed") {
1228
1503
  throw new inngest.NonRetriableError(`Workflow failed`, {
1229
1504
  cause: result
@@ -1250,15 +1525,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1250
1525
  });
1251
1526
  }
1252
1527
  getFunctions() {
1253
- return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
1528
+ return [
1529
+ this.getFunction(),
1530
+ ...this.cronConfig?.cron ? [this.createCronFunction()] : [],
1531
+ ...this.getNestedFunctions(this.executionGraph.steps)
1532
+ ];
1254
1533
  }
1255
1534
  };
1256
- function serve({
1257
- mastra,
1258
- inngest,
1259
- functions: userFunctions = [],
1260
- registerOptions
1261
- }) {
1535
+ function prepareServeOptions({ mastra, inngest, functions: userFunctions = [], registerOptions }) {
1262
1536
  const wfs = mastra.listWorkflows();
1263
1537
  const workflowFunctions = Array.from(
1264
1538
  new Set(
@@ -1271,177 +1545,181 @@ function serve({
1271
1545
  })
1272
1546
  )
1273
1547
  );
1274
- return hono.serve({
1548
+ return {
1275
1549
  ...registerOptions,
1276
1550
  client: inngest,
1277
1551
  functions: [...workflowFunctions, ...userFunctions]
1278
- });
1552
+ };
1279
1553
  }
1554
+ function createServe(adapter) {
1555
+ return (options) => {
1556
+ const serveOptions = prepareServeOptions(options);
1557
+ return adapter(serveOptions);
1558
+ };
1559
+ }
1560
+ var serve = createServe(hono.serve);
1280
1561
 
1281
1562
  // src/types.ts
1282
1563
  var _compatibilityCheck = true;
1283
1564
 
1284
1565
  // src/index.ts
1285
- function isAgent(params) {
1286
- return params?.component === "AGENT";
1566
+ function isInngestWorkflow(input) {
1567
+ return input instanceof InngestWorkflow;
1568
+ }
1569
+ function isAgent(input) {
1570
+ return input instanceof agent.Agent;
1571
+ }
1572
+ function isToolStep(input) {
1573
+ return input instanceof tools.Tool;
1287
1574
  }
1288
- function isTool(params) {
1289
- return params instanceof tools.Tool;
1575
+ function isStepParams(input) {
1576
+ return input !== null && typeof input === "object" && "id" in input && "execute" in input && !(input instanceof agent.Agent) && !(input instanceof tools.Tool) && !(input instanceof InngestWorkflow);
1290
1577
  }
1291
- function isInngestWorkflow(params) {
1292
- return params instanceof InngestWorkflow;
1578
+ function isProcessor(obj) {
1579
+ return obj !== null && typeof obj === "object" && "id" in obj && typeof obj.id === "string" && !(obj instanceof agent.Agent) && !(obj instanceof tools.Tool) && !(obj instanceof InngestWorkflow) && (typeof obj.processInput === "function" || typeof obj.processInputStep === "function" || typeof obj.processOutputStream === "function" || typeof obj.processOutputResult === "function" || typeof obj.processOutputStep === "function");
1293
1580
  }
1294
- function createStep(params, agentOptions) {
1581
+ function createStep(params, agentOrToolOptions) {
1295
1582
  if (isInngestWorkflow(params)) {
1296
1583
  return params;
1297
1584
  }
1298
1585
  if (isAgent(params)) {
1299
- const outputSchema = agentOptions?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
1300
- return {
1301
- id: params.name,
1302
- description: params.getDescription(),
1303
- inputSchema: zod.z.object({
1304
- prompt: zod.z.string()
1305
- // resourceId: z.string().optional(),
1306
- // threadId: z.string().optional(),
1307
- }),
1308
- outputSchema,
1309
- execute: async ({
1310
- inputData,
1311
- runId,
1312
- [_constants.PUBSUB_SYMBOL]: pubsub,
1313
- [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1314
- requestContext,
1315
- tracingContext,
1316
- abortSignal,
1317
- abort,
1318
- writer
1319
- }) => {
1320
- let streamPromise = {};
1321
- streamPromise.promise = new Promise((resolve, reject) => {
1322
- streamPromise.resolve = resolve;
1323
- streamPromise.reject = reject;
1586
+ return createStepFromAgent(params, agentOrToolOptions);
1587
+ }
1588
+ if (isToolStep(params)) {
1589
+ return createStepFromTool(params, agentOrToolOptions);
1590
+ }
1591
+ if (isStepParams(params)) {
1592
+ return createStepFromParams(params);
1593
+ }
1594
+ if (isProcessor(params)) {
1595
+ return createStepFromProcessor(params);
1596
+ }
1597
+ throw new Error("Invalid input: expected StepParams, Agent, ToolStep, Processor, or InngestWorkflow");
1598
+ }
1599
+ function createStepFromParams(params) {
1600
+ return {
1601
+ id: params.id,
1602
+ description: params.description,
1603
+ inputSchema: params.inputSchema,
1604
+ stateSchema: params.stateSchema,
1605
+ outputSchema: params.outputSchema,
1606
+ resumeSchema: params.resumeSchema,
1607
+ suspendSchema: params.suspendSchema,
1608
+ scorers: params.scorers,
1609
+ retries: params.retries,
1610
+ execute: params.execute.bind(params)
1611
+ };
1612
+ }
1613
+ function createStepFromAgent(params, agentOrToolOptions) {
1614
+ const options = agentOrToolOptions ?? {};
1615
+ const outputSchema = options?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
1616
+ const { retries, scorers, ...agentOptions } = options ?? {};
1617
+ return {
1618
+ id: params.name,
1619
+ description: params.getDescription(),
1620
+ inputSchema: zod.z.object({
1621
+ prompt: zod.z.string()
1622
+ }),
1623
+ outputSchema,
1624
+ retries,
1625
+ scorers,
1626
+ execute: async ({
1627
+ inputData,
1628
+ runId,
1629
+ [_constants.PUBSUB_SYMBOL]: pubsub,
1630
+ [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1631
+ requestContext,
1632
+ tracingContext,
1633
+ abortSignal,
1634
+ abort,
1635
+ writer
1636
+ }) => {
1637
+ let streamPromise = {};
1638
+ streamPromise.promise = new Promise((resolve, reject) => {
1639
+ streamPromise.resolve = resolve;
1640
+ streamPromise.reject = reject;
1641
+ });
1642
+ let structuredResult = null;
1643
+ const toolData = {
1644
+ name: params.name,
1645
+ args: inputData
1646
+ };
1647
+ let stream;
1648
+ if ((await params.getModel()).specificationVersion === "v1") {
1649
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
1650
+ ...agentOptions ?? {},
1651
+ requestContext,
1652
+ tracingContext,
1653
+ onFinish: (result) => {
1654
+ const resultWithObject = result;
1655
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1656
+ structuredResult = resultWithObject.object;
1657
+ }
1658
+ streamPromise.resolve(result.text);
1659
+ void agentOptions?.onFinish?.(result);
1660
+ },
1661
+ abortSignal
1324
1662
  });
1325
- let structuredResult = null;
1326
- const toolData = {
1327
- name: params.name,
1328
- args: inputData
1329
- };
1330
- let stream;
1331
- if ((await params.getModel()).specificationVersion === "v1") {
1332
- const { fullStream } = await params.streamLegacy(inputData.prompt, {
1333
- ...agentOptions ?? {},
1334
- // resourceId: inputData.resourceId,
1335
- // threadId: inputData.threadId,
1336
- requestContext,
1337
- tracingContext,
1338
- onFinish: (result) => {
1339
- const resultWithObject = result;
1340
- if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1341
- structuredResult = resultWithObject.object;
1342
- }
1343
- streamPromise.resolve(result.text);
1344
- void agentOptions?.onFinish?.(result);
1345
- },
1346
- abortSignal
1347
- });
1348
- stream = fullStream;
1349
- } else {
1350
- const modelOutput = await params.stream(inputData.prompt, {
1351
- ...agentOptions ?? {},
1352
- requestContext,
1353
- tracingContext,
1354
- onFinish: (result) => {
1355
- const resultWithObject = result;
1356
- if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1357
- structuredResult = resultWithObject.object;
1358
- }
1359
- streamPromise.resolve(result.text);
1360
- void agentOptions?.onFinish?.(result);
1361
- },
1362
- abortSignal
1363
- });
1364
- stream = modelOutput.fullStream;
1365
- }
1366
- if (streamFormat === "legacy") {
1367
- await pubsub.publish(`workflow.events.v2.${runId}`, {
1368
- type: "watch",
1369
- runId,
1370
- data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1371
- });
1372
- for await (const chunk of stream) {
1373
- if (chunk.type === "text-delta") {
1374
- await pubsub.publish(`workflow.events.v2.${runId}`, {
1375
- type: "watch",
1376
- runId,
1377
- data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
1378
- });
1663
+ stream = fullStream;
1664
+ } else {
1665
+ const modelOutput = await params.stream(inputData.prompt, {
1666
+ ...agentOptions ?? {},
1667
+ requestContext,
1668
+ tracingContext,
1669
+ onFinish: (result) => {
1670
+ const resultWithObject = result;
1671
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1672
+ structuredResult = resultWithObject.object;
1379
1673
  }
1380
- }
1381
- await pubsub.publish(`workflow.events.v2.${runId}`, {
1382
- type: "watch",
1383
- runId,
1384
- data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1385
- });
1386
- } else {
1387
- for await (const chunk of stream) {
1388
- await writer.write(chunk);
1674
+ streamPromise.resolve(result.text);
1675
+ void agentOptions?.onFinish?.(result);
1676
+ },
1677
+ abortSignal
1678
+ });
1679
+ stream = modelOutput.fullStream;
1680
+ }
1681
+ if (streamFormat === "legacy") {
1682
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1683
+ type: "watch",
1684
+ runId,
1685
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1686
+ });
1687
+ for await (const chunk of stream) {
1688
+ if (chunk.type === "text-delta") {
1689
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1690
+ type: "watch",
1691
+ runId,
1692
+ data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
1693
+ });
1389
1694
  }
1390
1695
  }
1391
- if (abortSignal.aborted) {
1392
- return abort();
1393
- }
1394
- if (structuredResult !== null) {
1395
- return structuredResult;
1696
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1697
+ type: "watch",
1698
+ runId,
1699
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1700
+ });
1701
+ } else {
1702
+ for await (const chunk of stream) {
1703
+ await writer.write(chunk);
1396
1704
  }
1397
- return {
1398
- text: await streamPromise.promise
1399
- };
1400
- },
1401
- component: params.component
1402
- };
1403
- }
1404
- if (isTool(params)) {
1405
- if (!params.inputSchema || !params.outputSchema) {
1406
- throw new Error("Tool must have input and output schemas defined");
1407
- }
1408
- return {
1409
- // TODO: tool probably should have strong id type
1410
- id: params.id,
1411
- description: params.description,
1412
- inputSchema: params.inputSchema,
1413
- outputSchema: params.outputSchema,
1414
- suspendSchema: params.suspendSchema,
1415
- resumeSchema: params.resumeSchema,
1416
- execute: async ({
1417
- inputData,
1418
- mastra,
1419
- requestContext,
1420
- tracingContext,
1421
- suspend,
1422
- resumeData,
1423
- runId,
1424
- workflowId,
1425
- state,
1426
- setState
1427
- }) => {
1428
- const toolContext = {
1429
- mastra,
1430
- requestContext,
1431
- tracingContext,
1432
- workflow: {
1433
- runId,
1434
- resumeData,
1435
- suspend,
1436
- workflowId,
1437
- state,
1438
- setState
1439
- }
1440
- };
1441
- return params.execute(inputData, toolContext);
1442
- },
1443
- component: "TOOL"
1444
- };
1705
+ }
1706
+ if (abortSignal.aborted) {
1707
+ return abort();
1708
+ }
1709
+ if (structuredResult !== null) {
1710
+ return structuredResult;
1711
+ }
1712
+ return {
1713
+ text: await streamPromise.promise
1714
+ };
1715
+ },
1716
+ component: params.component
1717
+ };
1718
+ }
1719
+ function createStepFromTool(params, agentOrToolOptions) {
1720
+ const toolOpts = agentOrToolOptions;
1721
+ if (!params.inputSchema || !params.outputSchema) {
1722
+ throw new Error("Tool must have input and output schemas defined");
1445
1723
  }
1446
1724
  return {
1447
1725
  id: params.id,
@@ -1450,7 +1728,480 @@ function createStep(params, agentOptions) {
1450
1728
  outputSchema: params.outputSchema,
1451
1729
  resumeSchema: params.resumeSchema,
1452
1730
  suspendSchema: params.suspendSchema,
1453
- execute: params.execute
1731
+ retries: toolOpts?.retries,
1732
+ scorers: toolOpts?.scorers,
1733
+ execute: async ({
1734
+ inputData,
1735
+ mastra,
1736
+ requestContext,
1737
+ tracingContext,
1738
+ suspend,
1739
+ resumeData,
1740
+ runId,
1741
+ workflowId,
1742
+ state,
1743
+ setState
1744
+ }) => {
1745
+ const toolContext = {
1746
+ mastra,
1747
+ requestContext,
1748
+ tracingContext,
1749
+ workflow: {
1750
+ runId,
1751
+ resumeData,
1752
+ suspend,
1753
+ workflowId,
1754
+ state,
1755
+ setState
1756
+ }
1757
+ };
1758
+ return params.execute(inputData, toolContext);
1759
+ },
1760
+ component: "TOOL"
1761
+ };
1762
+ }
1763
+ function createStepFromProcessor(processor) {
1764
+ const getProcessorEntityType = (phase) => {
1765
+ switch (phase) {
1766
+ case "input":
1767
+ return observability.EntityType.INPUT_PROCESSOR;
1768
+ case "inputStep":
1769
+ return observability.EntityType.INPUT_STEP_PROCESSOR;
1770
+ case "outputStream":
1771
+ case "outputResult":
1772
+ return observability.EntityType.OUTPUT_PROCESSOR;
1773
+ case "outputStep":
1774
+ return observability.EntityType.OUTPUT_STEP_PROCESSOR;
1775
+ default:
1776
+ return observability.EntityType.OUTPUT_PROCESSOR;
1777
+ }
1778
+ };
1779
+ const getSpanNamePrefix = (phase) => {
1780
+ switch (phase) {
1781
+ case "input":
1782
+ return "input processor";
1783
+ case "inputStep":
1784
+ return "input step processor";
1785
+ case "outputStream":
1786
+ return "output stream processor";
1787
+ case "outputResult":
1788
+ return "output processor";
1789
+ case "outputStep":
1790
+ return "output step processor";
1791
+ default:
1792
+ return "processor";
1793
+ }
1794
+ };
1795
+ const hasPhaseMethod = (phase) => {
1796
+ switch (phase) {
1797
+ case "input":
1798
+ return !!processor.processInput;
1799
+ case "inputStep":
1800
+ return !!processor.processInputStep;
1801
+ case "outputStream":
1802
+ return !!processor.processOutputStream;
1803
+ case "outputResult":
1804
+ return !!processor.processOutputResult;
1805
+ case "outputStep":
1806
+ return !!processor.processOutputStep;
1807
+ default:
1808
+ return false;
1809
+ }
1810
+ };
1811
+ return {
1812
+ id: `processor:${processor.id}`,
1813
+ description: processor.name ?? `Processor ${processor.id}`,
1814
+ inputSchema: processors.ProcessorStepSchema,
1815
+ outputSchema: processors.ProcessorStepOutputSchema,
1816
+ execute: async ({ inputData, requestContext, tracingContext }) => {
1817
+ const input = inputData;
1818
+ const {
1819
+ phase,
1820
+ messages,
1821
+ messageList,
1822
+ stepNumber,
1823
+ systemMessages,
1824
+ part,
1825
+ streamParts,
1826
+ state,
1827
+ finishReason,
1828
+ toolCalls,
1829
+ text,
1830
+ retryCount,
1831
+ // inputStep phase fields for model/tools configuration
1832
+ model,
1833
+ tools,
1834
+ toolChoice,
1835
+ activeTools,
1836
+ providerOptions,
1837
+ modelSettings,
1838
+ structuredOutput,
1839
+ steps
1840
+ } = input;
1841
+ const abort = (reason, options) => {
1842
+ throw new agent.TripWire(reason || `Tripwire triggered by ${processor.id}`, options, processor.id);
1843
+ };
1844
+ if (!hasPhaseMethod(phase)) {
1845
+ return input;
1846
+ }
1847
+ const currentSpan = tracingContext?.currentSpan;
1848
+ const parentSpan = phase === "inputStep" || phase === "outputStep" ? currentSpan?.findParent(observability.SpanType.MODEL_STEP) || currentSpan : currentSpan?.findParent(observability.SpanType.AGENT_RUN) || currentSpan;
1849
+ const processorSpan = phase !== "outputStream" ? parentSpan?.createChildSpan({
1850
+ type: observability.SpanType.PROCESSOR_RUN,
1851
+ name: `${getSpanNamePrefix(phase)}: ${processor.id}`,
1852
+ entityType: getProcessorEntityType(phase),
1853
+ entityId: processor.id,
1854
+ entityName: processor.name ?? processor.id,
1855
+ input: { phase, messageCount: messages?.length },
1856
+ attributes: {
1857
+ processorExecutor: "workflow",
1858
+ // Read processorIndex from processor (set in combineProcessorsIntoWorkflow)
1859
+ processorIndex: processor.processorIndex
1860
+ }
1861
+ }) : void 0;
1862
+ const processorTracingContext = processorSpan ? { currentSpan: processorSpan } : tracingContext;
1863
+ const baseContext = {
1864
+ abort,
1865
+ retryCount: retryCount ?? 0,
1866
+ requestContext,
1867
+ tracingContext: processorTracingContext
1868
+ };
1869
+ const passThrough = {
1870
+ phase,
1871
+ // Auto-create MessageList from messages if not provided
1872
+ // This enables running processor workflows from the UI where messageList can't be serialized
1873
+ messageList: messageList ?? (Array.isArray(messages) ? new agent.MessageList().add(messages, "input").addSystem(systemMessages ?? []) : void 0),
1874
+ stepNumber,
1875
+ systemMessages,
1876
+ streamParts,
1877
+ state,
1878
+ finishReason,
1879
+ toolCalls,
1880
+ text,
1881
+ retryCount,
1882
+ // inputStep phase fields for model/tools configuration
1883
+ model,
1884
+ tools,
1885
+ toolChoice,
1886
+ activeTools,
1887
+ providerOptions,
1888
+ modelSettings,
1889
+ structuredOutput,
1890
+ steps
1891
+ };
1892
+ const executePhaseWithSpan = async (fn) => {
1893
+ try {
1894
+ const result = await fn();
1895
+ processorSpan?.end({ output: result });
1896
+ return result;
1897
+ } catch (error) {
1898
+ if (error instanceof agent.TripWire) {
1899
+ processorSpan?.end({ output: { tripwire: error.message } });
1900
+ } else {
1901
+ processorSpan?.error({ error, endSpan: true });
1902
+ }
1903
+ throw error;
1904
+ }
1905
+ };
1906
+ return executePhaseWithSpan(async () => {
1907
+ switch (phase) {
1908
+ case "input": {
1909
+ if (processor.processInput) {
1910
+ if (!passThrough.messageList) {
1911
+ throw new error.MastraError({
1912
+ category: error.ErrorCategory.USER,
1913
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
1914
+ id: "PROCESSOR_MISSING_MESSAGE_LIST",
1915
+ text: `Processor ${processor.id} requires messageList or messages for processInput phase`
1916
+ });
1917
+ }
1918
+ const idsBeforeProcessing = messages.map((m) => m.id);
1919
+ const check = passThrough.messageList.makeMessageSourceChecker();
1920
+ const result = await processor.processInput({
1921
+ ...baseContext,
1922
+ messages,
1923
+ messageList: passThrough.messageList,
1924
+ systemMessages: systemMessages ?? []
1925
+ });
1926
+ if (result instanceof agent.MessageList) {
1927
+ if (result !== passThrough.messageList) {
1928
+ throw new error.MastraError({
1929
+ category: error.ErrorCategory.USER,
1930
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
1931
+ id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
1932
+ text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
1933
+ });
1934
+ }
1935
+ return {
1936
+ ...passThrough,
1937
+ messages: result.get.all.db(),
1938
+ systemMessages: result.getAllSystemMessages()
1939
+ };
1940
+ } else if (Array.isArray(result)) {
1941
+ processors.ProcessorRunner.applyMessagesToMessageList(
1942
+ result,
1943
+ passThrough.messageList,
1944
+ idsBeforeProcessing,
1945
+ check,
1946
+ "input"
1947
+ );
1948
+ return { ...passThrough, messages: result };
1949
+ } else if (result && "messages" in result && "systemMessages" in result) {
1950
+ const typedResult = result;
1951
+ processors.ProcessorRunner.applyMessagesToMessageList(
1952
+ typedResult.messages,
1953
+ passThrough.messageList,
1954
+ idsBeforeProcessing,
1955
+ check,
1956
+ "input"
1957
+ );
1958
+ passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
1959
+ return {
1960
+ ...passThrough,
1961
+ messages: typedResult.messages,
1962
+ systemMessages: typedResult.systemMessages
1963
+ };
1964
+ }
1965
+ return { ...passThrough, messages };
1966
+ }
1967
+ return { ...passThrough, messages };
1968
+ }
1969
+ case "inputStep": {
1970
+ if (processor.processInputStep) {
1971
+ if (!passThrough.messageList) {
1972
+ throw new error.MastraError({
1973
+ category: error.ErrorCategory.USER,
1974
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
1975
+ id: "PROCESSOR_MISSING_MESSAGE_LIST",
1976
+ text: `Processor ${processor.id} requires messageList or messages for processInputStep phase`
1977
+ });
1978
+ }
1979
+ const idsBeforeProcessing = messages.map((m) => m.id);
1980
+ const check = passThrough.messageList.makeMessageSourceChecker();
1981
+ const result = await processor.processInputStep({
1982
+ ...baseContext,
1983
+ messages,
1984
+ messageList: passThrough.messageList,
1985
+ stepNumber: stepNumber ?? 0,
1986
+ systemMessages: systemMessages ?? [],
1987
+ // Pass model/tools configuration fields - types match ProcessInputStepArgs
1988
+ model,
1989
+ tools,
1990
+ toolChoice,
1991
+ activeTools,
1992
+ providerOptions,
1993
+ modelSettings,
1994
+ structuredOutput,
1995
+ steps: steps ?? []
1996
+ });
1997
+ const validatedResult = await processors.ProcessorRunner.validateAndFormatProcessInputStepResult(result, {
1998
+ messageList: passThrough.messageList,
1999
+ processor,
2000
+ stepNumber: stepNumber ?? 0
2001
+ });
2002
+ if (validatedResult.messages) {
2003
+ processors.ProcessorRunner.applyMessagesToMessageList(
2004
+ validatedResult.messages,
2005
+ passThrough.messageList,
2006
+ idsBeforeProcessing,
2007
+ check
2008
+ );
2009
+ }
2010
+ if (validatedResult.systemMessages) {
2011
+ passThrough.messageList.replaceAllSystemMessages(validatedResult.systemMessages);
2012
+ }
2013
+ return { ...passThrough, messages, ...validatedResult };
2014
+ }
2015
+ return { ...passThrough, messages };
2016
+ }
2017
+ case "outputStream": {
2018
+ if (processor.processOutputStream) {
2019
+ const spanKey = `__outputStreamSpan_${processor.id}`;
2020
+ const mutableState = state ?? {};
2021
+ let processorSpan2 = mutableState[spanKey];
2022
+ if (!processorSpan2 && parentSpan) {
2023
+ processorSpan2 = parentSpan.createChildSpan({
2024
+ type: observability.SpanType.PROCESSOR_RUN,
2025
+ name: `output stream processor: ${processor.id}`,
2026
+ entityType: observability.EntityType.OUTPUT_PROCESSOR,
2027
+ entityId: processor.id,
2028
+ entityName: processor.name ?? processor.id,
2029
+ input: { phase, streamParts: [] },
2030
+ attributes: {
2031
+ processorExecutor: "workflow",
2032
+ processorIndex: processor.processorIndex
2033
+ }
2034
+ });
2035
+ mutableState[spanKey] = processorSpan2;
2036
+ }
2037
+ if (processorSpan2) {
2038
+ processorSpan2.input = {
2039
+ phase,
2040
+ streamParts: streamParts ?? [],
2041
+ totalChunks: (streamParts ?? []).length
2042
+ };
2043
+ }
2044
+ const processorTracingContext2 = processorSpan2 ? { currentSpan: processorSpan2 } : baseContext.tracingContext;
2045
+ let result;
2046
+ try {
2047
+ result = await processor.processOutputStream({
2048
+ ...baseContext,
2049
+ tracingContext: processorTracingContext2,
2050
+ part,
2051
+ streamParts: streamParts ?? [],
2052
+ state: mutableState,
2053
+ messageList: passThrough.messageList
2054
+ // Optional for stream processing
2055
+ });
2056
+ if (part && part.type === "finish") {
2057
+ processorSpan2?.end({ output: result });
2058
+ delete mutableState[spanKey];
2059
+ }
2060
+ } catch (error) {
2061
+ if (error instanceof agent.TripWire) {
2062
+ processorSpan2?.end({ output: { tripwire: error.message } });
2063
+ } else {
2064
+ processorSpan2?.error({ error, endSpan: true });
2065
+ }
2066
+ delete mutableState[spanKey];
2067
+ throw error;
2068
+ }
2069
+ return { ...passThrough, state: mutableState, part: result };
2070
+ }
2071
+ return { ...passThrough, part };
2072
+ }
2073
+ case "outputResult": {
2074
+ if (processor.processOutputResult) {
2075
+ if (!passThrough.messageList) {
2076
+ throw new error.MastraError({
2077
+ category: error.ErrorCategory.USER,
2078
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
2079
+ id: "PROCESSOR_MISSING_MESSAGE_LIST",
2080
+ text: `Processor ${processor.id} requires messageList or messages for processOutputResult phase`
2081
+ });
2082
+ }
2083
+ const idsBeforeProcessing = messages.map((m) => m.id);
2084
+ const check = passThrough.messageList.makeMessageSourceChecker();
2085
+ const result = await processor.processOutputResult({
2086
+ ...baseContext,
2087
+ messages,
2088
+ messageList: passThrough.messageList
2089
+ });
2090
+ if (result instanceof agent.MessageList) {
2091
+ if (result !== passThrough.messageList) {
2092
+ throw new error.MastraError({
2093
+ category: error.ErrorCategory.USER,
2094
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
2095
+ id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
2096
+ text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
2097
+ });
2098
+ }
2099
+ return {
2100
+ ...passThrough,
2101
+ messages: result.get.all.db(),
2102
+ systemMessages: result.getAllSystemMessages()
2103
+ };
2104
+ } else if (Array.isArray(result)) {
2105
+ processors.ProcessorRunner.applyMessagesToMessageList(
2106
+ result,
2107
+ passThrough.messageList,
2108
+ idsBeforeProcessing,
2109
+ check,
2110
+ "response"
2111
+ );
2112
+ return { ...passThrough, messages: result };
2113
+ } else if (result && "messages" in result && "systemMessages" in result) {
2114
+ const typedResult = result;
2115
+ processors.ProcessorRunner.applyMessagesToMessageList(
2116
+ typedResult.messages,
2117
+ passThrough.messageList,
2118
+ idsBeforeProcessing,
2119
+ check,
2120
+ "response"
2121
+ );
2122
+ passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
2123
+ return {
2124
+ ...passThrough,
2125
+ messages: typedResult.messages,
2126
+ systemMessages: typedResult.systemMessages
2127
+ };
2128
+ }
2129
+ return { ...passThrough, messages };
2130
+ }
2131
+ return { ...passThrough, messages };
2132
+ }
2133
+ case "outputStep": {
2134
+ if (processor.processOutputStep) {
2135
+ if (!passThrough.messageList) {
2136
+ throw new error.MastraError({
2137
+ category: error.ErrorCategory.USER,
2138
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
2139
+ id: "PROCESSOR_MISSING_MESSAGE_LIST",
2140
+ text: `Processor ${processor.id} requires messageList or messages for processOutputStep phase`
2141
+ });
2142
+ }
2143
+ const idsBeforeProcessing = messages.map((m) => m.id);
2144
+ const check = passThrough.messageList.makeMessageSourceChecker();
2145
+ const result = await processor.processOutputStep({
2146
+ ...baseContext,
2147
+ messages,
2148
+ messageList: passThrough.messageList,
2149
+ stepNumber: stepNumber ?? 0,
2150
+ finishReason,
2151
+ toolCalls,
2152
+ text,
2153
+ systemMessages: systemMessages ?? [],
2154
+ steps: steps ?? []
2155
+ });
2156
+ if (result instanceof agent.MessageList) {
2157
+ if (result !== passThrough.messageList) {
2158
+ throw new error.MastraError({
2159
+ category: error.ErrorCategory.USER,
2160
+ domain: error.ErrorDomain.MASTRA_WORKFLOW,
2161
+ id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
2162
+ text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
2163
+ });
2164
+ }
2165
+ return {
2166
+ ...passThrough,
2167
+ messages: result.get.all.db(),
2168
+ systemMessages: result.getAllSystemMessages()
2169
+ };
2170
+ } else if (Array.isArray(result)) {
2171
+ processors.ProcessorRunner.applyMessagesToMessageList(
2172
+ result,
2173
+ passThrough.messageList,
2174
+ idsBeforeProcessing,
2175
+ check,
2176
+ "response"
2177
+ );
2178
+ return { ...passThrough, messages: result };
2179
+ } else if (result && "messages" in result && "systemMessages" in result) {
2180
+ const typedResult = result;
2181
+ processors.ProcessorRunner.applyMessagesToMessageList(
2182
+ typedResult.messages,
2183
+ passThrough.messageList,
2184
+ idsBeforeProcessing,
2185
+ check,
2186
+ "response"
2187
+ );
2188
+ passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
2189
+ return {
2190
+ ...passThrough,
2191
+ messages: typedResult.messages,
2192
+ systemMessages: typedResult.systemMessages
2193
+ };
2194
+ }
2195
+ return { ...passThrough, messages };
2196
+ }
2197
+ return { ...passThrough, messages };
2198
+ }
2199
+ default:
2200
+ return { ...passThrough, messages };
2201
+ }
2202
+ });
2203
+ },
2204
+ component: "PROCESSOR"
1454
2205
  };
1455
2206
  }
1456
2207
  function init(inngest) {
@@ -1498,6 +2249,7 @@ exports.InngestPubSub = InngestPubSub;
1498
2249
  exports.InngestRun = InngestRun;
1499
2250
  exports.InngestWorkflow = InngestWorkflow;
1500
2251
  exports._compatibilityCheck = _compatibilityCheck;
2252
+ exports.createServe = createServe;
1501
2253
  exports.createStep = createStep;
1502
2254
  exports.init = init;
1503
2255
  exports.serve = serve;