@mastra/inngest 0.0.0-course-20250527170450 → 0.0.0-custom-instrumentation-20250708222033

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
@@ -3,20 +3,26 @@
3
3
  var crypto = require('crypto');
4
4
  var realtime = require('@inngest/realtime');
5
5
  var di = require('@mastra/core/di');
6
+ var tools = require('@mastra/core/tools');
6
7
  var workflows = require('@mastra/core/workflows');
7
8
  var _constants = require('@mastra/core/workflows/_constants');
8
9
  var hono = require('inngest/hono');
10
+ var zod = require('zod');
9
11
 
10
12
  // src/index.ts
11
13
  function serve({ mastra, inngest }) {
12
14
  const wfs = mastra.getWorkflows();
13
- const functions = Object.values(wfs).flatMap((wf) => {
14
- if (wf instanceof InngestWorkflow) {
15
- wf.__registerMastra(mastra);
16
- return wf.getFunctions();
17
- }
18
- return [];
19
- });
15
+ const functions = Array.from(
16
+ new Set(
17
+ Object.values(wfs).flatMap((wf) => {
18
+ if (wf instanceof InngestWorkflow) {
19
+ wf.__registerMastra(mastra);
20
+ return wf.getFunctions();
21
+ }
22
+ return [];
23
+ })
24
+ )
25
+ );
20
26
  return hono.serve({
21
27
  client: inngest,
22
28
  functions
@@ -24,14 +30,16 @@ function serve({ mastra, inngest }) {
24
30
  }
25
31
  var InngestRun = class extends workflows.Run {
26
32
  inngest;
33
+ serializedStepGraph;
27
34
  #mastra;
28
35
  constructor(params, inngest) {
29
36
  super(params);
30
37
  this.inngest = inngest;
38
+ this.serializedStepGraph = params.serializedStepGraph;
31
39
  this.#mastra = params.mastra;
32
40
  }
33
41
  async getRuns(eventId) {
34
- const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
42
+ const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
35
43
  headers: {
36
44
  Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
37
45
  }
@@ -41,15 +49,50 @@ var InngestRun = class extends workflows.Run {
41
49
  }
42
50
  async getRunOutput(eventId) {
43
51
  let runs = await this.getRuns(eventId);
44
- while (runs?.[0]?.status !== "Completed") {
52
+ while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
45
53
  await new Promise((resolve) => setTimeout(resolve, 1e3));
46
54
  runs = await this.getRuns(eventId);
47
- if (runs?.[0]?.status === "Failed" || runs?.[0]?.status === "Cancelled") {
55
+ if (runs?.[0]?.status === "Failed") {
56
+ console.log("run", runs?.[0]);
48
57
  throw new Error(`Function run ${runs?.[0]?.status}`);
58
+ } else if (runs?.[0]?.status === "Cancelled") {
59
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
60
+ workflowName: this.workflowId,
61
+ runId: this.runId
62
+ });
63
+ return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
49
64
  }
50
65
  }
51
66
  return runs?.[0];
52
67
  }
68
+ async sendEvent(event, data) {
69
+ await this.inngest.send({
70
+ name: `user-event-${event}`,
71
+ data
72
+ });
73
+ }
74
+ async cancel() {
75
+ await this.inngest.send({
76
+ name: `cancel.workflow.${this.workflowId}`,
77
+ data: {
78
+ runId: this.runId
79
+ }
80
+ });
81
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
82
+ workflowName: this.workflowId,
83
+ runId: this.runId
84
+ });
85
+ if (snapshot) {
86
+ await this.#mastra?.storage?.persistWorkflowSnapshot({
87
+ workflowName: this.workflowId,
88
+ runId: this.runId,
89
+ snapshot: {
90
+ ...snapshot,
91
+ status: "canceled"
92
+ }
93
+ });
94
+ }
95
+ }
53
96
  async start({
54
97
  inputData
55
98
  }) {
@@ -58,11 +101,13 @@ var InngestRun = class extends workflows.Run {
58
101
  runId: this.runId,
59
102
  snapshot: {
60
103
  runId: this.runId,
104
+ serializedStepGraph: this.serializedStepGraph,
61
105
  value: {},
62
106
  context: {},
63
107
  activePaths: [],
64
108
  suspendedPaths: {},
65
- timestamp: Date.now()
109
+ timestamp: Date.now(),
110
+ status: "running"
66
111
  }
67
112
  });
