@mastra/inngest 0.0.0-feat-add-query-option-to-playground-20251209160219 → 0.0.0-feat-8782-cf-bindings-20260102164434

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 crypto$1 = require('crypto');
8
9
  var di = require('@mastra/core/di');
9
10
  var inngest = require('inngest');
10
- var web = require('stream/web');
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,39 +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
  };
316
+ } else if (result.status === "tripwire") {
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
+ }
328
+ }
329
+ });
330
+ return {
331
+ executionContext,
332
+ result: {
333
+ status: "tripwire",
334
+ tripwire: result?.tripwire,
335
+ endedAt: Date.now()
336
+ }
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" } };
270
362
  }
271
- await emitter.emit("watch", {
272
- type: "workflow-step-result",
273
- payload: {
274
- id: step.id,
275
- status: "success",
276
- 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
+ }
277
373
  }
278
374
  });
279
- await emitter.emit("watch", {
280
- type: "workflow-step-finish",
281
- payload: {
282
- id: step.id,
283
- 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
+ }
284
384
  }
285
385
  });
286
- return { executionContext, result: { status: "success", output: result?.result } };
386
+ return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
287
387
  }
288
388
  );
289
389
  Object.assign(executionContext, res.executionContext);
290
390
  return {
291
391
  ...res.result,
292
392
  startedAt,
293
- endedAt: Date.now(),
294
393
  payload: inputData,
295
394
  resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
296
395
  resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
297
396
  };
298
397
  }
299
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
+ };
300
511
  var InngestRun = class extends workflows.Run {
301
512
  inngest;
302
513
  serializedStepGraph;
@@ -308,38 +519,90 @@ var InngestRun = class extends workflows.Run {
308
519
  this.#mastra = params.mastra;
309
520
  }
310
521
  async getRuns(eventId) {
311
- const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
312
- headers: {
313
- 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
+ }
314
554
  }
315
- });
316
- const json = await response.json();
317
- return json.data;
555
+ }
556
+ throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
318
557
  }
319
- async getRunOutput(eventId) {
320
- let runs = await this.getRuns(eventId);
558
+ async getRunOutput(eventId, maxWaitMs = 3e5) {
559
+ const startTime = Date.now();
321
560
  const storage = this.#mastra?.getStorage();
322
- while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
323
- await new Promise((resolve) => setTimeout(resolve, 1e3));
324
- 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
+ }
325
577
  if (runs?.[0]?.status === "Failed") {
326
- const snapshot = await storage?.loadWorkflowSnapshot({
578
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
327
579
  workflowName: this.workflowId,
328
580
  runId: this.runId
329
581
  });
582
+ if (snapshot?.context) {
583
+ snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
584
+ }
330
585
  return {
331
- 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
+ }
332
594
  };
333
595
  }
334
596
  if (runs?.[0]?.status === "Cancelled") {
335
- const snapshot = await storage?.loadWorkflowSnapshot({
597
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
336
598
  workflowName: this.workflowId,
337
599
  runId: this.runId
338
600
  });
339
601
  return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
340
602
  }
603
+ await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
341
604
  }
342
- return runs?.[0];
605
+ throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
343
606
  }
344
607
  async cancel() {
345
608
  const storage = this.#mastra?.getStorage();
@@ -349,12 +612,13 @@ var InngestRun = class extends workflows.Run {
349
612
  runId: this.runId
350
613
  }
351
614
  });
352
- const snapshot = await storage?.loadWorkflowSnapshot({
615
+ const workflowsStore = await storage?.getStore("workflows");
616
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
353
617
  workflowName: this.workflowId,
354
618
  runId: this.runId
355
619
  });
