@mastra/inngest 0.0.0-generate-message-id-20250512171942 → 0.0.0-gl-test-20250917080133

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
@@ -2,35 +2,49 @@
2
2
 
3
3
  var crypto = require('crypto');
4
4
  var realtime = require('@inngest/realtime');
5
+ var aiTracing = require('@mastra/core/ai-tracing');
5
6
  var di = require('@mastra/core/di');
6
- var vNext = require('@mastra/core/workflows/vNext');
7
+ var tools = require('@mastra/core/tools');
8
+ var workflows = require('@mastra/core/workflows');
9
+ var _constants = require('@mastra/core/workflows/_constants');
7
10
  var hono = require('inngest/hono');
11
+ var zod = require('zod');
8
12
 
9
13
  // src/index.ts
10
- function serve({ mastra, inngest }) {
11
- const wfs = mastra.vnext_getWorkflows();
12
- const functions = Object.values(wfs).flatMap((wf) => {
13
- if (wf instanceof InngestWorkflow) {
14
- wf.__registerMastra(mastra);
15
- return wf.getFunctions();
16
- }
17
- return [];
18
- });
14
+ function serve({
15
+ mastra,
16
+ inngest,
17
+ functions: userFunctions = []
18
+ }) {
19
+ const wfs = mastra.getWorkflows();
20
+ const workflowFunctions = Array.from(
21
+ new Set(
22
+ Object.values(wfs).flatMap((wf) => {
23
+ if (wf instanceof InngestWorkflow) {
24
+ wf.__registerMastra(mastra);
25
+ return wf.getFunctions();
26
+ }
27
+ return [];
28
+ })
29
+ )
30
+ );
19
31
  return hono.serve({
20
32
  client: inngest,
21
- functions
33
+ functions: [...workflowFunctions, ...userFunctions]
22
34
  });
23
35
  }
24
- var InngestRun = class extends vNext.Run {
36
+ var InngestRun = class extends workflows.Run {
25
37
  inngest;
38
+ serializedStepGraph;
26
39
  #mastra;
27
40
  constructor(params, inngest) {
28
41
  super(params);
29
42
  this.inngest = inngest;
43
+ this.serializedStepGraph = params.serializedStepGraph;
30
44
  this.#mastra = params.mastra;
31
45
  }
32
46
  async getRuns(eventId) {
33
- const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
47
+ const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
34
48
  headers: {
35
49
  Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
36
50
  }
@@ -40,35 +54,75 @@ var InngestRun = class extends vNext.Run {
40
54
  }
41
55
  async getRunOutput(eventId) {
42
56
  let runs = await this.getRuns(eventId);
43
- while (runs?.[0]?.status !== "Completed") {
57
+ while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
44
58
  await new Promise((resolve) => setTimeout(resolve, 1e3));
45
59
  runs = await this.getRuns(eventId);
46
- if (runs?.[0]?.status === "Failed" || runs?.[0]?.status === "Cancelled") {
60
+ if (runs?.[0]?.status === "Failed") {
47
61
  throw new Error(`Function run ${runs?.[0]?.status}`);
62
+ } else if (runs?.[0]?.status === "Cancelled") {
63
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
64
+ workflowName: this.workflowId,
65
+ runId: this.runId
66
+ });
67
+ return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
48
68
  }
49
69
  }
50
70
  return runs?.[0];
51
71
  }
72
+ async sendEvent(event, data) {
73
+ await this.inngest.send({
74
+ name: `user-event-${event}`,
75
+ data
76
+ });
77
+ }
78
+ async cancel() {
79
+ await this.inngest.send({
80
+ name: `cancel.workflow.${this.workflowId}`,
81
+ data: {
82
+ runId: this.runId
83
+ }
84
+ });
85
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
86
+ workflowName: this.workflowId,
87
+ runId: this.runId
88
+ });
89
+ if (snapshot) {
90
+ await this.#mastra?.storage?.persistWorkflowSnapshot({
91
+ workflowName: this.workflowId,
92
+ runId: this.runId,
93
+ resourceId: this.resourceId,
94
+ snapshot: {
95
+ ...snapshot,
96
+ status: "canceled"
97
+ }
98
+ });
99
+ }
100
+ }
52
101
  async start({
53
102
  inputData
54
103
  }) {
55
104
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
56
105
  workflowName: this.workflowId,
57
106
  runId: this.runId,
107
+ resourceId: this.resourceId,
58
108
  snapshot: {
59
109
  runId: this.runId,
110
+ serializedStepGraph: this.serializedStepGraph,
60
111
  value: {},
61
112
  context: {},
62
113
  activePaths: [],
63
114
  suspendedPaths: {},
64
- timestamp: Date.now()
115
+ waitingPaths: {},
116
+ timestamp: Date.now(),
117
+ status: "running"
65
118
  }
66
119
  });