68
113
  const eventOutput = await this.inngest.send({
@@ -81,10 +126,23 @@ var InngestRun = class extends workflows.Run {
81
126
  if (result.status === "failed") {
82
127
  result.error = new Error(result.error);
83
128
  }
84
- this.cleanup?.();
129
+ if (result.status !== "suspended") {
130
+ this.cleanup?.();
131
+ }
85
132
  return result;
86
133
  }
87
134
  async resume(params) {
135
+ const p = this._resume(params).then((result) => {
136
+ if (result.status !== "suspended") {
137
+ this.closeStreamAction?.().catch(() => {
138
+ });
139
+ }
140
+ return result;
141
+ });
142
+ this.executionResults = p;
143
+ return p;
144
+ }
145
+ async _resume(params) {
88
146
  const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
89
147
  (step) => typeof step === "string" ? step : step?.id
90
148
  );
@@ -118,25 +176,60 @@ var InngestRun = class extends workflows.Run {
118
176
  }
119
177
  return result;
120
178
  }
121
- watch(cb) {
179
+ watch(cb, type = "watch") {
180
+ let active = true;
122
181
  const streamPromise = realtime.subscribe(
123
182
  {
124
183
  channel: `workflow:${this.workflowId}:${this.runId}`,
125
- topics: ["watch"],
184
+ topics: [type],
126
185
  app: this.inngest
127
186
  },
128
187
  (message) => {
129
- cb(message.data);
188
+ if (active) {
189
+ cb(message.data);
190
+ }
130
191
  }
131
192
  );
132
193
  return () => {
133
- streamPromise.then((stream) => {
134
- stream.cancel();
194
+ active = false;
195
+ streamPromise.then(async (stream) => {
196
+ return stream.cancel();
135
197
  }).catch((err) => {
136
198
  console.error(err);
137
199
  });
138
200
  };
139
201
  }
202
+ stream({ inputData, runtimeContext } = {}) {
203
+ const { readable, writable } = new TransformStream();
204
+ const writer = writable.getWriter();
205
+ const unwatch = this.watch(async (event) => {
206
+ try {
207
+ await writer.write(event);
208
+ } catch {
209
+ }
210
+ }, "watch-v2");
211
+ this.closeStreamAction = async () => {
212
+ unwatch();
213
+ try {
214
+ await writer.close();
215
+ } catch (err) {
216
+ console.error("Error closing stream:", err);
217
+ } finally {
218
+ writer.releaseLock();
219
+ }
220
+ };
221
+ this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
222
+ if (result.status !== "suspended") {
223
+ this.closeStreamAction?.().catch(() => {
224
+ });
225
+ }
226
+ return result;
227
+ });
228
+ return {
229
+ stream: readable,
230
+ getWorkflowState: () => this.executionResults
231
+ };
232
+ }
140
233
  };
141
234
  var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
142
235
  #mastra;
@@ -159,11 +252,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
159
252
  const storage = this.#mastra?.getStorage();
160
253
  if (!storage) {
161
254
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
162
- return null;
255
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
163
256
  }
164
257
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
165
258
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
166
259
  }
