@mastra/inngest 0.0.0-fix-request-context-as-query-key-20251209130646 → 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.js CHANGED
@@ -1,12 +1,14 @@
1
1
  import { Tool } from '@mastra/core/tools';
2
- import { DefaultExecutionEngine, createTimeTravelExecutionParams, Run, Workflow } from '@mastra/core/workflows';
3
- import { EMITTER_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
2
+ import { DefaultExecutionEngine, createTimeTravelExecutionParams, Run, hydrateSerializedStepErrors, Workflow } from '@mastra/core/workflows';
3
+ import { PUBSUB_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
4
4
  import { z } from 'zod';
5
5
  import { randomUUID } from 'crypto';
6
- import { ReadableStream, WritableStream } from 'stream/web';
7
6
  import { RequestContext } from '@mastra/core/di';
8
7
  import { RetryAfterError, NonRetriableError } from 'inngest';
8
+ import { getErrorFromUnknown } from '@mastra/core/error';
9
9
  import { subscribe } from '@inngest/realtime';
10
+ import { PubSub } from '@mastra/core/events';
11
+ import { ReadableStream } from 'stream/web';
10
12
  import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
11
13
  import { serve as serve$1 } from 'inngest/hono';
12
14
 
@@ -23,17 +25,18 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
23
25
  // Hook Overrides
24
26
  // =============================================================================
25
27
  /**
26
- * Format errors with stack traces for better debugging in Inngest
28
+ * Format errors while preserving Error instances and their custom properties.
29
+ * Uses getErrorFromUnknown to ensure all error properties are preserved.
27
30
  */
28
31
  formatResultError(error, lastOutput) {
29
- if (error instanceof Error) {
30
- return error.stack ?? error.message;
31
- }
32
32
  const outputError = lastOutput?.error;
33
- if (outputError instanceof Error) {
34
- return outputError.message;
35
- }
36
- return outputError ?? error ?? "Unknown error";
33
+ const errorSource = error || outputError;
34
+ const errorInstance = getErrorFromUnknown(errorSource, {
35
+ serializeStack: true,
36
+ // Include stack in JSON for better debugging in Inngest
37
+ fallbackMessage: "Unknown workflow error"
38
+ });
39
+ return errorInstance.toJSON();
37
40
  }
38
41
  /**
39
42
  * Detect InngestWorkflow instances for special nested workflow handling
@@ -65,18 +68,24 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
65
68
  error: e,
66
69
  attributes: { status: "failed" }
67
70
  });
71
+ if (cause.error && !(cause.error instanceof Error)) {
72
+ cause.error = getErrorFromUnknown(cause.error, { serializeStack: false });
73
+ }
68
74
  return { ok: false, error: cause };
69
75
  }
70
- const errorMessage = e instanceof Error ? e.message : String(e);
76
+ const errorInstance = getErrorFromUnknown(e, {
77
+ serializeStack: false,
78
+ fallbackMessage: "Unknown step execution error"
79
+ });
71
80
  params.stepSpan?.error({
72
- error: e,
81
+ error: errorInstance,
73
82
  attributes: { status: "failed" }
74
83
  });
75
84
  return {
76
85
  ok: false,
77
86
  error: {
78
87
  status: "failed",
79
- error: `Error: ${errorMessage}`,
88
+ error: errorInstance,
80
89
  endedAt: Date.now()
81
90
  }
82
91
  };
@@ -105,11 +114,14 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
105
114
  return await operationFn();
106
115
  } catch (e) {
107
116
  if (retryConfig) {
108
- const errorMessage = e instanceof Error ? e.message : String(e);
109
- throw new RetryAfterError(errorMessage, retryConfig.delay, {
117
+ const errorInstance = getErrorFromUnknown(e, {
118
+ serializeStack: false,
119
+ fallbackMessage: "Unknown step execution error"
120
+ });
121
+ throw new RetryAfterError(errorInstance.message, retryConfig.delay, {
110
122
  cause: {
111
123
  status: "failed",
112
- error: `Error: ${errorMessage}`,
124
+ error: errorInstance,
113
125
  endedAt: Date.now()
114
126
  }
115
127
  });
@@ -132,7 +144,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
132
144
  if (!(params.step instanceof InngestWorkflow)) {
133
145
  return null;
134
146
  }
135
- const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, emitter, startedAt } = params;
147
+ const { step, stepResults, executionContext, resume, timeTravel, prevOutput, inputData, pubsub, startedAt } = params;
136
148
  const isResume = !!resume?.steps?.length;
137
149
  let result;
138
150
  let runId;
@@ -221,13 +233,17 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
221
233
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
222
234
  async () => {
223
235
  if (result.status === "failed") {
224
- await emitter.emit("watch", {
225
- type: "workflow-step-result",
226
- payload: {
227
- id: step.id,
228
- status: "failed",
229
- error: result?.error,
230
- payload: prevOutput
236
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
237
+ type: "watch",
238
+ runId: executionContext.runId,
239
+ data: {
240
+ type: "workflow-step-result",
241
+ payload: {
242
+ id: step.id,
243
+ status: "failed",
244
+ error: result?.error,
245
+ payload: prevOutput
246
+ }
231
247
  }
232
248
  });
233
249
  return { executionContext, result: { status: "failed", error: result?.error } };
@@ -239,11 +255,15 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
239
255
  for (const [stepName, stepResult] of suspendedSteps) {
240
256
  const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
241
257
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
242
- await emitter.emit("watch", {
243
- type: "workflow-step-suspended",
244
- payload: {
245
- id: step.id,
246
- status: "suspended"
258
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
259
+ type: "watch",
260
+ runId: executionContext.runId,
261
+ data: {
262
+ type: "workflow-step-suspended",
263
+ payload: {
264
+ id: step.id,
265
+ status: "suspended"
266
+ }
247
267
  }
248
268
  });
249
269
  return {
@@ -265,20 +285,49 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
265
285
  payload: {}
266
286
  }
267
287
  };
288
+ } else if (result.status === "tripwire") {
289
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
290
+ type: "watch",
291
+ runId: executionContext.runId,
292
+ data: {
293
+ type: "workflow-step-result",
294
+ payload: {
295
+ id: step.id,
296
+ status: "tripwire",
297
+ error: result?.tripwire?.reason,
298
+ payload: prevOutput
299
+ }
300
+ }
301
+ });
302
+ return {
303
+ executionContext,
304
+ result: {
305
+ status: "tripwire",
306
+ tripwire: result?.tripwire
307
+ }
308
+ };
268
309
  }
269
- await emitter.emit("watch", {
270
- type: "workflow-step-result",
271
- payload: {
272
- id: step.id,
273
- status: "success",
274
- output: result?.result
310
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
311
+ type: "watch",
312
+ runId: executionContext.runId,
313
+ data: {
314
+ type: "workflow-step-result",
315
+ payload: {
316
+ id: step.id,
317
+ status: "success",
318
+ output: result?.result
319
+ }
275
320
  }
276
321
  });
277
- await emitter.emit("watch", {
278
- type: "workflow-step-finish",
279
- payload: {
280
- id: step.id,
281
- metadata: {}
322
+ await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
323
+ type: "watch",
324
+ runId: executionContext.runId,
325
+ data: {
326
+ type: "workflow-step-finish",
327
+ payload: {
328
+ id: step.id,
329
+ metadata: {}
330
+ }
282
331
  }
283
332
  });
284
333
  return { executionContext, result: { status: "success", output: result?.result } };
@@ -295,6 +344,118 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
295
344
  };
296
345
  }
297
346
  };
347
+ var InngestPubSub = class extends PubSub {
348
+ inngest;
349
+ workflowId;
350
+ publishFn;
351
+ subscriptions = /* @__PURE__ */ new Map();
352
+ constructor(inngest, workflowId, publishFn) {
353
+ super();
354
+ this.inngest = inngest;
355
+ this.workflowId = workflowId;
356
+ this.publishFn = publishFn;
357
+ }
358
+ /**
359
+ * Publish an event to Inngest's realtime system.
360
+ *
361
+ * Topic format: "workflow.events.v2.{runId}"
362
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
363
+ */
364
+ async publish(topic, event) {
365
+ if (!this.publishFn) {
366
+ return;
367
+ }
368
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
369
+ if (!match) {
370
+ return;
371
+ }
372
+ const runId = match[1];
373
+ try {
374
+ await this.publishFn({
375
+ channel: `workflow:${this.workflowId}:${runId}`,
376
+ topic: "watch",
377
+ data: event.data
378
+ });
379
+ } catch (err) {
380
+ console.error("InngestPubSub publish error:", err?.message ?? err);
381
+ }
382
+ }
383
+ /**
384
+ * Subscribe to events from Inngest's realtime system.
385
+ *
386
+ * Topic format: "workflow.events.v2.{runId}"
387
+ * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
388
+ */
389
+ async subscribe(topic, cb) {
390
+ const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
391
+ if (!match || !match[1]) {
392
+ return;
393
+ }
394
+ const runId = match[1];
395
+ if (this.subscriptions.has(topic)) {
396
+ this.subscriptions.get(topic).callbacks.add(cb);
397
+ return;
398
+ }
399
+ const callbacks = /* @__PURE__ */ new Set([cb]);
400
+ const channel = `workflow:${this.workflowId}:${runId}`;
401
+ const streamPromise = subscribe(
402
+ {
403
+ channel,
404
+ topics: ["watch"],
405
+ app: this.inngest
406
+ },
407
+ (message) => {
408
+ const event = {
409
+ id: crypto.randomUUID(),
410
+ type: "watch",
411
+ runId,
412
+ data: message.data,
413
+ createdAt: /* @__PURE__ */ new Date()
414
+ };
415
+ for (const callback of callbacks) {
416
+ callback(event);
417
+ }
418
+ }
419
+ );
420
+ this.subscriptions.set(topic, {
421
+ unsubscribe: () => {
422
+ streamPromise.then((stream) => stream.cancel()).catch((err) => {
423
+ console.error("InngestPubSub unsubscribe error:", err);
424
+ });
425
+ },
426
+ callbacks
427
+ });
428
+ }
429
+ /**
430
+ * Unsubscribe a callback from a topic.
431
+ * If no callbacks remain, the underlying Inngest subscription is cancelled.
432
+ */
433
+ async unsubscribe(topic, cb) {
434
+ const sub = this.subscriptions.get(topic);
435
+ if (!sub) {
436
+ return;
437
+ }
438
+ sub.callbacks.delete(cb);
439
+ if (sub.callbacks.size === 0) {
440
+ sub.unsubscribe();
441
+ this.subscriptions.delete(topic);
442
+ }
443
+ }
444
+ /**
445
+ * Flush any pending operations. No-op for Inngest.
446
+ */
447
+ async flush() {
448
+ }
449
+ /**
450
+ * Clean up all subscriptions during graceful shutdown.
451
+ */
452
+ async close() {
453
+ for (const [, sub] of this.subscriptions) {
454
+ sub.unsubscribe();
455
+ }
456
+ this.subscriptions.clear();
457
+ }
458
+ };
298
459
  var InngestRun = class extends Run {
299
460
  inngest;
300
461
  serializedStepGraph;
@@ -306,27 +467,77 @@ var InngestRun = class extends Run {
306
467
  this.#mastra = params.mastra;
307
468
  }
308
469
  async getRuns(eventId) {
309
- const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
310
- headers: {
311
- Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
470
+ const maxRetries = 3;
471
+ let lastError = null;
472
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
473
+ try {
474
+ const response = await fetch(
475
+ `${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
476
+ {
477
+ headers: {
478
+ Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
479
+ }
480
+ }
481
+ );
482
+ if (response.status === 429) {
483
+ const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
484
+ await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
485
+ continue;
486
+ }
487
+ if (!response.ok) {
488
+ throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
489
+ }
490
+ const text = await response.text();
491
+ if (!text) {
492
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
493
+ continue;
494
+ }
495
+ const json = JSON.parse(text);
496
+ return json.data;
497
+ } catch (error) {
498
+ lastError = error;
499
+ if (attempt < maxRetries - 1) {
500
+ await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
501
+ }
312
502
  }
313
- });
314
- const json = await response.json();
315
- return json.data;
503
+ }
504
+ throw new NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
316
505
  }
317
- async getRunOutput(eventId) {
318
- let runs = await this.getRuns(eventId);
506
+ async getRunOutput(eventId, maxWaitMs = 3e5) {
507
+ const startTime = Date.now();
319
508
  const storage = this.#mastra?.getStorage();
320
- while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
321
- await new Promise((resolve) => setTimeout(resolve, 1e3));
322
- runs = await this.getRuns(eventId);
509
+ while (Date.now() - startTime < maxWaitMs) {
510
+ let runs;
511
+ try {
512
+ runs = await this.getRuns(eventId);
513
+ } catch (error) {
514
+ if (error instanceof NonRetriableError) {
515
+ throw error;
516
+ }
517
+ throw new NonRetriableError(
518
+ `Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
519
+ );
520
+ }
521
+ if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
522
+ return runs[0];
523
+ }
323
524
  if (runs?.[0]?.status === "Failed") {
324
525
  const snapshot = await storage?.loadWorkflowSnapshot({
325
526
  workflowName: this.workflowId,
326
527
  runId: this.runId
327
528
  });
529
+ if (snapshot?.context) {
530
+ snapshot.context = hydrateSerializedStepErrors(snapshot.context);
531
+ }
328
532
  return {
329
- output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
533
+ output: {
534
+ result: {
535
+ steps: snapshot?.context,
536
+ status: "failed",
537
+ // Get the original error from NonRetriableError's cause (which contains the workflow result)
538
+ error: getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
539
+ }
540
+ }
330
541
  };
331
542
  }
332
543
  if (runs?.[0]?.status === "Cancelled") {
@@ -336,8 +547,9 @@ var InngestRun = class extends Run {
336
547
  });
337
548
  return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
338
549
  }
550
+ await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
339
551
  }
340
- return runs?.[0];
552
+ throw new NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
341
553
  }
