@mastra/inngest 0.0.0-vector-sources-20250516175436 → 0.0.0-vector-extension-schema-20250922130418

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,179 @@ 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: workflows.getStepResult.bind(this, stepResults),
668
+ // TODO: this function shouldn't have suspend probably?
669
+ suspend: async (_suspendPayload) => {
670
+ },
671
+ bail: () => {
672
+ },
673
+ abort: () => {
674
+ abortController?.abort();
675
+ },
676
+ [_constants.EMITTER_SYMBOL]: emitter,
677
+ // TODO: add streamVNext support
678
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
679
+ engine: { step: this.inngestStep },
680
+ abortSignal: abortController?.signal,
681
+ writer: new tools.ToolStream(
682
+ {
683
+ prefix: "workflow-step",
684
+ callId: stepCallId,
685
+ name: "sleep",
686
+ runId
687
+ },
688
+ writableStream
689
+ )
690
+ });
691
+ });
692
+ sleepSpan?.update({
693
+ attributes: {
694
+ durationMs: duration
695
+ }
696
+ });
697
+ }
698
+ try {
699
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
700
+ sleepSpan?.end();
701
+ } catch (e) {
702
+ sleepSpan?.error({ error: e });
703
+ throw e;
704
+ }
705
+ }
706
+ async executeSleepUntil({
707
+ workflowId,
708
+ runId,
709
+ entry,
363
710
  prevOutput,
711
+ stepResults,
364
712
  emitter,
365
- runtimeContext
713
+ abortController,
714
+ runtimeContext,
715
+ executionContext,
716
+ writableStream,
717
+ tracingContext
366
718
  }) {
367
- return super.executeStep({
368
- workflowId,
369
- runId,
370
- step,
371
- stepResults,
372
- executionContext,
373
- resume,
374
- prevOutput,
375
- emitter,
376
- runtimeContext
719
+ let { date, fn } = entry;
720
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
721
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
722
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
723
+ attributes: {
724
+ untilDate: date,
725
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
726
+ sleepType: fn ? "dynamic" : "fixed"
727
+ },
728
+ tracingPolicy: this.options?.tracingPolicy
377
729
  });
730
+ if (fn) {
731
+ date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
732
+ const stepCallId = crypto.randomUUID();
733
+ return await fn({
734
+ runId,
735
+ workflowId,
736
+ mastra: this.mastra,
737
+ runtimeContext,
738
+ inputData: prevOutput,
739
+ runCount: -1,
740
+ tracingContext: {
741
+ currentSpan: sleepUntilSpan
742
+ },
743
+ getInitData: () => stepResults?.input,
744
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
745
+ // TODO: this function shouldn't have suspend probably?
746
+ suspend: async (_suspendPayload) => {
747
+ },
748
+ bail: () => {
749
+ },
750
+ abort: () => {
751
+ abortController?.abort();
752
+ },
753
+ [_constants.EMITTER_SYMBOL]: emitter,
754
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
755
+ // TODO: add streamVNext support
756
+ engine: { step: this.inngestStep },
757
+ abortSignal: abortController?.signal,
758
+ writer: new tools.ToolStream(
759
+ {
760
+ prefix: "workflow-step",
761
+ callId: stepCallId,
762
+ name: "sleep",
763
+ runId
764
+ },
765
+ writableStream
766
+ )
767
+ });
768
+ });
769
+ if (date && !(date instanceof Date)) {
770
+ date = new Date(date);
771
+ }
772
+ const time = !date ? 0 : date.getTime() - Date.now();
773
+ sleepUntilSpan?.update({
774
+ attributes: {
775
+ durationMs: Math.max(0, time)
776
+ }
777
+ });
778
+ }
779
+ if (!(date instanceof Date)) {
780
+ sleepUntilSpan?.end();
781
+ return;
782
+ }
783
+ try {
784
+ await this.inngestStep.sleepUntil(entry.id, date);
785
+ sleepUntilSpan?.end();
786
+ } catch (e) {
787
+ sleepUntilSpan?.error({ error: e });
788
+ throw e;
789
+ }
790
+ }
791
+ async executeWaitForEvent({ event, timeout }) {
792
+ const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
793
+ event: `user-event-${event}`,
794
+ timeout: timeout ?? 5e3
795
+ });
796
+ if (eventData === null) {
797
+ throw "Timeout waiting for event";
798
+ }
799
+ return eventData?.data;
378
800
  }