67
120
  const eventOutput = await this.inngest.send({
68
121
  name: `workflow.${this.workflowId}`,
69
122
  data: {
70
123
  inputData,
71
- runId: this.runId
124
+ runId: this.runId,
125
+ resourceId: this.resourceId
72
126
  }
73
127
  });
74
128
  const eventId = eventOutput.ids[0];
@@ -80,10 +134,23 @@ var InngestRun = class extends vNext.Run {
80
134
  if (result.status === "failed") {
81
135
  result.error = new Error(result.error);
82
136
  }
83
- this.cleanup?.();
137
+ if (result.status !== "suspended") {
138
+ this.cleanup?.();
139
+ }
84
140
  return result;
85
141
  }
86
142
  async resume(params) {
143
+ const p = this._resume(params).then((result) => {
144
+ if (result.status !== "suspended") {
145
+ this.closeStreamAction?.().catch(() => {
146
+ });
147
+ }
148
+ return result;
149
+ });
150
+ this.executionResults = p;
151
+ return p;
152
+ }
153
+ async _resume(params) {
87
154
  const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
88
155
  (step) => typeof step === "string" ? step : step?.id
89
156
  );
@@ -96,6 +163,7 @@ var InngestRun = class extends vNext.Run {
96
163
  data: {
97
164
  inputData: params.resumeData,
98
165
  runId: this.runId,
166
+ workflowId: this.workflowId,
99
167
  stepResults: snapshot?.context,
100
168
  resume: {
101
169
  steps,
@@ -117,32 +185,77 @@ var InngestRun = class extends vNext.Run {
117
185
  }
118
186
  return result;
119
187
  }
120
- watch(cb) {
188
+ watch(cb, type = "watch") {
189
+ let active = true;
121
190
  const streamPromise = realtime.subscribe(
122
191
  {
123
192
  channel: `workflow:${this.workflowId}:${this.runId}`,
124
- topics: ["watch"],
193
+ topics: [type],
125
194
  app: this.inngest
126
195
  },
127
196
  (message) => {
128
- cb(message.data);
197
+ if (active) {
198
+ cb(message.data);
199
+ }
129
200
  }
130
201
  );
131
202
  return () => {
132
- streamPromise.then((stream) => {
133
- stream.cancel();
203
+ active = false;
204
+ streamPromise.then(async (stream) => {
205
+ return stream.cancel();
134
206
  }).catch((err) => {
135
207
  console.error(err);
136
208
  });
137
209
  };
138
210
  }
211
+ stream({ inputData, runtimeContext } = {}) {
212
+ const { readable, writable } = new TransformStream();
213
+ const writer = writable.getWriter();
214
+ const unwatch = this.watch(async (event) => {
215
+ try {
216
+ const e = {
217
+ ...event,
218
+ type: event.type.replace("workflow-", "")
219
+ };
220
+ await writer.write(e);
221
+ } catch {
222
+ }
223
+ }, "watch-v2");
224
+ this.closeStreamAction = async () => {
225
+ unwatch();
226
+ try {
227
+ await writer.close();
228
+ } catch (err) {
229
+ console.error("Error closing stream:", err);
230
+ } finally {
231
+ writer.releaseLock();
232
+ }
233
+ };
234
+ this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
235
+ if (result.status !== "suspended") {
236
+ this.closeStreamAction?.().catch(() => {
237
+ });
238
+ }
239
+ return result;
240
+ });
241
+ return {
242
+ stream: readable,
243
+ getWorkflowState: () => this.executionResults
244
+ };
245
+ }
139
246
  };
140
- var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
247
+ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
141
248
  #mastra;
142
249
  inngest;
143
250
  function;
251
+ flowControlConfig;
144
252
  constructor(params, inngest) {
145
- super(params);
253
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
254
+ super(workflowParams);
255
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
256
+ ([_, value]) => value !== void 0
257
+ );
258
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
146
259
  this.#mastra = params.mastra;
147
260
  this.inngest = inngest;
148
261
  }
@@ -158,7 +271,7 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
158
271
  const storage = this.#mastra?.getStorage();
159
272
  if (!storage) {
160
273
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
161
- return null;
274
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
162
275
  }
163
276
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
164
277
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
@@ -181,14 +294,25 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
181
294
  }
182
295
  }
183
296
  }