260
+ async getWorkflowRunExecutionResult(runId) {
261
+ const storage = this.#mastra?.getStorage();
262
+ if (!storage) {
263
+ this.logger.debug("Cannot get workflow run execution result. Mastra storage is not initialized");
264
+ return null;
265
+ }
266
+ const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
267
+ if (!run?.snapshot) {
268
+ return null;
269
+ }
270
+ if (typeof run.snapshot === "string") {
271
+ return null;
272
+ }
273
+ return {
274
+ status: run.snapshot.status,
275
+ result: run.snapshot.result,
276
+ error: run.snapshot.error,
277
+ payload: run.snapshot.context?.input,
278
+ steps: run.snapshot.context
279
+ };
280
+ }
167
281
  __registerMastra(mastra) {
168
282
  this.#mastra = mastra;
169
283
  this.executionEngine.__registerMastra(mastra);
@@ -190,6 +304,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
190
304
  runId: runIdToUse,
191
305
  executionEngine: this.executionEngine,
192
306
  executionGraph: this.executionGraph,
307
+ serializedStepGraph: this.serializedStepGraph,
193
308
  mastra: this.#mastra,
194
309
  retryConfig: this.retryConfig,
195
310
  cleanup: () => this.runs.delete(runIdToUse)
@@ -199,13 +314,55 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
199
314
  this.runs.set(runIdToUse, run);
200
315
  return run;
201
316
  }
317
+ async createRunAsync(options) {
318
+ const runIdToUse = options?.runId || crypto.randomUUID();
319
+ const run = this.runs.get(runIdToUse) ?? new InngestRun(
320
+ {
321
+ workflowId: this.id,
322
+ runId: runIdToUse,
323
+ executionEngine: this.executionEngine,
324
+ executionGraph: this.executionGraph,
325
+ serializedStepGraph: this.serializedStepGraph,
326
+ mastra: this.#mastra,
327
+ retryConfig: this.retryConfig,
328
+ cleanup: () => this.runs.delete(runIdToUse)
329
+ },
330
+ this.inngest
331
+ );
332
+ this.runs.set(runIdToUse, run);
333
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
334
+ if (!workflowSnapshotInStorage) {
335
+ await this.mastra?.getStorage()?.persistWorkflowSnapshot({
336
+ workflowName: this.id,
337
+ runId: runIdToUse,
338
+ snapshot: {
339
+ runId: runIdToUse,
340
+ status: "pending",
341
+ value: {},
342
+ context: {},
343
+ activePaths: [],
344
+ serializedStepGraph: this.serializedStepGraph,
345
+ suspendedPaths: {},
346
+ result: void 0,
347
+ error: void 0,
348
+ // @ts-ignore
349
+ timestamp: Date.now()
350
+ }
351
+ });
352
+ }
353
+ return run;
354
+ }
202
355
  getFunction() {
203
356
  if (this.function) {
204
357
  return this.function;
205
358
  }
206
359
  this.function = this.inngest.createFunction(
207
- // @ts-ignore
208
- { id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
360
+ {
361
+ id: `workflow.${this.id}`,
362
+ // @ts-ignore
363
+ retries: this.retryConfig?.attempts ?? 0,
364
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }]
365
+ },
209
366
  { event: `workflow.${this.id}` },
210
367
  async ({ event, step, attempt, publish }) => {
211
368
  let { inputData, runId, resume } = event.data;
@@ -222,12 +379,18 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
222
379
  try {
223
380
  await publish({
224
381
  channel: `workflow:${this.id}:${runId}`,
225
- topic: "watch",
382
+ topic: event2,
226
383
  data
227
384
  });
228
385
  } catch (err) {
229
386
  this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
230
387
  }
388
+ },
389
+ on: (_event, _callback) => {
390
+ },
391
+ off: (_event, _callback) => {
392
+ },
393
+ once: (_event, _callback) => {
231
394
  }
232
395
  };
233
396
  const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
@@ -235,12 +398,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
235
398
  workflowId: this.id,
236
399
  runId,
237
400
  graph: this.executionGraph,
401
+ serializedStepGraph: this.serializedStepGraph,
238
402
  input: inputData,
239
403
  emitter,
240
404
  retryConfig: this.retryConfig,
241
405
  runtimeContext: new di.RuntimeContext(),