379
801
  async executeStep({
380
802
  step,
@@ -383,11 +805,25 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
383
805
  resume,
384
806
  prevOutput,
385
807
  emitter,
386
- runtimeContext
808
+ abortController,
809
+ runtimeContext,
810
+ tracingContext,
811
+ writableStream,
812
+ disableScorers
387
813
  }) {
388
- await this.inngestStep.run(
814
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
815
+ name: `workflow step: '${step.id}'`,
816
+ type: aiTracing.AISpanType.WORKFLOW_STEP,
817
+ input: prevOutput,
818
+ attributes: {
819
+ stepId: step.id
820
+ },
821
+ tracingPolicy: this.options?.tracingPolicy
822
+ });
823
+ const startedAt = await this.inngestStep.run(
389
824
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
390
825
  async () => {
826
+ const startedAt2 = Date.now();
391
827
  await emitter.emit("watch", {
392
828
  type: "watch",
393
829
  payload: {
@@ -409,6 +845,16 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
409
845
  },
410
846
  eventTimestamp: Date.now()
411
847
  });
848
+ await emitter.emit("watch-v2", {
849
+ type: "workflow-step-start",
850
+ payload: {
851
+ id: step.id,
852
+ status: "running",
853
+ payload: prevOutput,
854
+ startedAt: startedAt2
855
+ }
856
+ });
857
+ return startedAt2;
412
858
  }
413
859
  );
414
860
  if (step instanceof InngestWorkflow) {
@@ -469,6 +915,15 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
469
915
  },
470
916
  eventTimestamp: Date.now()
471
917
  });
918
+ await emitter.emit("watch-v2", {
919
+ type: "workflow-step-result",
920
+ payload: {
921
+ id: step.id,
922
+ status: "failed",
923
+ error: result?.error,
924
+ payload: prevOutput
925
+ }
926
+ });
472
927
  return { executionContext, result: { status: "failed", error: result?.error } };
473
928
  } else if (result.status === "suspended") {
474
929
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
@@ -495,6 +950,13 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
495
950
  },
496
951
  eventTimestamp: Date.now()
497
952
  });
953
+ await emitter.emit("watch-v2", {
954
+ type: "workflow-step-suspended",
955
+ payload: {
956
+ id: step.id,
957
+ status: "suspended"
958
+ }
959
+ });
498
960
  return {
499
961
  executionContext,
500
962
  result: {
@@ -545,6 +1007,21 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
545
1007
  },
546
1008
  eventTimestamp: Date.now()
547
1009
  });
1010
+ await emitter.emit("watch-v2", {
1011
+ type: "workflow-step-result",
1012
+ payload: {
1013
+ id: step.id,
1014
+ status: "success",
1015
+ output: result?.result
1016
+ }
1017
+ });
1018
+ await emitter.emit("watch-v2", {
1019
+ type: "workflow-step-finish",
1020
+ payload: {
1021
+ id: step.id,
1022
+ metadata: {}
1023
+ }
1024
+ });
548
1025
  return { executionContext, result: { status: "success", output: result?.result } };
549
1026
  }
550
1027
  );
@@ -554,42 +1031,78 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
554
1031
  const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
555
1032
  let execResults;
556
1033
  let suspended;