342
554
  async cancel() {
343
555
  const storage = this.#mastra?.getStorage();
@@ -367,6 +579,51 @@ var InngestRun = class extends Run {
367
579
  async start(params) {
368
580
  return this._start(params);
369
581
  }
582
+ /**
583
+ * Starts the workflow execution without waiting for completion (fire-and-forget).
584
+ * Returns immediately with the runId after sending the event to Inngest.
585
+ * The workflow executes independently in Inngest.
586
+ * Use this when you don't need to wait for the result or want to avoid polling failures.
587
+ */
588
+ async startAsync(params) {
589
+ await this.#mastra.getStorage()?.persistWorkflowSnapshot({
590
+ workflowName: this.workflowId,
591
+ runId: this.runId,
592
+ resourceId: this.resourceId,
593
+ snapshot: {
594
+ runId: this.runId,
595
+ serializedStepGraph: this.serializedStepGraph,
596
+ status: "running",
597
+ value: {},
598
+ context: {},
599
+ activePaths: [],
600
+ suspendedPaths: {},
601
+ activeStepsPath: {},
602
+ resumeLabels: {},
603
+ waitingPaths: {},
604
+ timestamp: Date.now()
605
+ }
606
+ });
607
+ const inputDataToUse = await this._validateInput(params.inputData);
608
+ const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
609
+ const eventOutput = await this.inngest.send({
610
+ name: `workflow.${this.workflowId}`,
611
+ data: {
612
+ inputData: inputDataToUse,
613
+ initialState: initialStateToUse,
614
+ runId: this.runId,
615
+ resourceId: this.resourceId,
616
+ outputOptions: params.outputOptions,
617
+ tracingOptions: params.tracingOptions,
618
+ requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
619
+ }
620
+ });
621
+ const eventId = eventOutput.ids[0];
622
+ if (!eventId) {
623
+ throw new Error("Event ID is not set");
624
+ }
625
+ return { runId: this.runId };
626
+ }
370
627
  async _start({
371
628
  inputData,
372
629
  initialState,
@@ -414,9 +671,7 @@ var InngestRun = class extends Run {
414
671
  }
415
672
  const runOutput = await this.getRunOutput(eventId);
416
673
  const result = runOutput?.output?.result;
417
- if (result.status === "failed") {
418
- result.error = new Error(result.error);
419
- }
674
+ this.hydrateFailedResult(result);
420
675
  if (result.status !== "suspended") {
421
676
  this.cleanup?.();
422
677
  }
@@ -475,9 +730,7 @@ var InngestRun = class extends Run {
475
730
  }
476
731
  const runOutput = await this.getRunOutput(eventId);
477
732
  const result = runOutput?.output?.result;
478
- if (result.status === "failed") {
479
- result.error = new Error(result.error);
480
- }
733
+ this.hydrateFailedResult(result);
481
734
  return result;
482
735
  }
483
736
  async timeTravel(params) {
@@ -567,9 +820,7 @@ var InngestRun = class extends Run {
567
820
  }
568
821
  const runOutput = await this.getRunOutput(eventId);
569
822
  const result = runOutput?.output?.result;
570
- if (result.status === "failed") {
571
- result.error = new Error(result.error);
572
- }
823
+ this.hydrateFailedResult(result);
573
824
  return result;
574
825
  }
575
826
  watch(cb) {
@@ -790,6 +1041,18 @@ var InngestRun = class extends Run {
790
1041
  });
791
1042
  return this.streamOutput;
792
1043
  }