242
406
  // TODO
243
- resume
407
+ resume,
408
+ abortController: new AbortController()
244
409
  });
245
410
  return { result, runId };
246
411
  }
@@ -264,29 +429,138 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
264
429
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
265
430
  }
266
431
  };
267
- function cloneWorkflow(workflow, opts) {
268
- const wf = new InngestWorkflow(
269
- {
270
- id: opts.id,
271
- inputSchema: workflow.inputSchema,
272
- outputSchema: workflow.outputSchema,
273
- steps: workflow.stepDefs,
274
- mastra: workflow.mastra
275
- },
276
- workflow.inngest
277
- );
278
- wf.setStepFlow(workflow.stepGraph);
279
- wf.commit();
280
- return wf;
432
+ function isAgent(params) {
433
+ return params?.component === "AGENT";
434
+ }
435
+ function isTool(params) {
436
+ return params instanceof tools.Tool;
437
+ }
438
+ function createStep(params) {
439
+ if (isAgent(params)) {
440
+ return {
441
+ id: params.name,
442
+ // @ts-ignore
443
+ inputSchema: zod.z.object({
444
+ prompt: zod.z.string()
445
+ // resourceId: z.string().optional(),
446
+ // threadId: z.string().optional(),
447
+ }),
448
+ // @ts-ignore
449
+ outputSchema: zod.z.object({
450
+ text: zod.z.string()
451
+ }),
452
+ execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
453
+ let streamPromise = {};
454
+ streamPromise.promise = new Promise((resolve, reject) => {
455
+ streamPromise.resolve = resolve;
456
+ streamPromise.reject = reject;
457
+ });
458
+ const toolData = {
459
+ name: params.name,
460
+ args: inputData
461
+ };
462
+ await emitter.emit("watch-v2", {
463
+ type: "tool-call-streaming-start",
464
+ ...toolData
465
+ });
466
+ const { fullStream } = await params.stream(inputData.prompt, {
467
+ // resourceId: inputData.resourceId,
468
+ // threadId: inputData.threadId,
469
+ runtimeContext,
470
+ onFinish: (result) => {
471
+ streamPromise.resolve(result.text);
472
+ },
473
+ abortSignal
474
+ });
475
+ if (abortSignal.aborted) {
476
+ return abort();
477
+ }
478
+ for await (const chunk of fullStream) {
479
+ switch (chunk.type) {
480
+ case "text-delta":
481
+ await emitter.emit("watch-v2", {
482
+ type: "tool-call-delta",
483
+ ...toolData,
484
+ argsTextDelta: chunk.textDelta
485
+ });
486
+ break;
487
+ case "step-start":
488
+ case "step-finish":
489
+ case "finish":
490
+ break;
491
+ case "tool-call":
492
+ case "tool-result":
493
+ case "tool-call-streaming-start":
494
+ case "tool-call-delta":
495
+ case "source":
496
+ case "file":
497
+ default:
498
+ await emitter.emit("watch-v2", chunk);
499
+ break;
500
+ }
501
+ }
502
+ return {
503
+ text: await streamPromise.promise
504
+ };
505
+ }
506
+ };
507
+ }
508
+ if (isTool(params)) {
509
+ if (!params.inputSchema || !params.outputSchema) {
510
+ throw new Error("Tool must have input and output schemas defined");
511
+ }
512
+ return {
513
+ // TODO: tool probably should have strong id type
514
+ // @ts-ignore
515
+ id: params.id,
516
+ inputSchema: params.inputSchema,
517
+ outputSchema: params.outputSchema,
518
+ execute: async ({ inputData, mastra, runtimeContext }) => {
519
+ return params.execute({
520
+ context: inputData,
521
+ mastra,
522
+ runtimeContext
523
+ });
524
+ }
525
+ };
526
+ }
527
+ return {
528
+ id: params.id,
529
+ description: params.description,
530
+ inputSchema: params.inputSchema,
531
+ outputSchema: params.outputSchema,
532
+ resumeSchema: params.resumeSchema,
533
+ suspendSchema: params.suspendSchema,
534
+ execute: params.execute
535
+ };
281
536
  }