184
- createRun(options) {
297
+ /**
298
+ * @deprecated Use createRunAsync() instead.
299
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
300
+ */
301
+ createRun(_options) {
302
+ throw new Error(
303
+ "createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
304
+ );
305
+ }
306
+ async createRunAsync(options) {
185
307
  const runIdToUse = options?.runId || crypto.randomUUID();
186
308
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
187
309
  {
188
310
  workflowId: this.id,
189
311
  runId: runIdToUse,
312
+ resourceId: options?.resourceId,
190
313
  executionEngine: this.executionEngine,
191
314
  executionGraph: this.executionGraph,
315
+ serializedStepGraph: this.serializedStepGraph,
192
316
  mastra: this.#mastra,
193
317
  retryConfig: this.retryConfig,
194
318
  cleanup: () => this.runs.delete(runIdToUse)
@@ -196,6 +320,28 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
196
320
  this.inngest
197
321
  );
198
322
  this.runs.set(runIdToUse, run);
323
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
324
+ if (!workflowSnapshotInStorage) {
325
+ await this.mastra?.getStorage()?.persistWorkflowSnapshot({
326
+ workflowName: this.id,
327
+ runId: runIdToUse,
328
+ resourceId: options?.resourceId,
329
+ snapshot: {
330
+ runId: runIdToUse,
331
+ status: "pending",
332
+ value: {},
333
+ context: {},
334
+ activePaths: [],
335
+ waitingPaths: {},
336
+ serializedStepGraph: this.serializedStepGraph,
337
+ suspendedPaths: {},
338
+ result: void 0,
339
+ error: void 0,
340
+ // @ts-ignore
341
+ timestamp: Date.now()
342
+ }
343
+ });
344
+ }
199
345
  return run;
200
346
  }
201
347
  getFunction() {
@@ -203,11 +349,17 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
203
349
  return this.function;
204
350
  }
205
351
  this.function = this.inngest.createFunction(
206
- // @ts-ignore
207
- { id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
352
+ {
353
+ id: `workflow.${this.id}`,
354
+ // @ts-ignore
355
+ retries: this.retryConfig?.attempts ?? 0,
356
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
357
+ // Spread flow control configuration
358
+ ...this.flowControlConfig
359
+ },
208
360
  { event: `workflow.${this.id}` },
209
361
  async ({ event, step, attempt, publish }) => {
210
- let { inputData, runId, resume } = event.data;
362
+ let { inputData, runId, resourceId, resume } = event.data;
211
363
  if (!runId) {
212
364
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
213
365
  return crypto.randomUUID();
@@ -221,25 +373,36 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
221
373
  try {
222
374
  await publish({
223
375
  channel: `workflow:${this.id}:${runId}`,
224
- topic: "watch",
376
+ topic: event2,
225
377
  data
226
378
  });
227
379
  } catch (err) {
228
380
  this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
229
381
  }
382
+ },
383
+ on: (_event, _callback) => {
384
+ },
385
+ off: (_event, _callback) => {
386
+ },
387
+ once: (_event, _callback) => {
230
388
  }
231
389
  };
232
390
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
233
391
  const result = await engine.execute({
234
392
  workflowId: this.id,
235
393
  runId,
394
+ resourceId,
236
395
  graph: this.executionGraph,
396
+ serializedStepGraph: this.serializedStepGraph,
237
397
  input: inputData,
238
398
  emitter,
239
399
  retryConfig: this.retryConfig,
240
400
  runtimeContext: new di.RuntimeContext(),
241
401
  // TODO
242
- resume
402
+ resume,
403
+ abortController: new AbortController(),
404
+ currentSpan: void 0
405
+ // TODO: Pass actual parent AI span from workflow execution context
243
406
  });
244
407
  return { result, runId };
245
408
  }
@@ -263,39 +426,147 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
263
426
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
264
427
  }
265
428
  };
266
- function cloneWorkflow(workflow, opts) {
267
- const wf = new InngestWorkflow(
268
- {
269
- id: opts.id,
270
- inputSchema: workflow.inputSchema,
271
- outputSchema: workflow.outputSchema,
272
- steps: workflow.stepDefs,
273
- mastra: workflow.mastra
274
- },
275
- workflow.inngest
276
- );
277
- wf.setStepFlow(workflow.stepGraph);
278
- wf.commit();
279
- return wf;
429
+ function isAgent(params) {
430
+ return params?.component === "AGENT";
431
+ }
432
+ function isTool(params) {
433
+ return params instanceof tools.Tool;
434
+ }
435
+ function createStep(params) {
436
+ if (isAgent(params)) {
437
+ return {
438
+ id: params.name,
439
+ // @ts-ignore
440
+ inputSchema: zod.z.object({
441
+ prompt: zod.z.string()
442
+ }),
443
+ // @ts-ignore
444
+ outputSchema: zod.z.object({
445
+ text: zod.z.string()
446
+ }),
447
+ execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
448
+ let streamPromise = {};
449
+ streamPromise.promise = new Promise((resolve, reject) => {
450
+ streamPromise.resolve = resolve;
451
+ streamPromise.reject = reject;
452
+ });
453
+ const toolData = {
454
+ name: params.name,
455
+ args: inputData
456
+ };
457
+ const { fullStream } = await params.stream(inputData.prompt, {
458
+ runtimeContext,
459
+ tracingContext,
460
+ onFinish: (result) => {
461
+ streamPromise.resolve(result.text);
462
+ },
463
+ abortSignal
464
+ });
465
+ if (abortSignal.aborted) {
466
+ return abort();
467
+ }
468
+ await emitter.emit("watch-v2", {
469
+ type: "tool-call-streaming-start",
470
+ ...toolData ?? {}
471
+ });
472
+ for await (const chunk of fullStream) {
473
+ if (chunk.type === "text-delta") {
474
+ await emitter.emit("watch-v2", {
475
+ type: "tool-call-delta",
476
+ ...toolData ?? {},
477
+ argsTextDelta: chunk.textDelta
478
+ });
479
+ }
480
+ }
481
+ await emitter.emit("watch-v2", {
482
+ type: "tool-call-streaming-finish",
483
+ ...toolData ?? {}
484
+ });
485
+ return {
486
+ text: await streamPromise.promise
487
+ };
488
+ }
489
+ };
490
+ }
491
+ if (isTool(params)) {
492
+ if (!params.inputSchema || !params.outputSchema) {
493
+ throw new Error("Tool must have input and output schemas defined");
494
+ }
495
+ return {
496
+ // TODO: tool probably should have strong id type
497
+ // @ts-ignore
498
+ id: params.id,
499
+ inputSchema: params.inputSchema,
500
+ outputSchema: params.outputSchema,
501
+ execute: async ({ inputData, mastra, runtimeContext, tracingContext }) => {
502
+ return params.execute({
503
+ context: inputData,
504
+ mastra: aiTracing.wrapMastra(mastra, tracingContext),
505
+ runtimeContext,
506
+ tracingContext
507
+ });
508
+ }
509
+ };
510
+ }
511
+ return {
512
+ id: params.id,
513
+ description: params.description,
514
+ inputSchema: params.inputSchema,
515
+ outputSchema: params.outputSchema,
516
+ resumeSchema: params.resumeSchema,
517
+ suspendSchema: params.suspendSchema,
518
+ execute: params.execute
519
+ };
280
520
  }