1034
+ let bailed;
557
1035
  try {
558
1036
  const result = await step.execute({
1037
+ runId: executionContext.runId,
559
1038
  mastra: this.mastra,
560
1039
  runtimeContext,
1040
+ writableStream,
561
1041
  inputData: prevOutput,
562
1042
  resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
563
- getInitData: () => stepResults?.input,
564
- getStepResult: (step2) => {
565
- const result2 = stepResults[step2.id];
566
- if (result2?.status === "success") {
567
- return result2.output;
568
- }
569
- return null;
1043
+ tracingContext: {
1044
+ currentSpan: stepAISpan
570
1045
  },
1046
+ getInitData: () => stepResults?.input,
1047
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
571
1048
  suspend: async (suspendPayload) => {
572
1049
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
573
1050
  suspended = { payload: suspendPayload };
574
1051
  },
1052
+ bail: (result2) => {
1053
+ bailed = { payload: result2 };
1054
+ },
575
1055
  resume: {
576
1056
  steps: resume?.steps?.slice(1) || [],
577
1057
  resumePayload: resume?.resumePayload,
578
1058
  // @ts-ignore
579
1059
  runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
580
1060
  },
581
- emitter
1061
+ [_constants.EMITTER_SYMBOL]: emitter,
1062
+ engine: {
1063
+ step: this.inngestStep
1064
+ },
1065
+ abortSignal: abortController.signal
582
1066
  });
583
- execResults = { status: "success", output: result };
1067
+ const endedAt = Date.now();
1068
+ execResults = {
1069
+ status: "success",
1070
+ output: result,
1071
+ startedAt,
1072
+ endedAt,
1073
+ payload: prevOutput,
1074
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1075
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1076
+ };
584
1077
  } catch (e) {
585
- execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
1078
+ execResults = {
1079
+ status: "failed",
1080
+ payload: prevOutput,
1081
+ error: e instanceof Error ? e.message : String(e),
1082
+ endedAt: Date.now(),
1083
+ startedAt,
1084
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1085
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1086
+ };
586
1087
  }
587
1088
  if (suspended) {
588
- execResults = { status: "suspended", payload: suspended.payload };
1089
+ execResults = {
1090
+ status: "suspended",
1091
+ suspendedPayload: suspended.payload,
1092
+ payload: prevOutput,
1093
+ suspendedAt: Date.now(),
1094
+ startedAt,
1095
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1096
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1097
+ };
1098
+ } else if (bailed) {
1099
+ execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
589
1100
  }
590
1101
  if (execResults.status === "failed") {
591
1102
  if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
592
- throw execResults.error;
1103
+ const error = new Error(execResults.error);
1104
+ stepAISpan?.error({ error });
1105
+ throw error;
593
1106
  }
594
1107
  }
595
1108
  await emitter.emit("watch", {
@@ -597,20 +1110,61 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
597
1110
  payload: {
598
1111
  currentStep: {
599
1112
  id: step.id,
600
- status: execResults.status,
601
- output: execResults.output
1113
+ ...execResults
602
1114
  },
603
1115
  workflowState: {
604
1116
  status: "running",
605
- steps: stepResults,
1117
+ steps: { ...stepResults, [step.id]: execResults },
606
1118
  result: null,
607
1119
  error: null
608
1120
  }
609
1121
  },
610
1122
  eventTimestamp: Date.now()
611
1123
  });
1124
+ if (execResults.status === "suspended") {
1125
+ await emitter.emit("watch-v2", {
1126
+ type: "workflow-step-suspended",
1127
+ payload: {
1128
+ id: step.id,
1129
+ ...execResults
1130
+ }
1131
+ });
1132
+ } else {
1133
+ await emitter.emit("watch-v2", {
1134
+ type: "workflow-step-result",
1135
+ payload: {
1136
+ id: step.id,
1137
+ ...execResults
1138
+ }
1139
+ });
1140
+ await emitter.emit("watch-v2", {
1141
+ type: "workflow-step-finish",
1142
+ payload: {
1143
+ id: step.id,
1144
+ metadata: {}
1145
+ }
1146
+ });
1147
+ }
1148
+ stepAISpan?.end({ output: execResults });
612
1149
  return { result: execResults, executionContext, stepResults };