356
620
  if (snapshot) {
357
- await storage?.persistWorkflowSnapshot({
621
+ await workflowsStore?.persistWorkflowSnapshot({
358
622
  workflowName: this.workflowId,
359
623
  runId: this.runId,
360
624
  resourceId: this.resourceId,
@@ -369,15 +633,64 @@ var InngestRun = class extends workflows.Run {
369
633
  async start(params) {
370
634
  return this._start(params);
371
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
+ }
372
683
  async _start({
373
684
  inputData,
374
685
  initialState,
375
686
  outputOptions,
376
687
  tracingOptions,
377
688
  format,
378
- requestContext
689
+ requestContext,
690
+ perStep
379
691
  }) {
380
- await this.#mastra.getStorage()?.persistWorkflowSnapshot({
692
+ const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
693
+ await workflowsStore?.persistWorkflowSnapshot({
381
694
  workflowName: this.workflowId,
382
695
  runId: this.runId,
383
696
  resourceId: this.resourceId,
@@ -407,7 +720,8 @@ var InngestRun = class extends workflows.Run {
407
720
  outputOptions,
408
721
  tracingOptions,
409
722
  format,
410
- requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
723
+ requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
724
+ perStep
411
725
  }
412
726
  });
413
727
  const eventId = eventOutput.ids[0];
@@ -416,9 +730,7 @@ var InngestRun = class extends workflows.Run {
416
730
  }
417
731
  const runOutput = await this.getRunOutput(eventId);
418
732
  const result = runOutput?.output?.result;
419
- if (result.status === "failed") {
420
- result.error = new Error(result.error);
421
- }
733
+ this.hydrateFailedResult(result);
422
734
  if (result.status !== "suspended") {
423
735
  this.cleanup?.();
424
736
  }
@@ -445,7 +757,8 @@ var InngestRun = class extends workflows.Run {
445
757
  (step) => typeof step === "string" ? step : step?.id
446
758
  );
447
759
  }
448
- const snapshot = await storage?.loadWorkflowSnapshot({
760
+ const workflowsStore = await storage?.getStore("workflows");
761
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
449
762
  workflowName: this.workflowId,
450
763
  runId: this.runId
451
764
  });
@@ -468,7 +781,8 @@ var InngestRun = class extends workflows.Run {
468
781
  resumePayload: resumeDataToUse,
469
782
  resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
470
783
  },
471
- requestContext: mergedRequestContext
784
+ requestContext: mergedRequestContext,
785
+ perStep: params.perStep
472
786
  }
473
787
  });
474
788
  const eventId = eventOutput.ids[0];
@@ -477,9 +791,7 @@ var InngestRun = class extends workflows.Run {
477
791
  }
478
792
  const runOutput = await this.getRunOutput(eventId);
479
793
  const result = runOutput?.output?.result;
480
- if (result.status === "failed") {
481
- result.error = new Error(result.error);
482
- }
794
+ this.hydrateFailedResult(result);
483
795
  return result;
484
796
  }
485
797
  async timeTravel(params) {
@@ -509,12 +821,13 @@ var InngestRun = class extends workflows.Run {
509
821
  throw new Error("No steps provided to timeTravel");
510
822
  }
511
823
  const storage = this.#mastra?.getStorage();
512
- const snapshot = await storage?.loadWorkflowSnapshot({
824
+ const workflowsStore = await storage?.getStore("workflows");
825
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
513
826
  workflowName: this.workflowId,
514
827
  runId: this.runId
515
828
  });
516
829
  if (!snapshot) {
517
- await storage?.persistWorkflowSnapshot({
830
+ await workflowsStore?.persistWorkflowSnapshot({
518
831
  workflowName: this.workflowId,
519
832
  runId: this.runId,
520
833
  resourceId: this.resourceId,
@@ -548,7 +861,8 @@ var InngestRun = class extends workflows.Run {
548
861
  nestedStepsContext: params.nestedStepsContext,
549
862
  snapshot: snapshot ?? { context: {} },
550
863
  graph: this.executionGraph,
551
- initialState: params.initialState
864
+ initialState: params.initialState,
865
+ perStep: params.perStep
552
866
  });
553
867
  const eventOutput = await this.inngest.send({
554
868
  name: `workflow.${this.workflowId}`,
@@ -560,7 +874,8 @@ var InngestRun = class extends workflows.Run {
560
874
  timeTravel: timeTravelData,
561
875
  tracingOptions: params.tracingOptions,
562
876
  outputOptions: params.outputOptions,
563
- requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
877
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
878
+ perStep: params.perStep
564
879
  }
565
880
  });
566
881
  const eventId = eventOutput.ids[0];
@@ -569,9 +884,7 @@ var InngestRun = class extends workflows.Run {
569
884
  }
570
885
  const runOutput = await this.getRunOutput(eventId);
571
886
  const result = runOutput?.output?.result;
572
- if (result.status === "failed") {
573
- result.error = new Error(result.error);
574
- }
887
+ this.hydrateFailedResult(result);
575
888
  return result;
576
889
  }
577
890
  watch(cb) {
@@ -653,7 +966,8 @@ var InngestRun = class extends workflows.Run {
653
966
  tracingOptions,
654
967
  closeOnSuspend = true,
655
968
  initialState,
656
- outputOptions
969
+ outputOptions,
970
+ perStep
657
971
  } = {}) {
658
972
  if (this.closeStreamAction && this.streamOutput) {
659
973
  return this.streamOutput;
@@ -689,7 +1003,8 @@ var InngestRun = class extends workflows.Run {
689
1003
  initialState,
690
1004
  tracingOptions,
691
1005
  outputOptions,
692
- format: "vnext"
1006
+ format: "vnext",
1007
+ perStep
693
1008
  });
694
1009
  let executionResults;
695
1010
  try {
@@ -720,9 +1035,6 @@ var InngestRun = class extends workflows.Run {
720
1035
  });
721
1036
  return this.streamOutput;
722
1037
  }
723
- streamVNext(args = {}) {
724
- return this.stream(args);
725
- }
726
1038
  timeTravelStream({
727
1039
  inputData,
728
1040
  resumeData,
@@ -732,7 +1044,8 @@ var InngestRun = class extends workflows.Run {
732
1044
  nestedStepsContext,
733
1045
  requestContext,
734
1046
  tracingOptions,
735
- outputOptions
1047
+ outputOptions,
1048
+ perStep
736
1049
  }) {
737
1050
  this.closeStreamAction = async () => {
738
1051
  };
@@ -767,7 +1080,8 @@ var InngestRun = class extends workflows.Run {
767
1080
  initialState,
768
1081
  requestContext,
769
1082
  tracingOptions,
770
- outputOptions
1083
+ outputOptions,
1084
+ perStep
771
1085
  });
772
1086
  self.executionResults = executionResultsPromise;
773
1087
  let executionResults;
@@ -792,6 +1106,18 @@ var InngestRun = class extends workflows.Run {
792
1106
  });
793
1107
  return this.streamOutput;
794
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
+ }
795
1121
  };
796
1122
 
797
1123
  // src/workflow.ts
@@ -799,9 +1125,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
799
1125
  #mastra;
800
1126
  inngest;
801
1127
  function;
1128
+ cronFunction;
802
1129
  flowControlConfig;
1130
+ cronConfig;
803
1131
  constructor(params, inngest) {
804
- const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
1132
+ const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
805
1133
  super(workflowParams);
806
1134
  this.engineType = "inngest";
807
1135
  const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
@@ -810,6 +1138,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
810
1138
  this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
811
1139
  this.#mastra = params.mastra;
812
1140
  this.inngest = inngest;
1141
+ if (cron) {
1142
+ this.cronConfig = { cron, inputData, initialState };
1143
+ }
813
1144
  }
814
1145
  async listWorkflowRuns(args) {
815
1146
  const storage = this.#mastra?.getStorage();
@@ -817,7 +1148,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
817
1148
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
818
1149
  return { runs: [], total: 0 };
819
1150
  }
820
- 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 ?? {} });
821
1156
  }
822
1157
  async getWorkflowRunById(runId) {
823
1158
  const storage = this.#mastra?.getStorage();
@@ -825,10 +1160,15 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
825
1160
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
826
1161
  return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
827
1162
  }
828
- 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 });
829
1168
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
830
1169
  }
