@mastra/inngest 0.0.0-feat-improve-processors-20251205191721 → 0.0.0-feat-mcp-embedded-docs-tools-clean-20260102135536

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,14 +1,17 @@
1
1
  'use strict';
2
2
 
3
+ var agent = require('@mastra/core/agent');
3
4
  var tools = require('@mastra/core/tools');
4
5
  var workflows = require('@mastra/core/workflows');
5
6
  var _constants = require('@mastra/core/workflows/_constants');
6
7
  var zod = require('zod');
7
- var crypto = require('crypto');
8
- var web = require('stream/web');
8
+ var crypto$1 = require('crypto');
9
9
  var di = require('@mastra/core/di');
10
10
  var inngest = require('inngest');
11
+ var error = require('@mastra/core/error');
11
12
  var realtime = require('@inngest/realtime');
13
+ var events = require('@mastra/core/events');
14
+ var web = require('stream/web');
12
15
  var stream = require('@mastra/core/stream');
13
16
  var hono = require('inngest/hono');
14
17
 
@@ -25,17 +28,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
25
28
  // Hook Overrides
26
29
  // =============================================================================
27
30
  /**
28
- * Format errors with stack traces for better debugging in Inngest
31
+ * Format errors while preserving Error instances and their custom properties.
32
+ * Uses getErrorFromUnknown to ensure all error properties are preserved.
29
33
  */