282
537
  function init(inngest) {
283
538
  return {
284
539
  createWorkflow(params) {
285
540
  return new InngestWorkflow(params, inngest);
286
541
  },
287
- createStep: workflows.createStep,
288
- cloneStep: workflows.cloneStep,
289
- cloneWorkflow
542
+ createStep,
543
+ cloneStep(step, opts) {
544
+ return {
545
+ id: opts.id,
546
+ description: step.description,
547
+ inputSchema: step.inputSchema,
548
+ outputSchema: step.outputSchema,
549
+ execute: step.execute
550
+ };
551
+ },
552
+ cloneWorkflow(workflow, opts) {
553
+ const wf = new workflows.Workflow({
554
+ id: opts.id,
555
+ inputSchema: workflow.inputSchema,
556
+ outputSchema: workflow.outputSchema,
557
+ steps: workflow.stepDefs,
558
+ mastra: workflow.mastra
559
+ });
560
+ wf.setStepFlow(workflow.stepGraph);
561
+ wf.commit();
562
+ return wf;
563
+ }
290
564
  };
291
565
  }
292
566
  var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
@@ -297,6 +571,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
297
571
  this.inngestStep = inngestStep;
298
572
  this.inngestAttempts = inngestAttempts;
299
573
  }
574
+ async execute(params) {
575
+ await params.emitter.emit("watch-v2", {
576
+ type: "start",
577
+ payload: { runId: params.runId }
578
+ });
579
+ const result = await super.execute(params);
580
+ await params.emitter.emit("watch-v2", {
581
+ type: "finish",
582
+ payload: { runId: params.runId }
583
+ });
584
+ return result;
585
+ }
300
586
  async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
301
587
  const base = {
302
588
  status: lastOutput.status,
@@ -363,6 +649,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
363
649
  resume,
364
650
  prevOutput,
365
651
  emitter,
652
+ abortController,
366
653
  runtimeContext
367
654
  }) {
368
655
  return super.executeStep({
@@ -374,9 +661,118 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
374
661
  resume,
375
662
  prevOutput,
376
663
  emitter,
664
+ abortController,
377
665
  runtimeContext
378
666
  });
379
667
  }
