@mastra/inngest 0.0.0-fix-prompt-enhance-route-20251210210827 → 0.0.0-fix-zod4-schema-validation-20251212180638

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
@@ -4,11 +4,13 @@ var tools = require('@mastra/core/tools');
4
4
  var workflows = require('@mastra/core/workflows');
5
5
  var _constants = require('@mastra/core/workflows/_constants');
6
6
  var zod = require('zod');
7
- var crypto = require('crypto');
7
+ var crypto$1 = require('crypto');
8
8
  var di = require('@mastra/core/di');
9
9
  var inngest = require('inngest');
10
- var web = require('stream/web');
10
+ var error = require('@mastra/core/error');
11
11
  var realtime = require('@inngest/realtime');
12
+ var events = require('@mastra/core/events');
13
+ var web = require('stream/web');
12
14
  var stream = require('@mastra/core/stream');
13
15
  var hono = require('inngest/hono');
14
16
 
@@ -25,17 +27,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
25
27
  // Hook Overrides
26
28
  // =============================================================================
27
29
  /**
28
- * Format errors with stack traces for better debugging in Inngest
30
+ * Format errors while preserving Error instances and their custom properties.
31
+ * Uses getErrorFromUnknown to ensure all error properties are preserved.
29
32
  */
30
- formatResultError(error, lastOutput) {
31
- if (error instanceof Error) {
32
- return error.stack ?? error.message;
33
- }
33
+ formatResultError(error$1, lastOutput) {
34
34
  const outputError = lastOutput?.error;
35
- if (outputError instanceof Error) {
36
- return outputError.message;
37
- }
38
- return outputError ?? error ?? "Unknown error";
35
+ const errorSource = error$1 || outputError;
36
+ const errorInstance = error.getErrorFromUnknown(errorSource, {
37
+ serializeStack: true,
38
+ // Include stack in JSON for better debugging in Inngest
39
+ fallbackMessage: "Unknown workflow error"
40
+ });
41
+ return errorInstance.toJSON();
39
42
  }
40
43
  /**
41
44
  * Detect InngestWorkflow instances for special nested workflow handling
@@ -67,18 +70,24 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
67
70
  error: e,
68
71
  attributes: { status: "failed" }
69
72
  });
73
+ if (cause.error && !(cause.error instanceof Error)) {
74
+ cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
75
+ }
70
76
  return { ok: false, error: cause };
71
77
  }
72
- const errorMessage = e instanceof Error ? e.message : String(e);
78
+ const errorInstance = error.getErrorFromUnknown(e, {
79
+ serializeStack: false,
80
+ fallbackMessage: "Unknown step execution error"
81
+ });
73
82
  params.stepSpan?.error({
74
- error: e,
83
+ error: errorInstance,
75
84
  attributes: { status: "failed" }
76
85
  });
77
86
  return {
78
87
  ok: false,
79
88
  error: {
80
89
  status: "failed",
81
- error: `Error: ${errorMessage}`,
90
+ error: errorInstance,
82
91
  endedAt: Date.now()
83
92
  }
84
93
  };
@@ -107,11 +116,14 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
107
116
  return await operationFn();
108
117
  } catch (e) {
109
118
  if (retryConfig) {
110
- const errorMessage = e instanceof Error ? e.message : String(e);
111
- throw new inngest.RetryAfterError(errorMessage, retryConfig.delay, {
119
+ const errorInstance = error.getErrorFromUnknown(e, {
120
+ serializeStack: false,
121
+ fallbackMessage: "Unknown step execution error"
122
+ });
123
+ throw new inngest.RetryAfterError(errorInstance.message, retryConfig.delay, {
112
124
  cause: {
113
125
  status: "failed",
114
- error: `Error: ${errorMessage}`,
126
+ error: errorInstance,
115
127
  endedAt: Date.now()
116
128
  }
117
129
  });
@@ -134,14 +146,14 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
134
146
  if (!(params.step instanceof InngestWorkflow)) {
135
147
  return null;
136
148
  }
137
- const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, emitter, startedAt } = params;
149
+ const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, pubsub, startedAt } = params;
138
150
  const isResume = !!resume?.steps?.length;
139
151
  let result;
140
152
  let runId;
141
153
  const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
142
154
  try {
143
155
  if (isResume) {
144
- runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
156
+ runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
145
157
  const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
146
158
  workflowName: step.id,
147
159
  runId
@@ -208,9 +220,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
208
220
  const errorCause = e?.cause;
209
221
  if (errorCause && typeof errorCause === "object") {
210
222
  result = errorCause;
211
- runId = errorCause.runId || crypto.randomUUID();
223
+ runId = errorCause.runId || crypto$1.randomUUID();
212
224
  } else {
213
- runId = crypto.randomUUID();
225
+ runId = crypto$1.randomUUID();
214
226
  result = {
215
227
  status: "failed",
216
228
  error: e instanceof Error ? e : new Error(String(e)),
@@ -223,13 +235,17 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
223
235
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
224
236
  async () => {
225
237
  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
238
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
239
+ type: "watch",
240
+ runId: executionContext.runId,
241
+ data: {
242
+ type: "workflow-step-result",
243
+ payload: {
244
+ id: step.id,
245
+ status: "failed",
246
+ error: result?.error,
247
+ payload: prevOutput
248
+ }
233
249
  }
234
250
  });
235
251
  return { executionContext, result: { status: "failed", error: result?.error } };
@@ -241,11 +257,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
241
257
  for (const [stepName, stepResult] of suspendedSteps) {
242
258
  const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
243
259
  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"
260
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
261
+ type: "watch",
262
+ runId: executionContext.runId,
263
+ data: {
264
+ type: "workflow-step-suspended",
265
+ payload: {
266
+ id: step.id,
267
+ status: "suspended"
268
+ }
249
269
  }
250
270
  });
251
271
  return {
@@ -267,20 +287,49 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
267
287
  payload: {}
268
288
  }
269
289
  };
290
+ } else if (result.status === "tripwire") {
291
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
292
+ type: "watch",
293
+ runId: executionContext.runId,
294
+ data: {
295
+ type: "workflow-step-result",
296
+ payload: {
297
+ id: step.id,
298
+ status: "tripwire",
299
+ error: result?.tripwire?.reason,
300
+ payload: prevOutput
301
+ }
302
+ }
303
+ });
304
+ return {
305
+ executionContext,
306
+ result: {
307
+ status: "tripwire",
308
+ tripwire: result?.tripwire
309
+ }
310
+ };
270
311
  }
271
- await emitter.emit("watch", {
272
- type: "workflow-step-result",
273
- payload: {
274
- id: step.id,
275
- status: "success",
276
- output: result?.result
312
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
313
+ type: "watch",
314
+ runId: executionContext.runId,
315
+ data: {
316
+ type: "workflow-step-result",
317
+ payload: {
318
+ id: step.id,
319
+ status: "success",
320
+ output: result?.result
321
+ }
277
322
  }
278
323
  });
279
- await emitter.emit("watch", {
280
- type: "workflow-step-finish",
281
- payload: {
282
- id: step.id,
283
- metadata: {}
324
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
325
+ type: "watch",
326
+ runId: executionContext.runId,
327
+ data: {
328
+ type: "workflow-step-finish",
329
+ payload: {
330
+ id: step.id,
331
+ metadata: {}
332
+ }
284
333
  }
285
334
  });
286
335
  return { executionContext, result: { status: "success", output: result?.result } };
@@ -297,6 +346,118 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
297
346
  };
298
347
  }
299
348
  };
349
+ var InngestPubSub = class extends events.PubSub {
350
+ inngest;
351
+ workflowId;
352
+ publishFn;
353
+ subscriptions = /* @__PURE__ */ new Map();
354
+ constructor(inngest, workflowId, publishFn) {
355
+ super();
356
+ this.inngest = inngest;
357
+ this.workflowId = workflowId;
358
+ this.publishFn = publishFn;
359
+ }
360
+ /**
361
+ * Publish an event to Inngest's realtime system.
362
+ *
363
+ * Topic format: "workflow.events.v2.{runId}"
364
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
365
+ */
366
+ async publish(topic, event) {
367
+ if (!this.publishFn) {
368
+ return;
369
+ }
370
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
371
+ if (!match) {
372
+ return;
373
+ }
374
+ const runId = match[1];
375
+ try {
376
+ await this.publishFn({
377
+ channel: `workflow:${this.workflowId}:${runId}`,
378
+ topic: "watch",
379
+ data: event.data
380
+ });
381
+ } catch (err) {
382
+ console.error("InngestPubSub publish error:", err?.message ?? err);
383
+ }
384
+ }
385
+ /**
386
+ * Subscribe to events from Inngest's realtime system.
387
+ *
388
+ * Topic format: "workflow.events.v2.{runId}"
389
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
390
+ */
391
+ async subscribe(topic, cb) {
392
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
393
+ if (!match || !match[1]) {
394
+ return;
395
+ }
396
+ const runId = match[1];
397
+ if (this.subscriptions.has(topic)) {
398
+ this.subscriptions.get(topic).callbacks.add(cb);
399
+ return;
400
+ }
401
+ const callbacks = /* @__PURE__ */ new Set([cb]);
402
+ const channel = `workflow:${this.workflowId}:${runId}`;
403
+ const streamPromise = realtime.subscribe(
404
+ {
405
+ channel,
406
+ topics: ["watch"],
407
+ app: this.inngest
408
+ },
409
+ (message) => {
410
+ const event = {
411
+ id: crypto.randomUUID(),
412
+ type: "watch",
413
+ runId,
414
+ data: message.data,
415
+ createdAt: /* @__PURE__ */ new Date()
416
+ };
417
+ for (const callback of callbacks) {
418
+ callback(event);
419
+ }
420
+ }
421
+ );
422
+ this.subscriptions.set(topic, {
423
+ unsubscribe: () => {
424
+ streamPromise.then((stream) => stream.cancel()).catch((err) => {
425
+ console.error("InngestPubSub unsubscribe error:", err);
426
+ });
427
+ },
428
+ callbacks
429
+ });
430
+ }
431
+ /**
432
+ * Unsubscribe a callback from a topic.
433
+ * If no callbacks remain, the underlying Inngest subscription is cancelled.
434
+ */
435
+ async unsubscribe(topic, cb) {
436
+ const sub = this.subscriptions.get(topic);
437
+ if (!sub) {
438
+ return;
439
+ }
440
+ sub.callbacks.delete(cb);
441
+ if (sub.callbacks.size === 0) {
442
+ sub.unsubscribe();
443
+ this.subscriptions.delete(topic);
444
+ }
445
+ }
446
+ /**
447
+ * Flush any pending operations. No-op for Inngest.
448
+ */
449
+ async flush() {
450
+ }
451
+ /**
452
+ * Clean up all subscriptions during graceful shutdown.
453
+ */
454
+ async close() {
455
+ for (const [, sub] of this.subscriptions) {
456
+ sub.unsubscribe();
457
+ }
458
+ this.subscriptions.clear();
459
+ }
460
+ };
300
461
  var InngestRun = class extends workflows.Run {
301
462
  inngest;
302
463
  serializedStepGraph;
@@ -308,27 +469,77 @@ var InngestRun = class extends workflows.Run {
308
469
  this.#mastra = params.mastra;
309
470
  }
310
471
  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}`
472
+ const maxRetries = 3;
473
+ let lastError = null;
474
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
475
+ try {
476
+ const response = await fetch(
477
+ `${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
478
+ {
479
+ headers: {
480
+ Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
481
+ }
482
+ }
483
+ );
484
+ if (response.status === 429) {
485
+ const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
486
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
487
+ continue;
488
+ }
489
+ if (!response.ok) {
490
+ throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
491
+ }
492
+ const text = await response.text();
493
+ if (!text) {
494
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
495
+ continue;
496
+ }
497
+ const json = JSON.parse(text);
498
+ return json.data;
499
+ } catch (error) {
500
+ lastError = error;
501
+ if (attempt < maxRetries - 1) {
502
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
503
+ }
314
504
  }