281
521
  function init(inngest) {
282
522
  return {
283
523
  createWorkflow(params) {
284
524
  return new InngestWorkflow(params, inngest);
285
525
  },
286
- createStep: vNext.createStep,
287
- cloneStep: vNext.cloneStep,
288
- cloneWorkflow
526
+ createStep,
527
+ cloneStep(step, opts) {
528
+ return {
529
+ id: opts.id,
530
+ description: step.description,
531
+ inputSchema: step.inputSchema,
532
+ outputSchema: step.outputSchema,
533
+ execute: step.execute
534
+ };
535
+ },
536
+ cloneWorkflow(workflow, opts) {
537
+ const wf = new workflows.Workflow({
538
+ id: opts.id,
539
+ inputSchema: workflow.inputSchema,
540
+ outputSchema: workflow.outputSchema,
541
+ steps: workflow.stepDefs,
542
+ mastra: workflow.mastra
543
+ });
544
+ wf.setStepFlow(workflow.stepGraph);
545
+ wf.commit();
546
+ return wf;
547
+ }
289
548
  };
290
549
  }
291
- var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
550
+ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
292
551
  inngestStep;
293
552
  inngestAttempts;
294
- constructor(mastra, inngestStep, inngestAttempts = 0) {
295
- super({ mastra });
553
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
554
+ super({ mastra, options });
296
555
  this.inngestStep = inngestStep;
297
556
  this.inngestAttempts = inngestAttempts;
298
557
  }
558
+ async execute(params) {
559
+ await params.emitter.emit("watch-v2", {
560
+ type: "workflow-start",
561
+ payload: { runId: params.runId }
562
+ });
563
+ const result = await super.execute(params);
564
+ await params.emitter.emit("watch-v2", {
565
+ type: "workflow-finish",
566
+ payload: { runId: params.runId }
567
+ });
568
+ return result;
569
+ }
299
570
  async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
300
571
  const base = {
301
572
  status: lastOutput.status,
@@ -353,28 +624,197 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
353
624
  executionSpan?.end();
354
625
  return base;
355
626
  }