831
1170
  __registerMastra(mastra) {
1171
+ super.__registerMastra(mastra);
832
1172
  this.#mastra = mastra;
833
1173
  this.executionEngine.__registerMastra(mastra);
834
1174
  const updateNested = (step) => {
@@ -847,7 +1187,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
847
1187
  }
848
1188
  }
849
1189
  async createRun(options) {
850
- const runIdToUse = options?.runId || crypto.randomUUID();
1190
+ const runIdToUse = options?.runId || crypto$1.randomUUID();
851
1191
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
852
1192
  {
853
1193
  workflowId: this.id,
@@ -870,9 +1210,12 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
870
1210
  workflowStatus: run.workflowRunStatus,
871
1211
  stepResults: {}
872
1212
  });
873
- const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
1213
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
1214
+ withNestedWorkflows: false
1215
+ });
874
1216
  if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
875
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
1217
+ const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
1218
+ await workflowsStore?.persistWorkflowSnapshot({
876
1219
  workflowName: this.id,
877
1220
  runId: runIdToUse,
878
1221
  resourceId: options?.resourceId,
@@ -895,6 +1238,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
895
1238
  }
896
1239
  return run;
897
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
+ }
898
1265
  getFunction() {
899
1266
  if (this.function) {
900
1267
  return this.function;
@@ -902,41 +1269,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
902
1269
  this.function = this.inngest.createFunction(
903
1270
  {
904
1271
  id: `workflow.${this.id}`,
905
- retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
1272
+ retries: 0,
906
1273
  cancelOn: [{ event: `cancel.workflow.${this.id}` }],
907
1274
  // Spread flow control configuration
908
1275
  ...this.flowControlConfig
909
1276
  },
910
1277
  { event: `workflow.${this.id}` },
911
1278
  async ({ event, step, attempt, publish }) => {
912
- let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
1279
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
913
1280
  if (!runId) {
914
1281
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
915
- return crypto.randomUUID();
1282
+ return crypto$1.randomUUID();
916
1283
  });
917
1284
  }
918
- const emitter = {
919
- emit: async (event2, data) => {
920
- if (!publish) {
921
- return;
922
- }
923
- try {
924
- await publish({
925
- channel: `workflow:${this.id}:${runId}`,
926
- topic: event2,
927
- data
928
- });
929
- } catch (err) {
930
- this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
931
- }
932
- },
933
- on: (_event, _callback) => {
934
- },
935
- off: (_event, _callback) => {
936
- },
937
- once: (_event, _callback) => {
938
- }
939
- };
1285
+ const pubsub = new InngestPubSub(this.inngest, this.id, publish);
940
1286
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
941
1287
  const result = await engine.execute({
942
1288
  workflowId: this.id,
@@ -946,21 +1292,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
946
1292
  serializedStepGraph: this.serializedStepGraph,
947
1293
  input: inputData,
948
1294
  initialState,
949
- emitter,
1295
+ pubsub,
950
1296
  retryConfig: this.retryConfig,
951
1297
  requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
952
1298
  resume,
953
1299
  timeTravel,
1300
+ perStep,
954
1301
  format,
955
1302
  abortController: new AbortController(),
956
1303
  // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
957
1304
  outputOptions,
958
1305
  outputWriter: async (chunk) => {
959
- void emitter.emit("watch", chunk).catch(() => {
960
- });
1306
+ try {
1307
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1308
+ type: "watch",
1309
+ runId,
1310
+ data: chunk
1311
+ });
1312
+ } catch (err) {
1313
+ this.logger.debug?.("Failed to publish watch event:", err);
1314
+ }
961
1315
  }
962
1316
  });