668
+ // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
669
+ // await this.inngestStep.sleep(id, duration);
670
+ // }
671
+ async executeSleep({
672
+ workflowId,
673
+ runId,
674
+ entry,
675
+ prevOutput,
676
+ stepResults,
677
+ emitter,
678
+ abortController,
679
+ runtimeContext
680
+ }) {
681
+ let { duration, fn } = entry;
682
+ if (fn) {
683
+ duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
684
+ return await fn({
685
+ runId,
686
+ mastra: this.mastra,
687
+ runtimeContext,
688
+ inputData: prevOutput,
689
+ runCount: -1,
690
+ getInitData: () => stepResults?.input,
691
+ getStepResult: (step) => {
692
+ if (!step?.id) {
693
+ return null;
694
+ }
695
+ const result = stepResults[step.id];
696
+ if (result?.status === "success") {
697
+ return result.output;
698
+ }
699
+ return null;
700
+ },
701
+ // TODO: this function shouldn't have suspend probably?
702
+ suspend: async (_suspendPayload) => {
703
+ },
704
+ bail: () => {
705
+ },
706
+ abort: () => {
707
+ abortController?.abort();
708
+ },
709
+ [_constants.EMITTER_SYMBOL]: emitter,
710
+ engine: { step: this.inngestStep },
711
+ abortSignal: abortController?.signal
712
+ });
713
+ });
714
+ }
715
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
716
+ }
717
+ async executeSleepUntil({
718
+ workflowId,
719
+ runId,
720
+ entry,
721
+ prevOutput,
722
+ stepResults,
723
+ emitter,
724
+ abortController,
725
+ runtimeContext
726
+ }) {
727
+ let { date, fn } = entry;
728
+ if (fn) {
729
+ date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
730
+ return await fn({
731
+ runId,
732
+ mastra: this.mastra,
733
+ runtimeContext,
734
+ inputData: prevOutput,
735
+ runCount: -1,
736
+ getInitData: () => stepResults?.input,
737
+ getStepResult: (step) => {
738
+ if (!step?.id) {
739
+ return null;
740
+ }
741
+ const result = stepResults[step.id];
742
+ if (result?.status === "success") {
743
+ return result.output;
744
+ }
745
+ return null;
746
+ },
747
+ // TODO: this function shouldn't have suspend probably?
748
+ suspend: async (_suspendPayload) => {
749
+ },
750
+ bail: () => {
751
+ },
752
+ abort: () => {
753
+ abortController?.abort();
754
+ },
755
+ [_constants.EMITTER_SYMBOL]: emitter,
756
+ engine: { step: this.inngestStep },
757
+ abortSignal: abortController?.signal
758
+ });
759
+ });
760
+ }
761
+ if (!(date instanceof Date)) {
762
+ return;
763
+ }
764
+ await this.inngestStep.sleepUntil(entry.id, date);
765
+ }
766
+ async executeWaitForEvent({ event, timeout }) {
767
+ const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
768
+ event: `user-event-${event}`,
769
+ timeout: timeout ?? 5e3
770
+ });
771
+ if (eventData === null) {
772
+ throw "Timeout waiting for event";
773
+ }
774
+ return eventData?.data;
775
+ }
380
776
  async executeStep({
381
777
  step,
382
778
  stepResults,
@@ -384,11 +780,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
384
780
  resume,
385
781
  prevOutput,
386
782
  emitter,
783
+ abortController,
387
784
  runtimeContext
388
785
  }) {
389
- await this.inngestStep.run(
786
+ const startedAt = await this.inngestStep.run(
390
787
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
391
788
  async () => {
789
+ const startedAt2 = Date.now();
392
790
  await emitter.emit("watch", {
393
791
  type: "watch",
394
792
  payload: {
@@ -410,6 +808,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
410
808
  },
411
809
  eventTimestamp: Date.now()
412
810
  });
811
+ await emitter.emit("watch-v2", {
812
+ type: "step-start",
813
+ payload: {
814
+ id: step.id,
815
+ status: "running",
816
+ payload: prevOutput,
817
+ startedAt: startedAt2
818
+ }
819
+ });
820
+ return startedAt2;
413
821
  }
414
822
  );
415
823
  if (step instanceof InngestWorkflow) {
@@ -470,6 +878,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
470
878
  },
471
879
  eventTimestamp: Date.now()
472
880
  });
881
+ await emitter.emit("watch-v2", {
882
+ type: "step-result",
883
+ payload: {
884
+ id: step.id,
885
+ status: "failed",
886
+ error: result?.error,
887
+ payload: prevOutput
888
+ }
889
+ });
473
890
  return { executionContext, result: { status: "failed", error: result?.error } };
474
891
  } else if (result.status === "suspended") {
475
892
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
@@ -496,6 +913,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
496
913
  },
497
914
  eventTimestamp: Date.now()
498
915
  });
916
+ await emitter.emit("watch-v2", {
917
+ type: "step-suspended",
918
+ payload: {
919
+ id: step.id,
920
+ status: "suspended"
921
+ }
922
+ });
499
923
  return {
500
924
  executionContext,
501
925
  result: {
@@ -546,6 +970,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
546
970
  },
547
971
  eventTimestamp: Date.now()
548
972
  });