30
- formatResultError(error, lastOutput) {
31
- if (error instanceof Error) {
32
- return error.stack ?? error.message;
33
- }
34
+ formatResultError(error$1, lastOutput) {
34
35
  const outputError = lastOutput?.error;
35
- if (outputError instanceof Error) {
36
- return outputError.message;
37
- }
38
- return outputError ?? error ?? "Unknown error";
36
+ const errorSource = error$1 || outputError;
37
+ const errorInstance = error.getErrorFromUnknown(errorSource, {
38
+ serializeStack: true,
39
+ // Include stack in JSON for better debugging in Inngest
40
+ fallbackMessage: "Unknown workflow error"
41
+ });
42
+ return errorInstance.toJSON();
39
43
  }
40
44
  /**
41
45
  * Detect InngestWorkflow instances for special nested workflow handling
@@ -57,32 +61,46 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
57
61
  * After retries exhausted, error propagates here and we return a failed result.
58
62
  */
59
63
  async executeStepWithRetry(stepId, runStep, params) {
60
- try {
61
- const result = await this.wrapDurableOperation(stepId, runStep, { delay: params.delay });
62
- return { ok: true, result };
63
- } catch (e) {
64
- const cause = e?.cause;
65
- if (cause?.status === "failed") {
66
- params.stepSpan?.error({
67
- error: e,
68
- attributes: { status: "failed" }
69
- });
70
- return { ok: false, error: cause };
64
+ for (let i = 0; i < params.retries + 1; i++) {
65
+ if (i > 0 && params.delay) {
66
+ await new Promise((resolve) => setTimeout(resolve, params.delay));
71
67
  }
72
- const errorMessage = e instanceof Error ? e.message : String(e);
73
- params.stepSpan?.error({
74
- error: e,
75
- attributes: { status: "failed" }
76
- });
77
- return {
78
- ok: false,
79
- error: {
80
- status: "failed",
81
- error: `Error: ${errorMessage}`,
82
- endedAt: Date.now()
68
+ try {
69
+ const result = await this.wrapDurableOperation(stepId, runStep);
70
+ return { ok: true, result };
71
+ } catch (e) {
72
+ if (i === params.retries) {
73
+ const cause = e?.cause;
74
+ if (cause?.status === "failed") {
75
+ params.stepSpan?.error({
76
+ error: e,
77
+ attributes: { status: "failed" }
78
+ });
79
+ if (cause.error && !(cause.error instanceof Error)) {
80
+ cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
81
+ }
82
+ return { ok: false, error: cause };
83
+ }
84
+ const errorInstance = error.getErrorFromUnknown(e, {
85
+ serializeStack: false,
86
+ fallbackMessage: "Unknown step execution error"
87
+ });
88
+ params.stepSpan?.error({
89
+ error: errorInstance,
90
+ attributes: { status: "failed" }
91
+ });
92
+ return {
93
+ ok: false,
94
+ error: {
95
+ status: "failed",
96
+ error: errorInstance,
97
+ endedAt: Date.now()
98
+ }
99
+ };
83
100
  }
84
- };
101
+ }
85
102
  }
103
+ return { ok: false, error: { status: "failed", error: new Error("Unknown error"), endedAt: Date.now() } };
86
104
  }
87
105
  /**
88
106
  * Use Inngest's sleep primitive for durability
@@ -101,21 +119,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
101
119
  * If retryConfig is provided, throws RetryAfterError INSIDE step.run() to trigger
102
120
  * Inngest's step-level retry mechanism (not function-level retry).
103
121
  */
104
- async wrapDurableOperation(operationId, operationFn, retryConfig) {
122
+ async wrapDurableOperation(operationId, operationFn) {
105
123
  return this.inngestStep.run(operationId, async () => {
106
124
  try {
107
125
  return await operationFn();
108
126
  } catch (e) {
109
- if (retryConfig) {
110
- const errorMessage = e instanceof Error ? e.message : String(e);
111
- throw new inngest.RetryAfterError(errorMessage, retryConfig.delay, {
112
- cause: {
113
- status: "failed",
114
- error: `Error: ${errorMessage}`,
115
- endedAt: Date.now()
116
- }
117
- });
118
- }
119
127
  throw e;
120
128
  }
121
129
  });
@@ -126,6 +134,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
126
134
  getEngineContext() {
127
135
  return { step: this.inngestStep };
128
136
  }
137
+ /**
138
+ * For Inngest, lifecycle callbacks are invoked in the workflow's finalize step
139
+ * (wrapped in step.run for durability), not in execute(). Override to skip.
140
+ */
141
+ async invokeLifecycleCallbacks(_result) {
142
+ }
143
+ /**
144
+ * Actually invoke the lifecycle callbacks. Called from workflow.ts finalize step.
145
+ */
146
+ async invokeLifecycleCallbacksInternal(result) {
147
+ return super.invokeLifecycleCallbacks(result);
148
+ }
129
149
  /**
130
150
  * Execute nested InngestWorkflow using inngestStep.invoke() for durability.
131
151
  * This MUST be called directly (not inside step.run()) due to Inngest constraints.
@@ -134,15 +154,27 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
134
154
  if (!(params.step instanceof InngestWorkflow)) {
135
155
  return null;
136
156
  }
137
- const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, emitter, startedAt } = params;
157
+ const {
158
+ step,
159
+ stepResults,
160
+ executionContext,
161
+ resume,
162
+ timeTravel,
163
+ prevOutput,
164
+ inputData,
165
+ pubsub,
166
+ startedAt,
167
+ perStep
168
+ } = params;
138
169
  const isResume = !!resume?.steps?.length;
139
170
  let result;
140
171
  let runId;
141
172
  const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
142
173
  try {
143
174
  if (isResume) {
144
- runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
145
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
175
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
176
+ const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
177
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
146
178
  workflowName: step.id,
147
179
  runId
148
180
  });
@@ -159,14 +191,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
159
191
  resumePayload: resume.resumePayload,
160
192
  resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
161
193
  },
162
- outputOptions: { includeState: true }
194
+ outputOptions: { includeState: true },
195
+ perStep
163
196
  }
164
197
  });
165
198
  result = invokeResp.result;
166
199
  runId = invokeResp.runId;
167
200
  executionContext.state = invokeResp.result.state;
168
201
  } else if (isTimeTravel) {
169
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
202
+ const workflowsStoreForTimeTravel = await this.mastra?.getStorage()?.getStore("workflows");
203
+ const snapshot = await workflowsStoreForTimeTravel?.loadWorkflowSnapshot({
170
204
  workflowName: step.id,
171
205
  runId: executionContext.runId
172
206
  }) ?? { context: {} };
@@ -185,7 +219,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
185
219
  timeTravel: timeTravelParams,
186
220
  initialState: executionContext.state ?? {},
187
221
  runId: executionContext.runId,
188
- outputOptions: { includeState: true }
222
+ outputOptions: { includeState: true },
223
+ perStep
189
224
  }
190
225
  });
191
226
  result = invokeResp.result;
@@ -197,7 +232,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
197
232
  data: {
198
233
  inputData,
199
234
  initialState: executionContext.state ?? {},
200
- outputOptions: { includeState: true }
235
+ outputOptions: { includeState: true },
236
+ perStep
201
237
  }
202
238
  });
203
239
  result = invokeResp.result;
@@ -208,9 +244,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
208
244
  const errorCause = e?.cause;
209
245
  if (errorCause && typeof errorCause === "object") {
210
246
  result = errorCause;
211
- runId = errorCause.runId || crypto.randomUUID();
247
+ runId = errorCause.runId || crypto$1.randomUUID();
212
248
  } else {
213
- runId = crypto.randomUUID();
249
+ runId = crypto$1.randomUUID();
214
250
  result = {
215
251
  status: "failed",
216
252
  error: e instanceof Error ? e : new Error(String(e)),
@@ -223,16 +259,20 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
223
259
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
224
260
  async () => {
225
261
  if (result.status === "failed") {
226
- await emitter.emit("watch", {
227
- type: "workflow-step-result",
228
- payload: {
229
- id: step.id,
230
- status: "failed",
231
- error: result?.error,
232
- payload: prevOutput
262
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
263
+ type: "watch",
264
+ runId: executionContext.runId,
265
+ data: {
266
+ type: "workflow-step-result",
267
+ payload: {
268
+ id: step.id,
269
+ status: "failed",
270
+ error: result?.error,
271
+ payload: prevOutput
272
+ }
233
273
  }
234
274
  });
235
- return { executionContext, result: { status: "failed", error: result?.error } };
275
+ return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
236
276
  } else if (result.status === "suspended") {
237
277
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
238
278
  const stepRes = stepResult;
@@ -241,17 +281,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
241
281
  for (const [stepName, stepResult] of suspendedSteps) {
242
282
  const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
243
283
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
244
- await emitter.emit("watch", {
245
- type: "workflow-step-suspended",
246
- payload: {
247
- id: step.id,
248
- status: "suspended"
284
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
285
+ type: "watch",
286
+ runId: executionContext.runId,
287
+ data: {
288
+ type: "workflow-step-suspended",
289
+ payload: {
290
+ id: step.id,
291
+ status: "suspended"
292
+ }
249
293
  }
250
294
  });
251
295
  return {
252
296
  executionContext,
253
297
  result: {
254
298
  status: "suspended",
299
+ suspendedAt: Date.now(),
255
300
  payload: stepResult.payload,
256
301
  suspendPayload: {
257
302
  ...stepResult?.suspendPayload,
@@ -264,59 +309,205 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
264
309
  executionContext,
265
310
  result: {
266
311
  status: "suspended",
312
+ suspendedAt: Date.now(),
267
313
  payload: {}
268
314
  }
269
315
  };
270
316
  } else if (result.status === "tripwire") {
271
- await emitter.emit("watch", {
272
- type: "workflow-step-result",
273
- payload: {
274
- id: step.id,
275
- status: "tripwire",
276
- error: result?.reason,
277
- payload: prevOutput
317
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
318
+ type: "watch",
319
+ runId: executionContext.runId,
320
+ data: {
321
+ type: "workflow-step-result",
322
+ payload: {
323
+ id: step.id,
324
+ status: "tripwire",
325
+ error: result?.tripwire?.reason,
326
+ payload: prevOutput
327
+ }
278
328
  }
279
329
  });
280
330
  return {
281
331
  executionContext,
282
332
  result: {
283
333
  status: "tripwire",
284
- reason: result?.reason,
285
- retry: result?.retry,
286
- metadata: result?.metadata,
287
- processorId: result?.processorId
334
+ tripwire: result?.tripwire,
335
+ endedAt: Date.now()
288
336
  }
289
337
  };
338
+ } else if (perStep || result.status === "paused") {
339
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
340
+ type: "watch",
341
+ runId: executionContext.runId,
342
+ data: {
343
+ type: "workflow-step-result",
344
+ payload: {
345
+ id: step.id,
346
+ status: "paused"
347
+ }
348
+ }
349
+ });
350
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
351
+ type: "watch",
352
+ runId: executionContext.runId,
353
+ data: {
354
+ type: "workflow-step-finish",
355
+ payload: {
356
+ id: step.id,
357
+ metadata: {}
358
+ }
359
+ }
360
+ });
361
+ return { executionContext, result: { status: "paused" } };
290
362
  }
291
- await emitter.emit("watch", {
292
- type: "workflow-step-result",
293
- payload: {
294
- id: step.id,
295
- status: "success",
296
- output: result?.result
363
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
364
+ type: "watch",
365
+ runId: executionContext.runId,
366
+ data: {
367
+ type: "workflow-step-result",
368
+ payload: {
369
+ id: step.id,
370
+ status: "success",
371
+ output: result?.result
372
+ }
297
373
  }
298
374
  });
299
- await emitter.emit("watch", {
300
- type: "workflow-step-finish",
301
- payload: {
302
- id: step.id,
303
- metadata: {}
375
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
376
+ type: "watch",
377
+ runId: executionContext.runId,
378
+ data: {
379
+ type: "workflow-step-finish",
380
+ payload: {
381
+ id: step.id,
382
+ metadata: {}
383
+ }
304
384
  }
305
385
  });
306
- return { executionContext, result: { status: "success", output: result?.result } };
386
+ return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
307
387
  }
308
388
  );
309
389
  Object.assign(executionContext, res.executionContext);
310
390
  return {
311
391
  ...res.result,
312
392
  startedAt,
313
- endedAt: Date.now(),
314
393
  payload: inputData,
315
394
  resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
316
395
  resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
317
396
  };
318
397
  }
319
398
  };
399
+ var InngestPubSub = class extends events.PubSub {
400
+ inngest;
401
+ workflowId;
402
+ publishFn;
403
+ subscriptions = /* @__PURE__ */ new Map();
404
+ constructor(inngest, workflowId, publishFn) {
405
+ super();
406
+ this.inngest = inngest;
407
+ this.workflowId = workflowId;
408
+ this.publishFn = publishFn;
409
+ }
410
+ /**
411
+ * Publish an event to Inngest's realtime system.
412
+ *
413
+ * Topic format: "workflow.events.v2.{runId}"
414
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
415
+ */
416
+ async publish(topic, event) {
417
+ if (!this.publishFn) {
418
+ return;
419
+ }
420
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
421
+ if (!match) {
422
+ return;
423
+ }
424
+ const runId = match[1];
425
+ try {
426
+ await this.publishFn({
427
+ channel: `workflow:${this.workflowId}:${runId}`,
428
+ topic: "watch",
429
+ data: event.data
430
+ });
431
+ } catch (err) {
432
+ console.error("InngestPubSub publish error:", err?.message ?? err);
433
+ }
434
+ }
435
+ /**
436
+ * Subscribe to events from Inngest's realtime system.
437
+ *
438
+ * Topic format: "workflow.events.v2.{runId}"
439
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
440
+ */
441
+ async subscribe(topic, cb) {
442
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
443
+ if (!match || !match[1]) {
444
+ return;
445
+ }
446
+ const runId = match[1];
447
+ if (this.subscriptions.has(topic)) {
448
+ this.subscriptions.get(topic).callbacks.add(cb);
449
+ return;
450
+ }
451
+ const callbacks = /* @__PURE__ */ new Set([cb]);
452
+ const channel = `workflow:${this.workflowId}:${runId}`;
453
+ const streamPromise = realtime.subscribe(
454
+ {
455
+ channel,
456
+ topics: ["watch"],
457
+ app: this.inngest
458
+ },
459
+ (message) => {
460
+ const event = {
461
+ id: crypto.randomUUID(),
462
+ type: "watch",
463
+ runId,
464
+ data: message.data,
465
+ createdAt: /* @__PURE__ */ new Date()
466
+ };
467
+ for (const callback of callbacks) {
468
+ callback(event);
469
+ }
470
+ }
471
+ );
472
+ this.subscriptions.set(topic, {
473
+ unsubscribe: () => {
474
+ streamPromise.then((stream) => stream.cancel()).catch((err) => {
475
+ console.error("InngestPubSub unsubscribe error:", err);
476
+ });
477
+ },
478
+ callbacks
479
+ });
480
+ }
481
+ /**
482
+ * Unsubscribe a callback from a topic.
483
+ * If no callbacks remain, the underlying Inngest subscription is cancelled.
484
+ */
485
+ async unsubscribe(topic, cb) {
486
+ const sub = this.subscriptions.get(topic);
487
+ if (!sub) {
488
+ return;
489
+ }
490
+ sub.callbacks.delete(cb);
491
+ if (sub.callbacks.size === 0) {
492
+ sub.unsubscribe();
493
+ this.subscriptions.delete(topic);
494
+ }
495
+ }
496
+ /**
497
+ * Flush any pending operations. No-op for Inngest.
498
+ */
499
+ async flush() {
500
+ }
501
+ /**
502
+ * Clean up all subscriptions during graceful shutdown.
503
+ */
504
+ async close() {
505
+ for (const [, sub] of this.subscriptions) {
506
+ sub.unsubscribe();
507
+ }
508
+ this.subscriptions.clear();
509
+ }
510
+ };
320
511
  var InngestRun = class extends workflows.Run {
321
512
  inngest;
322
513
  serializedStepGraph;
@@ -328,38 +519,90 @@ var InngestRun = class extends workflows.Run {
328
519
  this.#mastra = params.mastra;
329
520
  }
330
521
  async getRuns(eventId) {
331
- const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
332
- headers: {
333
- Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
522
+ const maxRetries = 3;
523
+ let lastError = null;
524
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
525
+ try {
526
+ const response = await fetch(
527
+ `${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
528
+ {
529
+ headers: {
530
+ Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
531
+ }
532
+ }
533
+ );
534
+ if (response.status === 429) {
535
+ const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
536
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
537
+ continue;
538
+ }
539
+ if (!response.ok) {
540
+ throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
541
+ }
542
+ const text = await response.text();
543
+ if (!text) {
544
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
545
+ continue;
546
+ }
547
+ const json = JSON.parse(text);
548
+ return json.data;
549
+ } catch (error) {
550
+ lastError = error;
551
+ if (attempt < maxRetries - 1) {
552
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
553
+ }
334
554
  }
335
- });
336
- const json = await response.json();
337
- return json.data;
555
+ }
556
+ throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
338
557
  }
339
- async getRunOutput(eventId) {
340
- let runs = await this.getRuns(eventId);
558
+ async getRunOutput(eventId, maxWaitMs = 3e5) {
559
+ const startTime = Date.now();
341
560
  const storage = this.#mastra?.getStorage();
342
- while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
343
- await new Promise((resolve) => setTimeout(resolve, 1e3));
344
- runs = await this.getRuns(eventId);
561
+ const workflowsStore = await storage?.getStore("workflows");
562
+ while (Date.now() - startTime < maxWaitMs) {
563
+ let runs;
564
+ try {
565
+ runs = await this.getRuns(eventId);
566
+ } catch (error) {
567
+ if (error instanceof inngest.NonRetriableError) {
568
+ throw error;
569
+ }
570
+ throw new inngest.NonRetriableError(
571
+ `Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
572
+ );
573
+ }
574
+ if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
575
+ return runs[0];
576
+ }
345
577
  if (runs?.[0]?.status === "Failed") {
346
- const snapshot = await storage?.loadWorkflowSnapshot({
578
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
347
579
  workflowName: this.workflowId,
348
580
  runId: this.runId
349
581
  });
582
+ if (snapshot?.context) {
583
+ snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
584
+ }
350
585
  return {
351
- output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
586
+ output: {
587
+ result: {
588
+ steps: snapshot?.context,
589
+ status: "failed",
590
+ // Get the original error from NonRetriableError's cause (which contains the workflow result)
591
+ error: error.getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
592
+ }
593
+ }
352
594
  };
353
595
  }
354
596
  if (runs?.[0]?.status === "Cancelled") {
355
- const snapshot = await storage?.loadWorkflowSnapshot({
597
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
356
598
  workflowName: this.workflowId,
357
599
  runId: this.runId
358
600
  });
359
601
  return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
360
602
  }
603
+ await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
361
604
  }
362
- return runs?.[0];
605
+ throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
363
606
  }
364
607
  async cancel() {
365
608
  const storage = this.#mastra?.getStorage();
@@ -369,12 +612,13 @@ var InngestRun = class extends workflows.Run {
369
612
  runId: this.runId
370
613
  }
371
614
  });
372
- const snapshot = await storage?.loadWorkflowSnapshot({
615
+ const workflowsStore = await storage?.getStore("workflows");
616
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
373
617
  workflowName: this.workflowId,
374
618
  runId: this.runId
375
619
  });
376
620
  if (snapshot) {
377
- await storage?.persistWorkflowSnapshot({
621
+ await workflowsStore?.persistWorkflowSnapshot({
378
622
  workflowName: this.workflowId,
379
623
  runId: this.runId,
380
624
  resourceId: this.resourceId,
@@ -389,15 +633,64 @@ var InngestRun = class extends workflows.Run {
389
633
  async start(params) {
390
634
  return this._start(params);
391
635
  }
636
+ /**
637
+ * Starts the workflow execution without waiting for completion (fire-and-forget).
638
+ * Returns immediately with the runId after sending the event to Inngest.
639
+ * The workflow executes independently in Inngest.
640
+ * Use this when you don't need to wait for the result or want to avoid polling failures.
641
+ */
642
+ async startAsync(params) {
643
+ const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
644
+ await workflowsStore?.persistWorkflowSnapshot({
645
+ workflowName: this.workflowId,
646
+ runId: this.runId,
647
+ resourceId: this.resourceId,
648
+ snapshot: {
649
+ runId: this.runId,
650
+ serializedStepGraph: this.serializedStepGraph,
651
+ status: "running",
652
+ value: {},
653
+ context: {},
654
+ activePaths: [],
655
+ suspendedPaths: {},
656
+ activeStepsPath: {},
657
+ resumeLabels: {},
658
+ waitingPaths: {},
659
+ timestamp: Date.now()
660
+ }
661
+ });
662
+ const inputDataToUse = await this._validateInput(params.inputData);
663
+ const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
664
+ const eventOutput = await this.inngest.send({
665
+ name: `workflow.${this.workflowId}`,
666
+ data: {
667
+ inputData: inputDataToUse,
668
+ initialState: initialStateToUse,
669
+ runId: this.runId,
670
+ resourceId: this.resourceId,
671
+ outputOptions: params.outputOptions,
672
+ tracingOptions: params.tracingOptions,
673
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
674
+ perStep: params.perStep
675
+ }
676
+ });
677
+ const eventId = eventOutput.ids[0];
678
+ if (!eventId) {
679
+ throw new Error("Event ID is not set");
680
+ }
681
+ return { runId: this.runId };
682
+ }
392
683
  async _start({
393
684
  inputData,
394
685
  initialState,
395
686
  outputOptions,
396
687
  tracingOptions,
397
688
  format,
398
- requestContext
689
+ requestContext,
690
+ perStep
399
691
  }) {
400
- await this.#mastra.getStorage()?.persistWorkflowSnapshot({
692
+ const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
693
+ await workflowsStore?.persistWorkflowSnapshot({
401
694
  workflowName: this.workflowId,
402
695
  runId: this.runId,
403
696
  resourceId: this.resourceId,
@@ -427,7 +720,8 @@ var InngestRun = class extends workflows.Run {
427
720
  outputOptions,
428
721
  tracingOptions,
429
722
  format,
430
- requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
723
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
724
+ perStep
431
725
  }
432
726
  });
433
727
  const eventId = eventOutput.ids[0];
@@ -436,9 +730,7 @@ var InngestRun = class extends workflows.Run {
436
730
  }
437
731
  const runOutput = await this.getRunOutput(eventId);
438
732
  const result = runOutput?.output?.result;
439
- if (result.status === "failed") {
440
- result.error = new Error(result.error);
441
- }
733
+ this.hydrateFailedResult(result);
442
734
  if (result.status !== "suspended") {
443
735
  this.cleanup?.();
444
736
  }
@@ -465,7 +757,8 @@ var InngestRun = class extends workflows.Run {
465
757
  (step) => typeof step === "string" ? step : step?.id
466
758
  );
467
759
  }
468
- const snapshot = await storage?.loadWorkflowSnapshot({
760
+ const workflowsStore = await storage?.getStore("workflows");
761
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
469
762
  workflowName: this.workflowId,
470
763
  runId: this.runId
471
764
  });
@@ -488,7 +781,8 @@ var InngestRun = class extends workflows.Run {
488
781
  resumePayload: resumeDataToUse,
489
782
  resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
490
783
  },
491
- requestContext: mergedRequestContext
784
+ requestContext: mergedRequestContext,
785
+ perStep: params.perStep
492
786
  }
493
787
  });
494
788
  const eventId = eventOutput.ids[0];
@@ -497,9 +791,7 @@ var InngestRun = class extends workflows.Run {
497
791
  }
498
792
  const runOutput = await this.getRunOutput(eventId);
499
793
  const result = runOutput?.output?.result;
500
- if (result.status === "failed") {
501
- result.error = new Error(result.error);
502
- }
794
+ this.hydrateFailedResult(result);
503
795
  return result;
504
796
  }
505
797
  async timeTravel(params) {
@@ -529,12 +821,13 @@ var InngestRun = class extends workflows.Run {
529
821
  throw new Error("No steps provided to timeTravel");
530
822
  }
531
823
  const storage = this.#mastra?.getStorage();
532
- const snapshot = await storage?.loadWorkflowSnapshot({
824
+ const workflowsStore = await storage?.getStore("workflows");
825
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
533
826
  workflowName: this.workflowId,
534
827
  runId: this.runId
535
828
  });
536
829
  if (!snapshot) {
537
- await storage?.persistWorkflowSnapshot({
830
+ await workflowsStore?.persistWorkflowSnapshot({
538
831
  workflowName: this.workflowId,
539
832
  runId: this.runId,
540
833
  resourceId: this.resourceId,
@@ -568,7 +861,8 @@ var InngestRun = class extends workflows.Run {
568
861
  nestedStepsContext: params.nestedStepsContext,
569
862
  snapshot: snapshot ?? { context: {} },
570
863
  graph: this.executionGraph,
571
- initialState: params.initialState
864
+ initialState: params.initialState,
865
+ perStep: params.perStep
572
866
  });
573
867
  const eventOutput = await this.inngest.send({
574
868
  name: `workflow.${this.workflowId}`,
@@ -580,7 +874,8 @@ var InngestRun = class extends workflows.Run {
580
874
  timeTravel: timeTravelData,
581
875
  tracingOptions: params.tracingOptions,
582
876
  outputOptions: params.outputOptions,
583
- requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
877
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
878
+ perStep: params.perStep
584
879
  }
585
880
  });
586
881
  const eventId = eventOutput.ids[0];
@@ -589,9 +884,7 @@ var InngestRun = class extends workflows.Run {
589
884
  }
590
885
  const runOutput = await this.getRunOutput(eventId);
591
886
  const result = runOutput?.output?.result;
592
- if (result.status === "failed") {
593
- result.error = new Error(result.error);
594
- }
887
+ this.hydrateFailedResult(result);
595
888
  return result;
596
889
  }
597
890
  watch(cb) {
@@ -673,7 +966,8 @@ var InngestRun = class extends workflows.Run {
673
966
  tracingOptions,
674
967
  closeOnSuspend = true,
675
968
  initialState,
676
- outputOptions
969
+ outputOptions,
970
+ perStep
677
971
  } = {}) {
678
972
  if (this.closeStreamAction && this.streamOutput) {
679
973
  return this.streamOutput;
@@ -709,7 +1003,8 @@ var InngestRun = class extends workflows.Run {
709
1003
  initialState,
710
1004
  tracingOptions,
711
1005
  outputOptions,
712
- format: "vnext"
1006
+ format: "vnext",
1007
+ perStep
713
1008
  });
714
1009
  let executionResults;
715
1010
  try {
@@ -740,9 +1035,6 @@ var InngestRun = class extends workflows.Run {
740
1035
  });
741
1036
  return this.streamOutput;
742
1037
  }
743
- streamVNext(args = {}) {
744
- return this.stream(args);
745
- }
746
1038
  timeTravelStream({
747
1039
  inputData,
748
1040
  resumeData,
@@ -752,7 +1044,8 @@ var InngestRun = class extends workflows.Run {
752
1044
  nestedStepsContext,
753
1045
  requestContext,
754
1046
  tracingOptions,
755
- outputOptions
1047
+ outputOptions,
1048
+ perStep
756
1049
  }) {
757
1050
  this.closeStreamAction = async () => {
758
1051
  };
@@ -787,7 +1080,8 @@ var InngestRun = class extends workflows.Run {
787
1080
  initialState,
788
1081
  requestContext,
789
1082
  tracingOptions,
790
- outputOptions
1083
+ outputOptions,
1084
+ perStep
791
1085
  });
792
1086
  self.executionResults = executionResultsPromise;
793
1087
  let executionResults;
@@ -812,6 +1106,18 @@ var InngestRun = class extends workflows.Run {
812
1106
  });
813
1107
  return this.streamOutput;
814
1108
  }
1109
+ /**
1110
+ * Hydrates errors in a failed workflow result back to proper Error instances.
1111
+ * This ensures error.cause chains and custom properties are preserved.
1112
+ */
1113
+ hydrateFailedResult(result) {
1114
+ if (result.status === "failed") {
1115
+ result.error = error.getErrorFromUnknown(result.error, { serializeStack: false });
1116
+ if (result.steps) {
1117
+ workflows.hydrateSerializedStepErrors(result.steps);
1118
+ }
1119
+ }
1120
+ }
815
1121
  };
816
1122
 
817
1123
  // src/workflow.ts
@@ -819,9 +1125,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
819
1125
  #mastra;
820
1126
  inngest;
821
1127
  function;
1128
+ cronFunction;
822
1129
  flowControlConfig;
1130
+ cronConfig;
823
1131
  constructor(params, inngest) {
824
- const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
1132
+ const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
825
1133
  super(workflowParams);
826
1134
  this.engineType = "inngest";
827
1135
  const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
@@ -830,6 +1138,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
830
1138
  this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
831
1139
  this.#mastra = params.mastra;
832
1140
  this.inngest = inngest;
1141
+ if (cron) {
1142
+ this.cronConfig = { cron, inputData, initialState };
1143
+ }
833
1144
  }
834
1145
  async listWorkflowRuns(args) {
835
1146
  const storage = this.#mastra?.getStorage();
@@ -837,7 +1148,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
837
1148
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
838
1149
  return { runs: [], total: 0 };
839
1150
  }
840
- return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
1151
+ const workflowsStore = await storage.getStore("workflows");
1152
+ if (!workflowsStore) {
1153
+ return { runs: [], total: 0 };
1154
+ }
1155
+ return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
841
1156
  }
842
1157
  async getWorkflowRunById(runId) {
843
1158
  const storage = this.#mastra?.getStorage();
@@ -845,10 +1160,15 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
845
1160
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
846
1161
  return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
847
1162
  }
848
- const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
1163
+ const workflowsStore = await storage.getStore("workflows");
1164
+ if (!workflowsStore) {
1165
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
1166
+ }
1167
+ const run = await workflowsStore.getWorkflowRunById({ runId, workflowName: this.id });
849
1168
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
850
1169
  }
851
1170
  __registerMastra(mastra) {
1171
+ super.__registerMastra(mastra);
852
1172
  this.#mastra = mastra;
853
1173
  this.executionEngine.__registerMastra(mastra);
854
1174
  const updateNested = (step) => {
@@ -867,7 +1187,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
867
1187
  }
868
1188
  }
869
1189
  async createRun(options) {
870
- const runIdToUse = options?.runId || crypto.randomUUID();
1190
+ const runIdToUse = options?.runId || crypto$1.randomUUID();
871
1191
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
872
1192
  {
873
1193
  workflowId: this.id,
@@ -890,9 +1210,12 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
890
1210
  workflowStatus: run.workflowRunStatus,
891
1211
  stepResults: {}
892
1212
  });
893
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
1213
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
1214
+ withNestedWorkflows: false
1215
+ });
894
1216
  if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
895
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1217
+ const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
1218
+ await workflowsStore?.persistWorkflowSnapshot({
896
1219
  workflowName: this.id,
897
1220
  runId: runIdToUse,
898
1221
  resourceId: options?.resourceId,
@@ -915,6 +1238,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
915
1238
  }
916
1239
  return run;
917
1240
  }
1241
+ //createCronFunction is only called if cronConfig.cron is defined.
1242
+ createCronFunction() {
1243
+ if (this.cronFunction) {
1244
+ return this.cronFunction;
1245
+ }
1246
+ this.cronFunction = this.inngest.createFunction(
1247
+ {
1248
+ id: `workflow.${this.id}.cron`,
1249
+ retries: 0,
1250
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
1251
+ ...this.flowControlConfig
1252
+ },
1253
+ { cron: this.cronConfig?.cron ?? "" },
1254
+ async () => {
1255
+ const run = await this.createRun();
1256
+ const result = await run.start({
1257
+ inputData: this.cronConfig?.inputData,
1258
+ initialState: this.cronConfig?.initialState
1259
+ });
1260
+ return { result, runId: run.runId };
1261
+ }
1262
+ );
1263
+ return this.cronFunction;
1264
+ }
918
1265
  getFunction() {
919
1266
  if (this.function) {
920
1267
  return this.function;
@@ -922,41 +1269,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
922
1269
  this.function = this.inngest.createFunction(
923
1270
  {
924
1271
  id: `workflow.${this.id}`,
925
- retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
1272
+ retries: 0,
926
1273
  cancelOn: [{ event: `cancel.workflow.${this.id}` }],
927
1274
  // Spread flow control configuration
928
1275
  ...this.flowControlConfig
929
1276
  },
930
1277
  { event: `workflow.${this.id}` },
931
1278
  async ({ event, step, attempt, publish }) => {
932
- let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
1279
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
933
1280
  if (!runId) {
934
1281
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
935
- return crypto.randomUUID();
1282
+ return crypto$1.randomUUID();
936
1283
  });
937
1284
  }
938
- const emitter = {
939
- emit: async (event2, data) => {
940
- if (!publish) {
941
- return;
942
- }
943
- try {
944
- await publish({
945
- channel: `workflow:${this.id}:${runId}`,
946
- topic: event2,
947
- data
948
- });
949
- } catch (err) {
950
- this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
951
- }
952
- },
953
- on: (_event, _callback) => {
954
- },
955
- off: (_event, _callback) => {
956
- },
957
- once: (_event, _callback) => {
958
- }
959
- };
1285
+ const pubsub = new InngestPubSub(this.inngest, this.id, publish);
960
1286
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
961
1287
  const result = await engine.execute({
962
1288
  workflowId: this.id,
@@ -966,23 +1292,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
966
1292
  serializedStepGraph: this.serializedStepGraph,
967
1293
  input: inputData,
968
1294
  initialState,
969
- emitter,
1295
+ pubsub,
970
1296
  retryConfig: this.retryConfig,
971
1297
  requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
972
1298
  resume,
973
1299
  timeTravel,
1300
+ perStep,
974
1301
  format,
975
1302
  abortController: new AbortController(),
976
1303
  // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
977
1304
  outputOptions,
978
- writableStream: new web.WritableStream({
979
- write(chunk) {
980
- void emitter.emit("watch", chunk).catch(() => {
1305
+ outputWriter: async (chunk) => {
1306
+ try {
1307
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1308
+ type: "watch",
1309
+ runId,
1310
+ data: chunk
981
1311
  });
1312
+ } catch (err) {
1313
+ this.logger.debug?.("Failed to publish watch event:", err);
982
1314
  }
983
- })
1315
+ }
984
1316
  });
985
1317
  await step.run(`workflow.${this.id}.finalize`, async () => {
1318
+ if (result.status !== "paused") {
1319
+ await engine.invokeLifecycleCallbacksInternal(result);
1320
+ }
986
1321
  if (result.status === "failed") {
987
1322
  throw new inngest.NonRetriableError(`Workflow failed`, {
988
1323
  cause: result
@@ -1009,7 +1344,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
1009
1344
  });
1010
1345
  }
1011
1346
  getFunctions() {
1012
- return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
1347
+ return [
1348
+ this.getFunction(),
1349
+ ...this.cronConfig?.cron ? [this.createCronFunction()] : [],
1350
+ ...this.getNestedFunctions(this.executionGraph.steps)
1351
+ ];
1013
1352
  }
1014
1353
  };
1015
1354
  function serve({
@@ -1041,20 +1380,14 @@ function serve({
1041
1380
  var _compatibilityCheck = true;
1042
1381
 
1043
1382
  // src/index.ts
1044
- function isAgent(params) {
1045
- return params?.component === "AGENT";
1046
- }
1047
- function isTool(params) {
1048
- return params instanceof tools.Tool;
1049
- }
1050
- function isInngestWorkflow(params) {
1051
- return params instanceof InngestWorkflow;
1052
- }
1053
- function createStep(params, agentOptions) {
1054
- if (isInngestWorkflow(params)) {
1383
+ function createStep(params, agentOrToolOptions) {
1384
+ if (params instanceof InngestWorkflow) {
1055
1385
  return params;
1056
1386
  }
1057
- if (isAgent(params)) {
1387
+ if (params instanceof agent.Agent) {
1388
+ const options = agentOrToolOptions;
1389
+ const outputSchema = options?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
1390
+ const { retries, scorers, ...agentOptions } = options ?? {};
1058
1391
  return {
1059
1392
  id: params.name,
1060
1393
  description: params.getDescription(),
@@ -1063,12 +1396,13 @@ function createStep(params, agentOptions) {
1063
1396
  // resourceId: z.string().optional(),
1064
1397
  // threadId: z.string().optional(),
1065
1398
  }),
1066
- outputSchema: zod.z.object({
1067
- text: zod.z.string()
1068
- }),
1399
+ outputSchema,
1400
+ retries,
1401
+ scorers,
1069
1402
  execute: async ({
1070
1403
  inputData,
1071
- [_constants.EMITTER_SYMBOL]: emitter,
1404
+ runId,
1405
+ [_constants.PUBSUB_SYMBOL]: pubsub,
1072
1406
  [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1073
1407
  requestContext,
1074
1408
  tracingContext,
@@ -1081,6 +1415,7 @@ function createStep(params, agentOptions) {
1081
1415
  streamPromise.resolve = resolve;
1082
1416
  streamPromise.reject = reject;
1083
1417
  });
1418
+ let structuredResult = null;
1084
1419
  const toolData = {
1085
1420
  name: params.name,
1086
1421
  args: inputData
@@ -1094,6 +1429,10 @@ function createStep(params, agentOptions) {
1094
1429
  requestContext,
1095
1430
  tracingContext,
1096
1431
  onFinish: (result) => {
1432
+ const resultWithObject = result;
1433
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1434
+ structuredResult = resultWithObject.object;
1435
+ }
1097
1436
  streamPromise.resolve(result.text);
1098
1437
  void agentOptions?.onFinish?.(result);
1099
1438
  },
@@ -1106,6 +1445,10 @@ function createStep(params, agentOptions) {
1106
1445
  requestContext,
1107
1446
  tracingContext,
1108
1447
  onFinish: (result) => {
1448
+ const resultWithObject = result;
1449
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1450
+ structuredResult = resultWithObject.object;
1451
+ }
1109
1452
  streamPromise.resolve(result.text);
1110
1453
  void agentOptions?.onFinish?.(result);
1111
1454
  },
@@ -1114,22 +1457,24 @@ function createStep(params, agentOptions) {
1114
1457
  stream = modelOutput.fullStream;
1115
1458
  }
1116
1459
  if (streamFormat === "legacy") {
1117
- await emitter.emit("watch", {
1118
- type: "tool-call-streaming-start",
1119
- ...toolData ?? {}
1460
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1461
+ type: "watch",
1462
+ runId,
1463
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1120
1464
  });
1121
1465
  for await (const chunk of stream) {
1122
1466
  if (chunk.type === "text-delta") {
1123
- await emitter.emit("watch", {
1124
- type: "tool-call-delta",
1125
- ...toolData ?? {},
1126
- argsTextDelta: chunk.textDelta
1467
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1468
+ type: "watch",
1469
+ runId,
1470
+ data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
1127
1471
  });
1128
1472
  }
1129
1473
  }
1130
- await emitter.emit("watch", {
1131
- type: "tool-call-streaming-finish",
1132
- ...toolData ?? {}
1474
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1475
+ type: "watch",
1476
+ runId,
1477
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1133
1478
  });
1134
1479
  } else {
1135
1480
  for await (const chunk of stream) {
@@ -1139,6 +1484,9 @@ function createStep(params, agentOptions) {
1139
1484
  if (abortSignal.aborted) {
1140
1485
  return abort();
1141
1486
  }
1487
+ if (structuredResult !== null) {
1488
+ return structuredResult;
1489
+ }
1142
1490
  return {
1143
1491
  text: await streamPromise.promise
1144
1492
  };
@@ -1146,7 +1494,8 @@ function createStep(params, agentOptions) {
1146
1494
  component: params.component
1147
1495
  };
1148
1496
  }
1149
- if (isTool(params)) {
1497
+ if (params instanceof tools.Tool) {
1498
+ const toolOpts = agentOrToolOptions;
1150
1499
  if (!params.inputSchema || !params.outputSchema) {
1151
1500
  throw new Error("Tool must have input and output schemas defined");
1152
1501
  }
@@ -1158,6 +1507,8 @@ function createStep(params, agentOptions) {
1158
1507
  outputSchema: params.outputSchema,
1159
1508
  suspendSchema: params.suspendSchema,
1160
1509
  resumeSchema: params.resumeSchema,
1510
+ retries: toolOpts?.retries,
1511
+ scorers: toolOpts?.scorers,
1161
1512
  execute: async ({
1162
1513
  inputData,
1163
1514
  mastra,
@@ -1195,6 +1546,8 @@ function createStep(params, agentOptions) {
1195
1546
  outputSchema: params.outputSchema,
1196
1547
  resumeSchema: params.resumeSchema,
1197
1548
  suspendSchema: params.suspendSchema,
1549
+ retries: params.retries,
1550
+ scorers: params.scorers,
1198
1551
  execute: params.execute
1199
1552
  };
1200
1553
  }
@@ -1239,6 +1592,7 @@ function init(inngest) {
1239
1592
  }
1240
1593
 
1241
1594
  exports.InngestExecutionEngine = InngestExecutionEngine;
1595
+ exports.InngestPubSub = InngestPubSub;
1242
1596
  exports.InngestRun = InngestRun;
1243
1597
  exports.InngestWorkflow = InngestWorkflow;
1244
1598
  exports._compatibilityCheck = _compatibilityCheck;