1044
+ /**
1045
+ * Hydrates errors in a failed workflow result back to proper Error instances.
1046
+ * This ensures error.cause chains and custom properties are preserved.
1047
+ */
1048
+ hydrateFailedResult(result) {
1049
+ if (result.status === "failed") {
1050
+ result.error = getErrorFromUnknown(result.error, { serializeStack: false });
1051
+ if (result.steps) {
1052
+ hydrateSerializedStepErrors(result.steps);
1053
+ }
1054
+ }
1055
+ }
793
1056
  };
794
1057
 
795
1058
  // src/workflow.ts
@@ -827,6 +1090,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
827
1090
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
828
1091
  }
829
1092
  __registerMastra(mastra) {
1093
+ super.__registerMastra(mastra);
830
1094
  this.#mastra = mastra;
831
1095
  this.executionEngine.__registerMastra(mastra);
832
1096
  const updateNested = (step) => {
@@ -913,28 +1177,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
913
1177
  return randomUUID();
914
1178
  });
915
1179
  }
916
- const emitter = {
917
- emit: async (event2, data) => {
918
- if (!publish) {
919
- return;
920
- }
921
- try {
922
- await publish({
923
- channel: `workflow:${this.id}:${runId}`,
924
- topic: event2,
925
- data
926
- });
927
- } catch (err) {
928
- this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
929
- }
930
- },
931
- on: (_event, _callback) => {
932
- },
933
- off: (_event, _callback) => {
934
- },
935
- once: (_event, _callback) => {
936
- }
937
- };
1180
+ const pubsub = new InngestPubSub(this.inngest, this.id, publish);
938
1181
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
939
1182
  const result = await engine.execute({
940
1183
  workflowId: this.id,
@@ -944,7 +1187,7 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
944
1187
  serializedStepGraph: this.serializedStepGraph,
945
1188
  input: inputData,
946
1189
  initialState,
947
- emitter,
1190
+ pubsub,
948
1191
  retryConfig: this.retryConfig,
949
1192
  requestContext: new RequestContext(Object.entries(event.data.requestContext ?? {})),
950
1193
  resume,
@@ -953,12 +1196,17 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
953
1196
  abortController: new AbortController(),
954
1197
  // currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
955
1198
  outputOptions,
956
- writableStream: new WritableStream({
957
- write(chunk) {
958
- void emitter.emit("watch", chunk).catch(() => {
1199
+ outputWriter: async (chunk) => {
1200
+ try {
1201
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1202
+ type: "watch",
1203
+ runId,
1204
+ data: chunk
959
1205
  });
1206
+ } catch (err) {
1207
+ this.logger.debug?.("Failed to publish watch event:", err);
960
1208
  }
961
- })
1209
+ }
962
1210
  });
963
1211
  await step.run(`workflow.${this.id}.finalize`, async () => {
964
1212
  if (result.status === "failed") {
@@ -1033,6 +1281,7 @@ function createStep(params, agentOptions) {
1033
1281
  return params;
1034
1282
  }
1035
1283
  if (isAgent(params)) {
1284
+ const outputSchema = agentOptions?.structuredOutput?.schema ?? z.object({ text: z.string() });
1036
1285
  return {
1037
1286
  id: params.name,
1038
1287
  description: params.getDescription(),
@@ -1041,12 +1290,11 @@ function createStep(params, agentOptions) {
1041
1290
  // resourceId: z.string().optional(),
1042
1291
  // threadId: z.string().optional(),
1043
1292
  }),
1044
- outputSchema: z.object({
1045
- text: z.string()
1046
- }),
1293
+ outputSchema,
1047
1294
  execute: async ({
1048
1295
  inputData,
1049
- [EMITTER_SYMBOL]: emitter,
1296
+ runId,
1297
+ [PUBSUB_SYMBOL]: pubsub,
1050
1298
  [STREAM_FORMAT_SYMBOL]: streamFormat,
1051
1299
  requestContext,
1052
1300
  tracingContext,
@@ -1059,6 +1307,7 @@ function createStep(params, agentOptions) {
1059
1307
  streamPromise.resolve = resolve;
1060
1308
  streamPromise.reject = reject;
1061
1309
  });
1310
+ let structuredResult = null;
1062
1311
  const toolData = {
1063
1312
  name: params.name,
1064
1313
  args: inputData
@@ -1072,6 +1321,10 @@ function createStep(params, agentOptions) {
1072
1321
  requestContext,
1073
1322
  tracingContext,
1074
1323
  onFinish: (result) => {
1324
+ const resultWithObject = result;
1325
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1326
+ structuredResult = resultWithObject.object;
1327
+ }
1075
1328
  streamPromise.resolve(result.text);
1076
1329
  void agentOptions?.onFinish?.(result);
1077
1330
  },
@@ -1084,6 +1337,10 @@ function createStep(params, agentOptions) {
1084
1337
  requestContext,
1085
1338
  tracingContext,
1086
1339
  onFinish: (result) => {
1340
+ const resultWithObject = result;
1341
+ if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
1342
+ structuredResult = resultWithObject.object;
1343
+ }
1087
1344
  streamPromise.resolve(result.text);
1088
1345
  void agentOptions?.onFinish?.(result);
1089
1346
  },
@@ -1092,22 +1349,24 @@ function createStep(params, agentOptions) {
1092
1349
  stream = modelOutput.fullStream;
1093
1350
  }
1094
1351
  if (streamFormat === "legacy") {
1095
- await emitter.emit("watch", {
1096
- type: "tool-call-streaming-start",
1097
- ...toolData ?? {}
1352
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1353
+ type: "watch",
1354
+ runId,
1355
+ data: { type: "tool-call-streaming-start", ...toolData ?? {} }
1098
1356
  });
1099
1357
  for await (const chunk of stream) {
1100
1358
  if (chunk.type === "text-delta") {
1101
- await emitter.emit("watch", {
1102
- type: "tool-call-delta",
1103
- ...toolData ?? {},
1104
- argsTextDelta: chunk.textDelta
1359
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1360
+ type: "watch",
1361
+ runId,
1362
+ data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
1105
1363
  });
1106
1364
  }
1107
1365
  }
1108
- await emitter.emit("watch", {
1109
- type: "tool-call-streaming-finish",
1110
- ...toolData ?? {}
1366
+ await pubsub.publish(`workflow.events.v2.${runId}`, {
1367
+ type: "watch",
1368
+ runId,
1369
+ data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
1111
1370
  });
1112
1371
  } else {
1113
1372
  for await (const chunk of stream) {
@@ -1117,6 +1376,9 @@ function createStep(params, agentOptions) {
1117
1376
  if (abortSignal.aborted) {
1118
1377
  return abort();
1119
1378
  }
1379
+ if (structuredResult !== null) {
1380
+ return structuredResult;
1381
+ }
1120
1382
  return {
1121
1383
  text: await streamPromise.promise
1122
1384
  };
@@ -1216,6 +1478,6 @@ function init(inngest) {
1216
1478
  };
1217
1479
  }
1218
1480
 
1219
- export { InngestExecutionEngine, InngestRun, InngestWorkflow, _compatibilityCheck, createStep, init, serve };
1481
+ export { InngestExecutionEngine, InngestPubSub, InngestRun, InngestWorkflow, _compatibilityCheck, createStep, init, serve };
1220
1482
  //# sourceMappingURL=index.js.map
1221
1483
  //# sourceMappingURL=index.js.map