973
+ await emitter.emit("watch-v2", {
974
+ type: "step-result",
975
+ payload: {
976
+ id: step.id,
977
+ status: "success",
978
+ output: result?.result
979
+ }
980
+ });
981
+ await emitter.emit("watch-v2", {
982
+ type: "step-finish",
983
+ payload: {
984
+ id: step.id,
985
+ metadata: {}
986
+ }
987
+ });
549
988
  return { executionContext, result: { status: "success", output: result?.result } };
550
989
  }
551
990
  );
@@ -555,8 +994,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
555
994
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
556
995
  let execResults;
557
996
  let suspended;
997
+ let bailed;
558
998
  try {
559
999
  const result = await step.execute({
1000
+ runId: executionContext.runId,
560
1001
  mastra: this.mastra,
561
1002
  runtimeContext,
562
1003
  inputData: prevOutput,
@@ -573,20 +1014,54 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
573
1014
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
574
1015
  suspended = { payload: suspendPayload };
575
1016
  },
1017
+ bail: (result2) => {
1018
+ bailed = { payload: result2 };
1019
+ },
576
1020
  resume: {
577
1021
  steps: resume?.steps?.slice(1) || [],
578
1022
  resumePayload: resume?.resumePayload,
579
1023
  // @ts-ignore
580
1024
  runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
581
1025
  },
582
- emitter
1026
+ [_constants.EMITTER_SYMBOL]: emitter,
1027
+ engine: {
1028
+ step: this.inngestStep
1029
+ },
1030
+ abortSignal: abortController.signal
583
1031
  });
584
- execResults = { status: "success", output: result };
1032
+ const endedAt = Date.now();
1033
+ execResults = {
1034
+ status: "success",
1035
+ output: result,
1036
+ startedAt,
1037
+ endedAt,
1038
+ payload: prevOutput,
1039
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1040
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1041
+ };
585
1042
  } catch (e) {
586
- execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
1043
+ execResults = {
1044
+ status: "failed",
1045
+ payload: prevOutput,
1046
+ error: e instanceof Error ? e.message : String(e),
1047
+ endedAt: Date.now(),
1048
+ startedAt,
1049
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1050
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1051
+ };
587
1052
  }
588
1053
  if (suspended) {
589
- execResults = { status: "suspended", payload: suspended.payload };
1054
+ execResults = {
1055
+ status: "suspended",
1056
+ suspendedPayload: suspended.payload,
1057
+ payload: prevOutput,
1058
+ suspendedAt: Date.now(),
1059
+ startedAt,
1060
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1061
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1062
+ };
1063
+ } else if (bailed) {
1064
+ execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
590
1065
  }
591
1066
  if (execResults.status === "failed") {
592
1067
  if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
@@ -598,18 +1073,41 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
598
1073
  payload: {
599
1074
  currentStep: {
600
1075
  id: step.id,
601
- status: execResults.status,
602
- output: execResults.output
1076
+ ...execResults
603
1077
  },
604
1078
  workflowState: {
605
1079
  status: "running",
606
- steps: stepResults,
1080
+ steps: { ...stepResults, [step.id]: execResults },
607
1081
  result: null,
608
1082
  error: null
609
1083
  }
610
1084
  },
611
1085
  eventTimestamp: Date.now()
612
1086
  });
1087
+ if (execResults.status === "suspended") {
1088
+ await emitter.emit("watch-v2", {
1089
+ type: "step-suspended",
1090
+ payload: {
1091
+ id: step.id,
1092
+ ...execResults
1093
+ }
1094
+ });
1095
+ } else {
1096
+ await emitter.emit("watch-v2", {
1097
+ type: "step-result",
1098
+ payload: {
1099
+ id: step.id,
1100
+ ...execResults
1101
+ }
1102
+ });
1103
+ await emitter.emit("watch-v2", {
1104
+ type: "step-finish",
1105
+ payload: {
1106
+ id: step.id,
1107
+ metadata: {}
1108
+ }
1109
+ });
1110
+ }
613
1111
  return { result: execResults, executionContext, stepResults };
614
1112
  });
615
1113
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
@@ -620,7 +1118,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
620
1118
  workflowId,