315
- });
316
- const json = await response.json();
317
- return json.data;
505
+ }
506
+ throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
318
507
  }
319
- async getRunOutput(eventId) {
320
- let runs = await this.getRuns(eventId);
508
+ async getRunOutput(eventId, maxWaitMs = 3e5) {
509
+ const startTime = Date.now();
321
510
  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);
511
+ while (Date.now() - startTime < maxWaitMs) {
512
+ let runs;
513
+ try {
514
+ runs = await this.getRuns(eventId);
515
+ } catch (error) {
516
+ if (error instanceof inngest.NonRetriableError) {
517
+ throw error;
518
+ }
519
+ throw new inngest.NonRetriableError(
520
+ `Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
521
+ );
522
+ }
523
+ if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
524
+ return runs[0];
525
+ }
325
526
  if (runs?.[0]?.status === "Failed") {
326
527
  const snapshot = await storage?.loadWorkflowSnapshot({
327
528
  workflowName: this.workflowId,
328
529
  runId: this.runId
329
530
  });
531
+ if (snapshot?.context) {
532
+ snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
533
+ }
330
534
  return {
331
- output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
535
+ output: {
536
+ result: {
537
+ steps: snapshot?.context,
538
+ status: "failed",
539
+ // Get the original error from NonRetriableError's cause (which contains the workflow result)
540
+ error: error.getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
541
+ }
542
+ }
332
543
  };
333
544
  }
334
545
  if (runs?.[0]?.status === "Cancelled") {
@@ -338,8 +549,9 @@ var InngestRun = class extends workflows.Run {
338
549
  });
339
550
  return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
340
551
  }
552
+ await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
341
553
  }
342
- return runs?.[0];
554
+ throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
343
555
  }
344
556
  async cancel() {
345
557
  const storage = this.#mastra?.getStorage();
@@ -369,6 +581,51 @@ var InngestRun = class extends workflows.Run {
369
581
  async start(params) {
370
582
  return this._start(params);
371
583
  }
584
+ /**
585
+ * Starts the workflow execution without waiting for completion (fire-and-forget).
586
+ * Returns immediately with the runId after sending the event to Inngest.
587
+ * The workflow executes independently in Inngest.
588
+ * Use this when you don't need to wait for the result or want to avoid polling failures.
589
+ */
590
+ async startAsync(params) {
591
+ await this.#mastra.getStorage()?.persistWorkflowSnapshot({
592
+ workflowName: this.workflowId,
593
+ runId: this.runId,
594
+ resourceId: this.resourceId,
595
+ snapshot: {
596
+ runId: this.runId,
597
+ serializedStepGraph: this.serializedStepGraph,
598
+ status: "running",
599
+ value: {},
600
+ context: {},
601
+ activePaths: [],
602
+ suspendedPaths: {},
603
+ activeStepsPath: {},
604
+ resumeLabels: {},
605
+ waitingPaths: {},
606
+ timestamp: Date.now()
607
+ }
608
+ });
609
+ const inputDataToUse = await this._validateInput(params.inputData);
610
+ const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
611
+ const eventOutput = await this.inngest.send({
612
+ name: `workflow.${this.workflowId}`,
613
+ data: {
614
+ inputData: inputDataToUse,
615
+ initialState: initialStateToUse,
616
+ runId: this.runId,
617
+ resourceId: this.resourceId,
618
+ outputOptions: params.outputOptions,
619
+ tracingOptions: params.tracingOptions,
620
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
621
+ }
622
+ });
623
+ const eventId = eventOutput.ids[0];
624
+ if (!eventId) {
625
+ throw new Error("Event ID is not set");
626
+ }
627
+ return { runId: this.runId };
628
+ }
372
629
  async _start({
373
630
  inputData,
374
631
  initialState,
@@ -416,9 +673,7 @@ var InngestRun = class extends workflows.Run {
416
673
  }
417
674
  const runOutput = await this.getRunOutput(eventId);
418
675
  const result = runOutput?.output?.result;
419
- if (result.status === "failed") {
420
- result.error = new Error(result.error);
421
- }
676
+ this.hydrateFailedResult(result);
422
677
  if (result.status !== "suspended") {
423
678
  this.cleanup?.();
424
679
  }
@@ -477,9 +732,7 @@ var InngestRun = class extends workflows.Run {
477
732
  }
478
733
  const runOutput = await this.getRunOutput(eventId);
479
734
  const result = runOutput?.output?.result;
480
- if (result.status === "failed") {
481
- result.error = new Error(result.error);
482
- }
735
+ this.hydrateFailedResult(result);
483
736
  return result;
484
737
  }
485
738
  async timeTravel(params) {
@@ -569,9 +822,7 @@ var InngestRun = class extends workflows.Run {
569
822
  }
570
823
  const runOutput = await this.getRunOutput(eventId);
571
824
  const result = runOutput?.output?.result;
572
- if (result.status === "failed") {
573
- result.error = new Error(result.error);
574
- }
825
+ this.hydrateFailedResult(result);
575
826
  return result;
576
827
  }
577
828
  watch(cb) {
@@ -792,6 +1043,18 @@ var InngestRun = class extends workflows.Run {
792
1043
  });
793
1044
  return this.streamOutput;
794
1045
  }
1046
+ /**
1047
+ * Hydrates errors in a failed workflow result back to proper Error instances.
1048
+ * This ensures error.cause chains and custom properties are preserved.
1049
+ */
1050
+ hydrateFailedResult(result) {
1051
+ if (result.status === "failed") {
1052
+ result.error = error.getErrorFromUnknown(result.error, { serializeStack: false });
1053
+ if (result.steps) {
1054
+ workflows.hydrateSerializedStepErrors(result.steps);
1055
+ }
1056
+ }
1057
+ }
795
1058
  };
796
1059
 
797
1060
  // src/workflow.ts
@@ -829,6 +1092,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
829
1092
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
830
1093
  }
831
1094
  __registerMastra(mastra) {
1095
+ super.__registerMastra(mastra);
832
1096
  this.#mastra = mastra;
833
1097
  this.executionEngine.__registerMastra(mastra);
834
1098
  const updateNested = (step) => {
@@ -847,7 +1111,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
847
1111
  }
848
1112
  }
849
1113
  async createRun(options) {
850
- const runIdToUse = options?.runId || crypto.randomUUID();
1114
+ const runIdToUse = options?.runId || crypto$1.randomUUID();
851
1115
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
852
1116
  {
853
1117
  workflowId: this.id,
@@ -912,31 +1176,10 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
912
1176
  let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
913
1177
  if (!runId) {
914
1178
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
915
- return crypto.randomUUID();
1179
+ return crypto$1.randomUUID();
916
1180
  });
917
1181
  }
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
- };
1182
+ const pubsub = new InngestPubSub(this.inngest, this.id, publish);
940
1183
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
941
1184
  const result = await engine.execute({
942
1185
  workflowId: this.id,
@@ -946,7 +1189,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
946
1189
  serializedStepGraph: this.serializedStepGraph,
947
1190
  input: inputData,
948
1191
  initialState,
949
- emitter,
1192
+ pubsub,
950
1193
  retryConfig: this.retryConfig,
951
1194
  requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
952
1195
  resume,
@@ -956,8 +1199,15 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
956
1199
  // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
957
1200
  outputOptions,
958
1201
  outputWriter: async (chunk) => {
959
- void emitter.emit("watch", chunk).catch(() => {
960
- });
1202
+ try {
1203
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1204
+ type: "watch",
1205
+ runId,
1206
+ data: chunk
1207
+ });
1208
+ } catch (err) {
1209
+ this.logger.debug?.("Failed to publish watch event:", err);
1210
+ }
961
1211
  }
962
1212
  });
963
1213
  await step.run(`workflow.${this.id}.finalize`, async () => {
@@ -1045,7 +1295,8 @@ function createStep(params, agentOptions) {
1045
1295
  outputSchema,
1046
1296
  execute: async ({
1047
1297
  inputData,
1048
- [_constants.EMITTER_SYMBOL]: emitter,
1298
+ runId,
1299
+ [_constants.PUBSUB_SYMBOL]: pubsub,
1049
1300
  [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
1050
1301
  requestContext,
1051
1302
  tracingContext,
@@ -1100,22 +1351,24 @@ function createStep(params, agentOptions) {
1100
1351
  stream = modelOutput.fullStream;
1101
1352
  }
1102
1353
  if (streamFormat === "legacy") {
1103
- await emitter.emit("watch", {
1104
- type: "tool-call-streaming-start",
1105
- ...toolData ?? {}
1354
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1355
+ type: "watch",
1356
+ runId,
1357
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1106
1358
  });
1107
1359
  for await (const chunk of stream) {
1108
1360
  if (chunk.type === "text-delta") {
1109
- await emitter.emit("watch", {
1110
- type: "tool-call-delta",
1111
- ...toolData ?? {},
1112
- argsTextDelta: chunk.textDelta
1361
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1362
+ type: "watch",
1363
+ runId,
1364
+ data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
1113
1365
  });
1114
1366
  }
1115
1367
  }
1116
- await emitter.emit("watch", {
1117
- type: "tool-call-streaming-finish",
1118
- ...toolData ?? {}
1368
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1369
+ type: "watch",
1370
+ runId,
1371
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1119
1372
  });
1120
1373
  } else {
1121
1374
  for await (const chunk of stream) {
@@ -1228,6 +1481,7 @@ function init(inngest) {
1228
1481
  }
1229
1482
 
1230
1483
  exports.InngestExecutionEngine = InngestExecutionEngine;
1484
+ exports.InngestPubSub = InngestPubSub;
1231
1485
  exports.InngestRun = InngestRun;
1232
1486
  exports.InngestWorkflow = InngestWorkflow;
1233
1487
  exports._compatibilityCheck = _compatibilityCheck;