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