621
1119
  runId,
622
1120
  stepResults,
623
- executionContext
1121
+ executionContext,
1122
+ serializedStepGraph,
1123
+ workflowStatus,
1124
+ result,
1125
+ error
624
1126
  }) {
625
1127
  await this.inngestStep.run(
626
1128
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -634,6 +1136,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
634
1136
  context: stepResults,
635
1137
  activePaths: [],
636
1138
  suspendedPaths: executionContext.suspendedPaths,
1139
+ serializedStepGraph,
1140
+ status: workflowStatus,
1141
+ result,
1142
+ error,
637
1143
  // @ts-ignore
638
1144
  timestamp: Date.now()
639
1145
  }
@@ -648,9 +1154,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
648
1154
  prevOutput,
649
1155
  prevStep,
650
1156
  stepResults,
1157
+ serializedStepGraph,
651
1158
  resume,
652
1159
  executionContext,
653
1160
  emitter,
1161
+ abortController,
654
1162
  runtimeContext
655
1163
  }) {
656
1164
  let execResults;
@@ -659,8 +1167,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
659
1167
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
660
1168
  try {
661
1169
  const result = await cond({
1170
+ runId,
662
1171
  mastra: this.mastra,
663
1172
  runtimeContext,
1173
+ runCount: -1,
664
1174
  inputData: prevOutput,
665
1175
  getInitData: () => stepResults?.input,
666
1176
  getStepResult: (step) => {
@@ -676,7 +1186,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
676
1186
  // TODO: this function shouldn't have suspend probably?
677
1187
  suspend: async (_suspendPayload) => {
678
1188
  },
679
- [_constants.EMITTER_SYMBOL]: emitter
1189
+ bail: () => {
1190
+ },
1191
+ abort: () => {
1192
+ abortController.abort();
1193
+ },
1194
+ [_constants.EMITTER_SYMBOL]: emitter,
1195
+ engine: {
1196
+ step: this.inngestStep
1197
+ },
1198
+ abortSignal: abortController.signal
680
1199
  });
681
1200
  return result ? index : null;
682
1201
  } catch (e) {
@@ -695,6 +1214,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
695
1214
  prevStep,
696
1215
  stepResults,
697
1216
  resume,
1217
+ serializedStepGraph,
698
1218
  executionContext: {
699
1219
  workflowId,
700
1220
  runId,
@@ -704,21 +1224,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
704
1224
  executionSpan: executionContext.executionSpan
705
1225
  },
706
1226
  emitter,
1227
+ abortController,
707
1228
  runtimeContext
708
1229
  })
709
1230
  )
710
1231
  );
711
- const hasFailed = results.find((result) => result.status === "failed");
712
- const hasSuspended = results.find((result) => result.status === "suspended");
1232
+ const hasFailed = results.find((result) => result.result.status === "failed");
1233
+ const hasSuspended = results.find((result) => result.result.status === "suspended");
713
1234
  if (hasFailed) {
714
- execResults = { status: "failed", error: hasFailed.error };
1235
+ execResults = { status: "failed", error: hasFailed.result.error };
715
1236
  } else if (hasSuspended) {
716
- execResults = { status: "suspended", payload: hasSuspended.payload };
1237
+ execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
717
1238
  } else {
718
1239
  execResults = {
719
1240
  status: "success",
720
1241
  output: results.reduce((acc, result, index) => {
721
- if (result.status === "success") {
1242
+ if (result.result.status === "success") {
722
1243
  acc[stepsToRun[index].step.id] = result.output;
723
1244
  }
724
1245
  return acc;
@@ -732,5 +1253,6 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
732
1253
  exports.InngestExecutionEngine = InngestExecutionEngine;
733
1254
  exports.InngestRun = InngestRun;
734
1255
  exports.InngestWorkflow = InngestWorkflow;
1256
+ exports.createStep = createStep;
735
1257
  exports.init = init;
736
1258
  exports.serve = serve;