@mastra/inngest 0.0.0-cloud-transporter-20250513033346 → 0.0.0-consolidate-changesets-20250904042643

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