356
- async superExecuteStep({
627
+ // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
628
+ // await this.inngestStep.sleep(id, duration);
629
+ // }
630
+ async executeSleep({
357
631
  workflowId,
358
632
  runId,
359
- step,
633
+ entry,
634
+ prevOutput,
360
635
  stepResults,
636
+ emitter,
637
+ abortController,
638
+ runtimeContext,
361
639
  executionContext,
362
- resume,
640
+ writableStream,
641
+ tracingContext
642
+ }) {
643
+ let { duration, fn } = entry;
644
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
645
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
646
+ name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
647
+ attributes: {
648
+ durationMs: duration,
649
+ sleepType: fn ? "dynamic" : "fixed"
650
+ },
651
+ tracingPolicy: this.options?.tracingPolicy
652
+ });
653
+ if (fn) {
654
+ const stepCallId = crypto.randomUUID();
655
+ duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
656
+ return await fn({
657
+ runId,
658
+ workflowId,
659
+ mastra: this.mastra,
660
+ runtimeContext,
661
+ inputData: prevOutput,
662
+ runCount: -1,
663
+ tracingContext: {
664
+ currentSpan: sleepSpan
665
+ },
666
+ getInitData: () => stepResults?.input,
667
+ getStepResult: (step) => {
668
+ if (!step?.id) {
669
+ return null;
670
+ }
671
+ const result = stepResults[step.id];
672
+ if (result?.status === "success") {
673
+ return result.output;
674
+ }
675
+ return null;
676
+ },
677
+ // TODO: this function shouldn't have suspend probably?
678
+ suspend: async (_suspendPayload) => {
679
+ },
680
+ bail: () => {
681
+ },
682
+ abort: () => {
683
+ abortController?.abort();
684
+ },
685
+ [_constants.EMITTER_SYMBOL]: emitter,
686
+ // TODO: add streamVNext support
687
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
688
+ engine: { step: this.inngestStep },
689
+ abortSignal: abortController?.signal,
690
+ writer: new tools.ToolStream(
691
+ {
692
+ prefix: "workflow-step",
693
+ callId: stepCallId,
694
+ name: "sleep",
695
+ runId
696
+ },
697
+ writableStream
698
+ )
699
+ });
700
+ });
701
+ sleepSpan?.update({
702
+ attributes: {
703
+ durationMs: duration
704
+ }
705
+ });
706
+ }
707
+ try {
708
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
709
+ sleepSpan?.end();
710
+ } catch (e) {
711
+ sleepSpan?.error({ error: e });
712
+ throw e;
713
+ }
714
+ }
715
+ async executeSleepUntil({
716
+ workflowId,
717
+ runId,
718
+ entry,
363
719
  prevOutput,
720
+ stepResults,
364
721
  emitter,
365
- runtimeContext
722
+ abortController,
723
+ runtimeContext,
724
+ executionContext,
725
+ writableStream,
726
+ tracingContext
366
727
  }) {
367
- return super.executeStep({
368
- workflowId,
369
- runId,
370
- step,
371
- stepResults,
372
- executionContext,
373
- resume,
374
- prevOutput,
375
- emitter,
376
- runtimeContext
728
+ let { date, fn } = entry;
729
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
730
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
731
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
732
+ attributes: {
733
+ untilDate: date,
734
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
735
+ sleepType: fn ? "dynamic" : "fixed"
736
+ },
737
+ tracingPolicy: this.options?.tracingPolicy
377
738
  });
739
+ if (fn) {
740
+ date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
741
+ const stepCallId = crypto.randomUUID();
742
+ return await fn({
743
+ runId,
744
+ workflowId,
745
+ mastra: this.mastra,
746
+ runtimeContext,
747
+ inputData: prevOutput,
748
+ runCount: -1,
749
+ tracingContext: {
750
+ currentSpan: sleepUntilSpan
751
+ },
752
+ getInitData: () => stepResults?.input,
753
+ getStepResult: (step) => {
754
+ if (!step?.id) {
755
+ return null;
756
+ }
757
+ const result = stepResults[step.id];
758
+ if (result?.status === "success") {
759
+ return result.output;
760
+ }
761
+ return null;
762
+ },
763
+ // TODO: this function shouldn't have suspend probably?
764
+ suspend: async (_suspendPayload) => {
765
+ },
766
+ bail: () => {
767
+ },
768
+ abort: () => {
769
+ abortController?.abort();
770
+ },
771
+ [_constants.EMITTER_SYMBOL]: emitter,
772
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
773
+ // TODO: add streamVNext support
774
+ engine: { step: this.inngestStep },
775
+ abortSignal: abortController?.signal,
776
+ writer: new tools.ToolStream(
777
+ {
778
+ prefix: "workflow-step",
779
+ callId: stepCallId,
780
+ name: "sleep",
781
+ runId
782
+ },
783
+ writableStream
784
+ )
785
+ });
786
+ });
787
+ if (date && !(date instanceof Date)) {
788
+ date = new Date(date);
789
+ }
790
+ const time = !date ? 0 : date.getTime() - Date.now();
791
+ sleepUntilSpan?.update({
792
+ attributes: {
793
+ durationMs: Math.max(0, time)
794
+ }
795
+ });
796
+ }
797
+ if (!(date instanceof Date)) {
798
+ sleepUntilSpan?.end();
799
+ return;
800
+ }
801
+ try {
802
+ await this.inngestStep.sleepUntil(entry.id, date);
803
+ sleepUntilSpan?.end();
804
+ } catch (e) {
805
+ sleepUntilSpan?.error({ error: e });
806
+ throw e;
807
+ }
808
+ }
809
+ async executeWaitForEvent({ event, timeout }) {
810
+ const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
811
+ event: `user-event-${event}`,
812
+ timeout: timeout ?? 5e3
813
+ });
814
+ if (eventData === null) {
815
+ throw "Timeout waiting for event";
816
+ }
817
+ return eventData?.data;
378
818
  }