613
1150
  });
1151
+ if (disableScorers !== false) {
1152
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1153
+ if (step.scorers) {
1154
+ await this.runScorers({
1155
+ scorers: step.scorers,
1156
+ runId: executionContext.runId,
1157
+ input: prevOutput,
1158
+ output: stepRes.result,
1159
+ workflowId: executionContext.workflowId,
1160
+ stepId: step.id,
1161
+ runtimeContext,
1162
+ disableScorers,
1163
+ tracingContext: { currentSpan: stepAISpan }
1164
+ });
1165
+ }
1166
+ });
1167
+ }
614
1168
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
615
1169
  Object.assign(stepResults, stepRes.stepResults);
616
1170
  return stepRes.result;
@@ -619,7 +1173,12 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
619
1173
  workflowId,
620
1174
  runId,
621
1175
  stepResults,
622
- executionContext
1176
+ resourceId,
1177
+ executionContext,
1178
+ serializedStepGraph,
1179
+ workflowStatus,
1180
+ result,
1181
+ error
623
1182
  }) {
624
1183
  await this.inngestStep.run(
625
1184
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
@@ -627,12 +1186,18 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
627
1186
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
628
1187
  workflowName: workflowId,
629
1188
  runId,
1189
+ resourceId,
630
1190
  snapshot: {
631
1191
  runId,
632
1192
  value: {},
633
1193
  context: stepResults,
634
1194
  activePaths: [],
635
1195
  suspendedPaths: executionContext.suspendedPaths,
1196
+ waitingPaths: {},
1197
+ serializedStepGraph,
1198
+ status: workflowStatus,
1199
+ result,
1200
+ error,
636
1201
  // @ts-ignore
637
1202
  timestamp: Date.now()
638
1203
  }
@@ -647,50 +1212,109 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
647
1212
  prevOutput,
648
1213
  prevStep,
649
1214
  stepResults,
1215
+ serializedStepGraph,
650
1216
  resume,
651
1217
  executionContext,
652
1218
  emitter,
653
- runtimeContext
1219
+ abortController,
1220
+ runtimeContext,
1221
+ writableStream,
1222
+ disableScorers,
1223
+ tracingContext
654
1224
  }) {
1225
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1226
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
1227
+ name: `conditional: '${entry.conditions.length} conditions'`,
1228
+ input: prevOutput,
1229
+ attributes: {
1230
+ conditionCount: entry.conditions.length
1231
+ },
1232
+ tracingPolicy: this.options?.tracingPolicy
1233
+ });
655
1234
  let execResults;
656
1235
  const truthyIndexes = (await Promise.all(
657
1236
  entry.conditions.map(
658
1237
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1238
+ const evalSpan = conditionalSpan?.createChildSpan({
1239
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1240
+ name: `condition: '${index}'`,
1241
+ input: prevOutput,
1242
+ attributes: {
1243
+ conditionIndex: index
1244
+ },
1245
+ tracingPolicy: this.options?.tracingPolicy
1246
+ });
659
1247
  try {
660
1248
  const result = await cond({
1249
+ runId,
1250
+ workflowId,
661
1251
  mastra: this.mastra,
662
1252
  runtimeContext,
1253
+ runCount: -1,
663
1254
  inputData: prevOutput,
664
- getInitData: () => stepResults?.input,
665
- getStepResult: (step) => {
666
- if (!step?.id) {
667
- return null;
668
- }
669
- const result2 = stepResults[step.id];
670
- if (result2?.status === "success") {
671
- return result2.output;
672
- }
673
- return null;
1255
+ tracingContext: {
1256
+ currentSpan: evalSpan
674
1257
  },
1258
+ getInitData: () => stepResults?.input,
1259
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
675
1260
  // TODO: this function shouldn't have suspend probably?
676
1261
  suspend: async (_suspendPayload) => {
677
1262
  },
678
- emitter
1263
+ bail: () => {
1264
+ },
1265
+ abort: () => {
1266
+ abortController.abort();
1267
+ },
1268
+ [_constants.EMITTER_SYMBOL]: emitter,
1269
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1270
+ // TODO: add streamVNext support
1271
+ engine: {
1272
+ step: this.inngestStep
1273
+ },
1274
+ abortSignal: abortController.signal,
1275
+ writer: new tools.ToolStream(
1276
+ {
1277
+ prefix: "workflow-step",
1278
+ callId: crypto.randomUUID(),
1279
+ name: "conditional",
1280
+ runId
1281
+ },
1282
+ writableStream
1283
+ )
1284
+ });
1285
+ evalSpan?.end({
1286
+ output: result,
1287
+ attributes: {
1288
+ result: !!result
1289
+ }
679
1290
  });
680
1291
  return result ? index : null;
681
1292
  } catch (e) {
1293
+ evalSpan?.error({
1294
+ error: e instanceof Error ? e : new Error(String(e)),
1295
+ attributes: {
1296
+ result: false
1297
+ }
1298
+ });
682
1299
  return null;
683
1300
  }
684
1301
  })
685
1302
  )
686
1303
  )).filter((index) => index !== null);