963
1317
  await step.run(`workflow.${this.id}.finalize`, async () => {
1318
+ if (result.status !== "paused") {
1319
+ await engine.invokeLifecycleCallbacksInternal(result);
1320
+ }
964
1321
  if (result.status === "failed") {
965
1322
  throw new inngest.NonRetriableError(`Workflow failed`, {
966
1323
  cause: result
@@ -987,7 +1344,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
987
1344
  });
988
1345
  }
989
1346
  getFunctions() {
990
- 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
+ ];
991
1352
  }
992
1353
  };
993
1354
  function serve({
@@ -1019,20 +1380,14 @@ function serve({
1019
1380
  var _compatibilityCheck = true;
1020
1381
 
1021
1382
  // src/index.ts
1022
- function isAgent(params) {
1023
- return params?.component === "AGENT";
1024
- }
1025
- function isTool(params) {
1026
- return params instanceof tools.Tool;
1027
- }
1028
- function isInngestWorkflow(params) {
1029
- return params instanceof InngestWorkflow;
1030
- }
1031
- function createStep(params, agentOptions) {
1032
- if (isInngestWorkflow(params)) {
1383
+ function createStep(params, agentOrToolOptions) {
1384
+ if (params instanceof InngestWorkflow) {
1033
1385
  return params;
1034
1386
  }
1035
- 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 ?? {};
1036
1391
  return {
1037
1392
  id: params.name,
1038
1393
  description: params.getDescription(),
@@ -1041,12 +1396,13 @@ function createStep(params, agentOptions) {
1041
1396
  // resourceId: z.string().optional(),
1042
1397
  // threadId: z.string().optional(),
1043
1398
  }),
1044
- outputSchema: zod.z.object({
1045
- text: zod.z.string()
1046
- }),
1399
+ outputSchema,
1400
+ retries,
1401
+ scorers,
1047
1402
  execute: async ({
1048
1403
  inputData,
1049
- [_constants.EMITTER_SYMBOL]: emitter,
1404
+ runId,
1405
+ [_constants.PUBSUB_SYMBOL]: pubsub,
1050
1406
  [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1051
1407
  requestContext,
1052
1408
  tracingContext,
@@ -1059,6 +1415,7 @@ function createStep(params, agentOptions) {
1059
1415
  streamPromise.resolve = resolve;
1060
1416
  streamPromise.reject = reject;
1061
1417
  });
1418
+ let structuredResult = null;
1062
1419
  const toolData = {
1063
1420
  name: params.name,
1064
1421
  args: inputData
@@ -1072,6 +1429,10 @@ function createStep(params, agentOptions) {
1072
1429
  requestContext,
1073
1430
  tracingContext,
1074
1431
  onFinish: (result) => {
1432
+ const resultWithObject = result;
1433
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1434
+ structuredResult = resultWithObject.object;
1435
+ }
1075
1436
  streamPromise.resolve(result.text);
1076
1437
  void agentOptions?.onFinish?.(result);
1077
1438
  },
@@ -1084,6 +1445,10 @@ function createStep(params, agentOptions) {
1084
1445
  requestContext,
1085
1446
  tracingContext,
1086
1447
  onFinish: (result) => {
1448
+ const resultWithObject = result;
1449
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1450
+ structuredResult = resultWithObject.object;
1451
+ }
1087
1452
  streamPromise.resolve(result.text);
1088
1453
  void agentOptions?.onFinish?.(result);
1089
1454
  },
@@ -1092,22 +1457,24 @@ function createStep(params, agentOptions) {
1092
1457
  stream = modelOutput.fullStream;
1093
1458
  }
1094
1459
  if (streamFormat === "legacy") {
1095
- await emitter.emit("watch", {
1096
- type: "tool-call-streaming-start",
1097
- ...toolData ?? {}
1460
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1461
+ type: "watch",
1462
+ runId,
1463
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1098
1464
  });
1099
1465
  for await (const chunk of stream) {
1100
1466
  if (chunk.type === "text-delta") {
1101
- await emitter.emit("watch", {
1102
- type: "tool-call-delta",
1103
- ...toolData ?? {},
1104
- 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 }
1105
1471
  });
1106
1472
  }
1107
1473
  }
1108
- await emitter.emit("watch", {
1109
- type: "tool-call-streaming-finish",
1110
- ...toolData ?? {}
1474
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1475
+ type: "watch",
1476
+ runId,
1477
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1111
1478
  });
1112
1479
  } else {
1113
1480
  for await (const chunk of stream) {
@@ -1117,6 +1484,9 @@ function createStep(params, agentOptions) {
1117
1484
  if (abortSignal.aborted) {
1118
1485
  return abort();
1119
1486
  }
1487
+ if (structuredResult !== null) {
1488
+ return structuredResult;
1489
+ }
1120
1490
  return {
1121
1491
  text: await streamPromise.promise
1122
1492
  };
@@ -1124,7 +1494,8 @@ function createStep(params, agentOptions) {
1124
1494
  component: params.component
1125
1495
  };
1126
1496
  }
1127
- if (isTool(params)) {
1497
+ if (params instanceof tools.Tool) {
1498
+ const toolOpts = agentOrToolOptions;
1128
1499
  if (!params.inputSchema || !params.outputSchema) {
1129
1500
  throw new Error("Tool must have input and output schemas defined");
1130
1501
  }
@@ -1136,6 +1507,8 @@ function createStep(params, agentOptions) {
1136
1507
  outputSchema: params.outputSchema,
1137
1508
  suspendSchema: params.suspendSchema,
1138
1509
  resumeSchema: params.resumeSchema,
1510
+ retries: toolOpts?.retries,
1511
+ scorers: toolOpts?.scorers,
1139
1512
  execute: async ({
1140
1513
  inputData,
1141
1514
  mastra,
@@ -1173,6 +1546,8 @@ function createStep(params, agentOptions) {
1173
1546
  outputSchema: params.outputSchema,
1174
1547
  resumeSchema: params.resumeSchema,
1175
1548
  suspendSchema: params.suspendSchema,
1549
+ retries: params.retries,
1550
+ scorers: params.scorers,
1176
1551
  execute: params.execute
1177
1552
  };
1178
1553
  }
@@ -1217,6 +1592,7 @@ function init(inngest) {
1217
1592
  }
1218
1593
 
1219
1594
  exports.InngestExecutionEngine = InngestExecutionEngine;
1595
+ exports.InngestPubSub = InngestPubSub;
1220
1596
  exports.InngestRun = InngestRun;
1221
1597
  exports.InngestWorkflow = InngestWorkflow;
1222
1598
  exports._compatibilityCheck = _compatibilityCheck;