379
819
  async executeStep({
380
820
  step,
@@ -383,11 +823,25 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
383
823
  resume,
384
824
  prevOutput,
385
825
  emitter,
386
- runtimeContext
826
+ abortController,
827
+ runtimeContext,
828
+ tracingContext,
829
+ writableStream,
830
+ disableScorers
387
831
  }) {
388
- await this.inngestStep.run(
832
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
833
+ name: `workflow step: '${step.id}'`,
834
+ type: aiTracing.AISpanType.WORKFLOW_STEP,
835
+ input: prevOutput,
836
+ attributes: {
837
+ stepId: step.id
838
+ },
839
+ tracingPolicy: this.options?.tracingPolicy
840
+ });
841
+ const startedAt = await this.inngestStep.run(
389
842
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
390
843
  async () => {
844
+ const startedAt2 = Date.now();
391
845
  await emitter.emit("watch", {
392
846
  type: "watch",
393
847
  payload: {
@@ -409,6 +863,16 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
409
863
  },
410
864
  eventTimestamp: Date.now()
411
865
  });
866
+ await emitter.emit("watch-v2", {
867
+ type: "workflow-step-start",
868
+ payload: {
869
+ id: step.id,
870
+ status: "running",
871
+ payload: prevOutput,
872
+ startedAt: startedAt2
873
+ }
874
+ });
875
+ return startedAt2;
412
876
  }
413
877
  );
414
878
  if (step instanceof InngestWorkflow) {
@@ -469,6 +933,15 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
469
933
  },
470
934
  eventTimestamp: Date.now()
471
935
  });
936
+ await emitter.emit("watch-v2", {
937
+ type: "workflow-step-result",
938
+ payload: {
939
+ id: step.id,
940
+ status: "failed",
941
+ error: result?.error,
942
+ payload: prevOutput
943
+ }
944
+ });
472
945
  return { executionContext, result: { status: "failed", error: result?.error } };
473
946
  } else if (result.status === "suspended") {
474
947
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
@@ -495,6 +968,13 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
495
968
  },
496
969
  eventTimestamp: Date.now()
497
970
  });
971
+ await emitter.emit("watch-v2", {
972
+ type: "workflow-step-suspended",
973
+ payload: {
974
+ id: step.id,
975
+ status: "suspended"
976
+ }
977
+ });
498
978
  return {
499
979
  executionContext,
500
980
  result: {
@@ -545,6 +1025,21 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
545
1025
  },
546
1026
  eventTimestamp: Date.now()
547
1027
  });
1028
+ await emitter.emit("watch-v2", {
1029
+ type: "workflow-step-result",
1030
+ payload: {
1031
+ id: step.id,
1032
+ status: "success",
1033
+ output: result?.result
1034
+ }
1035
+ });
1036
+ await emitter.emit("watch-v2", {
1037
+ type: "workflow-step-finish",
1038
+ payload: {
1039
+ id: step.id,
1040
+ metadata: {}
1041
+ }
1042
+ });
548
1043
  return { executionContext, result: { status: "success", output: result?.result } };
549
1044
  }
550
1045
  );
@@ -554,12 +1049,18 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
554
1049
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
555
1050
  let execResults;
556
1051
  let suspended;
1052
+ let bailed;
557
1053
  try {
558
1054
  const result = await step.execute({
1055
+ runId: executionContext.runId,
559
1056
  mastra: this.mastra,
560
1057
  runtimeContext,
1058
+ writableStream,
561
1059
  inputData: prevOutput,
562
1060
  resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1061
+ tracingContext: {
1062
+ currentSpan: stepAISpan
1063
+ },
563
1064
  getInitData: () => stepResults?.input,
564
1065
  getStepResult: (step2) => {
565
1066
  const result2 = stepResults[step2.id];
@@ -572,24 +1073,60 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
572
1073
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
573
1074
  suspended = { payload: suspendPayload };
574
1075
  },
1076
+ bail: (result2) => {
1077
+ bailed = { payload: result2 };
1078
+ },
575
1079
  resume: {
576
1080
  steps: resume?.steps?.slice(1) || [],
577
1081
  resumePayload: resume?.resumePayload,
578
1082
  // @ts-ignore
579
1083
  runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
580
1084
  },
581
- emitter
1085
+ [_constants.EMITTER_SYMBOL]: emitter,
1086
+ engine: {
1087
+ step: this.inngestStep
1088
+ },
1089
+ abortSignal: abortController.signal
582
1090
  });
583
- execResults = { status: "success", output: result };
1091
+ const endedAt = Date.now();
1092
+ execResults = {
1093
+ status: "success",
1094
+ output: result,
1095
+ startedAt,
1096
+ endedAt,
1097
+ payload: prevOutput,
1098
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1099
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1100
+ };
584
1101
  } catch (e) {
585
- execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
1102
+ execResults = {
1103
+ status: "failed",
1104
+ payload: prevOutput,
1105
+ error: e instanceof Error ? e.message : String(e),
1106
+ endedAt: Date.now(),
1107
+ startedAt,
1108
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1109
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1110
+ };
586
1111
  }