687
1304
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1305
+ conditionalSpan?.update({
1306
+ attributes: {
1307
+ truthyIndexes,
1308
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1309
+ }
1310
+ });
688
1311
  const results = await Promise.all(
689
1312
  stepsToRun.map(
690
1313
  (step, index) => this.executeEntry({
691
1314
  workflowId,
692
1315
  runId,
693
1316
  entry: step,
1317
+ serializedStepGraph,
694
1318
  prevStep,
695
1319
  stepResults,
696
1320
  resume,
@@ -703,27 +1327,42 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
703
1327
  executionSpan: executionContext.executionSpan
704
1328
  },
705
1329
  emitter,
706
- runtimeContext
1330
+ abortController,
1331
+ runtimeContext,
1332
+ writableStream,
1333
+ disableScorers,
1334
+ tracingContext: {
1335
+ currentSpan: conditionalSpan
1336
+ }
707
1337
  })
708
1338
  )
709
1339
  );
710
- const hasFailed = results.find((result) => result.status === "failed");
711
- const hasSuspended = results.find((result) => result.status === "suspended");
1340
+ const hasFailed = results.find((result) => result.result.status === "failed");
1341
+ const hasSuspended = results.find((result) => result.result.status === "suspended");
712
1342
  if (hasFailed) {
713
- execResults = { status: "failed", error: hasFailed.error };
1343
+ execResults = { status: "failed", error: hasFailed.result.error };
714
1344
  } else if (hasSuspended) {
715
- execResults = { status: "suspended", payload: hasSuspended.payload };
1345
+ execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
716
1346
  } else {
717
1347
  execResults = {
718
1348
  status: "success",
719
1349
  output: results.reduce((acc, result, index) => {
720
- if (result.status === "success") {
1350
+ if (result.result.status === "success") {
721
1351
  acc[stepsToRun[index].step.id] = result.output;
722
1352
  }
723
1353
  return acc;
724
1354
  }, {})
725
1355
  };
726
1356
  }
1357
+ if (execResults.status === "failed") {
1358
+ conditionalSpan?.error({
1359
+ error: new Error(execResults.error)
1360
+ });
1361
+ } else {
1362
+ conditionalSpan?.end({
1363
+ output: execResults.output || execResults
1364
+ });
1365
+ }
727
1366
  return execResults;
728
1367
  }
729
1368
  };
@@ -731,5 +1370,8 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
731
1370
  exports.InngestExecutionEngine = InngestExecutionEngine;
732
1371
  exports.InngestRun = InngestRun;
733
1372
  exports.InngestWorkflow = InngestWorkflow;
1373
+ exports.createStep = createStep;
734
1374
  exports.init = init;
735
1375
  exports.serve = serve;
1376
+ //# sourceMappingURL=index.cjs.map
1377
+ //# sourceMappingURL=index.cjs.map