587
1112
  if (suspended) {
588
- execResults = { status: "suspended", payload: suspended.payload };
1113
+ execResults = {
1114
+ status: "suspended",
1115
+ suspendedPayload: suspended.payload,
1116
+ payload: prevOutput,
1117
+ suspendedAt: Date.now(),
1118
+ startedAt,
1119
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1120
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1121
+ };
1122
+ } else if (bailed) {
1123
+ execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
589
1124
  }
590
1125
  if (execResults.status === "failed") {
591
1126
  if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
592
- throw execResults.error;
1127
+ const error = new Error(execResults.error);
1128
+ stepAISpan?.error({ error });
1129
+ throw error;
593
1130
  }
594
1131
  }
595
1132
  await emitter.emit("watch", {
@@ -597,20 +1134,61 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
597
1134
  payload: {
598
1135
  currentStep: {
599
1136
  id: step.id,
600
- status: execResults.status,
601
- output: execResults.output
1137
+ ...execResults
602
1138
  },
603
1139
  workflowState: {
604
1140
  status: "running",
605
- steps: stepResults,
1141
+ steps: { ...stepResults, [step.id]: execResults },
606
1142
  result: null,
607
1143
  error: null
608
1144
  }
609
1145
  },
610
1146
  eventTimestamp: Date.now()
611
1147
  });
1148
+ if (execResults.status === "suspended") {
1149
+ await emitter.emit("watch-v2", {
1150
+ type: "workflow-step-suspended",
1151
+ payload: {
1152
+ id: step.id,
1153
+ ...execResults
1154
+ }
1155
+ });
1156
+ } else {
1157
+ await emitter.emit("watch-v2", {
1158
+ type: "workflow-step-result",
1159
+ payload: {
1160
+ id: step.id,
1161
+ ...execResults
1162
+ }
1163
+ });
1164
+ await emitter.emit("watch-v2", {
1165
+ type: "workflow-step-finish",
1166
+ payload: {
1167
+ id: step.id,
1168
+ metadata: {}
1169
+ }
1170
+ });
1171
+ }
1172
+ stepAISpan?.end({ output: execResults });
612
1173
  return { result: execResults, executionContext, stepResults };
613
1174
  });
1175
+ if (disableScorers !== false) {
1176
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1177
+ if (step.scorers) {
1178
+ await this.runScorers({
1179
+ scorers: step.scorers,
1180
+ runId: executionContext.runId,
1181
+ input: prevOutput,
1182
+ output: stepRes.result,
1183
+ workflowId: executionContext.workflowId,
1184
+ stepId: step.id,
1185
+ runtimeContext,
1186
+ disableScorers,
1187
+ tracingContext: { currentSpan: stepAISpan }
1188
+ });
1189
+ }
1190
+ });
1191
+ }
614
1192
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
615
1193
  Object.assign(stepResults, stepRes.stepResults);
616
1194
  return stepRes.result;
@@ -619,7 +1197,12 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
619
1197
  workflowId,
620
1198
  runId,
621
1199
  stepResults,
622
- executionContext
1200
+ resourceId,
1201
+ executionContext,
1202
+ serializedStepGraph,
1203
+ workflowStatus,
1204
+ result,
1205
+ error
623
1206
  }) {
624
1207
  await this.inngestStep.run(
625
1208
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -627,12 +1210,18 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
627
1210
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
628
1211
  workflowName: workflowId,
629
1212
  runId,
1213
+ resourceId,
630
1214
  snapshot: {
631
1215
  runId,
632
1216
  value: {},
633
1217
  context: stepResults,
634
1218
  activePaths: [],
635
1219
  suspendedPaths: executionContext.suspendedPaths,
1220
+ waitingPaths: {},
1221
+ serializedStepGraph,
1222
+ status: workflowStatus,
1223
+ result,
1224
+ error,
636
1225
  // @ts-ignore
637
1226
  timestamp: Date.now()
638
1227
  }
@@ -647,20 +1236,49 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
647
1236
  prevOutput,
648
1237
  prevStep,
649
1238
  stepResults,
1239
+ serializedStepGraph,
650
1240
  resume,
651
1241
  executionContext,
652
1242
  emitter,
653
- runtimeContext
1243
+ abortController,
1244
+ runtimeContext,
1245
+ writableStream,
1246
+ disableScorers,
1247
+ tracingContext
654
1248
  }) {
1249
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1250
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
1251
+ name: `conditional: '${entry.conditions.length} conditions'`,
1252
+ input: prevOutput,
1253
+ attributes: {
1254
+ conditionCount: entry.conditions.length
1255
+ },
1256
+ tracingPolicy: this.options?.tracingPolicy
1257
+ });
655
1258
  let execResults;
656
1259
  const truthyIndexes = (await Promise.all(
657
1260
  entry.conditions.map(
658
1261
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1262
+ const evalSpan = conditionalSpan?.createChildSpan({
1263
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1264
+ name: `condition: '${index}'`,
1265
+ input: prevOutput,
1266
+ attributes: {
1267
+ conditionIndex: index
1268
+ },
1269
+ tracingPolicy: this.options?.tracingPolicy
1270
+ });
659
1271
  try {
660
1272
  const result = await cond({
1273
+ runId,
1274
+ workflowId,
661
1275
  mastra: this.mastra,
662
1276
  runtimeContext,
1277
+ runCount: -1,
663
1278
  inputData: prevOutput,
1279
+ tracingContext: {
1280
+ currentSpan: evalSpan
1281
+ },
664
1282
  getInitData: () => stepResults?.input,
665
1283
  getStepResult: (step) => {
666
1284
  if (!step?.id) {
@@ -675,22 +1293,61 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
675
1293
  // TODO: this function shouldn't have suspend probably?
676
1294
  suspend: async (_suspendPayload) => {
677
1295
  },
678
- emitter
1296
+ bail: () => {
1297
+ },
1298
+ abort: () => {
1299
+ abortController.abort();
1300
+ },
1301
+ [_constants.EMITTER_SYMBOL]: emitter,
1302
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1303
+ // TODO: add streamVNext support
1304
+ engine: {
1305
+ step: this.inngestStep
1306
+ },
1307
+ abortSignal: abortController.signal,
1308
+ writer: new tools.ToolStream(
1309
+ {
1310
+ prefix: "workflow-step",
1311
+ callId: crypto.randomUUID(),
1312
+ name: "conditional",
1313
+ runId
1314
+ },
1315
+ writableStream
1316
+ )
1317
+ });
1318
+ evalSpan?.end({
1319
+ output: result,
1320
+ attributes: {
1321
+ result: !!result
1322
+ }
679
1323
  });
680
1324
  return result ? index : null;
681
1325
  } catch (e) {
1326
+ evalSpan?.error({
1327
+ error: e instanceof Error ? e : new Error(String(e)),
1328
+ attributes: {
1329
+ result: false
1330
+ }
1331
+ });
682
1332
  return null;
683
1333
  }
684
1334
  })
685
1335
  )
686
1336
  )).filter((index) => index !== null);
687
1337
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1338
+ conditionalSpan?.update({
1339
+ attributes: {
1340
+ truthyIndexes,
1341
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1342
+ }
1343
+ });
688
1344
  const results = await Promise.all(
689
1345
  stepsToRun.map(
690
1346
  (step, index) => this.executeEntry({
691
1347
  workflowId,
692
1348
  runId,
693
1349
  entry: step,
1350
+ serializedStepGraph,
694
1351
  prevStep,
695
1352
  stepResults,
696
1353
  resume,
@@ -703,27 +1360,42 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
703
1360
  executionSpan: executionContext.executionSpan
704
1361
  },
705
1362
  emitter,
706
- runtimeContext
1363
+ abortController,
1364
+ runtimeContext,
1365
+ writableStream,
1366
+ disableScorers,
1367
+ tracingContext: {
1368
+ currentSpan: conditionalSpan
1369
+ }
707
1370
  })
708
1371
  )
709
1372
  );
710
- const hasFailed = results.find((result) => result.status === "failed");
711
- const hasSuspended = results.find((result) => result.status === "suspended");
1373
+ const hasFailed = results.find((result) => result.result.status === "failed");
1374
+ const hasSuspended = results.find((result) => result.result.status === "suspended");
712
1375
  if (hasFailed) {
713
- execResults = { status: "failed", error: hasFailed.error };
1376
+ execResults = { status: "failed", error: hasFailed.result.error };
714
1377
  } else if (hasSuspended) {
715
- execResults = { status: "suspended", payload: hasSuspended.payload };
1378
+ execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
716
1379
  } else {
717
1380
  execResults = {
718
1381
  status: "success",
719
1382
  output: results.reduce((acc, result, index) => {
720
- if (result.status === "success") {
1383
+ if (result.result.status === "success") {
721
1384
  acc[stepsToRun[index].step.id] = result.output;
722
1385
  }
723
1386
  return acc;
724
1387
  }, {})
725
1388
  };
726
1389
  }
1390
+ if (execResults.status === "failed") {
1391
+ conditionalSpan?.error({
1392
+ error: new Error(execResults.error)
1393
+ });
1394
+ } else {
1395
+ conditionalSpan?.end({
1396
+ output: execResults.output || execResults
1397
+ });
1398
+ }
727
1399
  return execResults;
728
1400
  }
729
1401
  };
@@ -731,5 +1403,8 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
731
1403
  exports.InngestExecutionEngine = InngestExecutionEngine;
732
1404
  exports.InngestRun = InngestRun;
733
1405
  exports.InngestWorkflow = InngestWorkflow;
1406
+ exports.createStep = createStep;
734
1407
  exports.init = init;
735
1408
  exports.serve = serve;
1409
+ //# sourceMappingURL=index.cjs.map
1410
+ //# sourceMappingURL=index.cjs.map