@mastra/inngest 0.0.0-redis-cloud-transporter-20250508203756 → 0.0.0-remove-unused-model-providers-api-20251030210744

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
@@ -1,36 +1,55 @@
1
1
  'use strict';
2
2
 
3
3
  var crypto = require('crypto');
4
+ var web = require('stream/web');
4
5
  var realtime = require('@inngest/realtime');
6
+ var aiTracing = require('@mastra/core/ai-tracing');
5
7
  var di = require('@mastra/core/di');
6
- var vNext = require('@mastra/core/workflows/vNext');
8
+ var stream = require('@mastra/core/stream');
9
+ var tools = require('@mastra/core/tools');
10
+ var workflows = require('@mastra/core/workflows');
11
+ var _constants = require('@mastra/core/workflows/_constants');
12
+ var inngest = require('inngest');
7
13
  var hono = require('inngest/hono');
14
+ var zod = require('zod');
8
15
 
9
16
  // 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
- });
17
+ function serve({
18
+ mastra,
19
+ inngest,
20
+ functions: userFunctions = [],
21
+ registerOptions
22
+ }) {
23
+ const wfs = mastra.listWorkflows();
24
+ const workflowFunctions = Array.from(
25
+ new Set(
26
+ Object.values(wfs).flatMap((wf) => {
27
+ if (wf instanceof InngestWorkflow) {
28
+ wf.__registerMastra(mastra);
29
+ return wf.getFunctions();
30
+ }
31
+ return [];
32
+ })
33
+ )
34
+ );
19
35
  return hono.serve({
36
+ ...registerOptions,
20
37
  client: inngest,
21
- functions
38
+ functions: [...workflowFunctions, ...userFunctions]
22
39
  });
23
40
  }
24
- var InngestRun = class extends vNext.Run {
41
+ var InngestRun = class extends workflows.Run {
25
42
  inngest;
43
+ serializedStepGraph;
26
44
  #mastra;
27
45
  constructor(params, inngest) {
28
46
  super(params);
29
47
  this.inngest = inngest;
48
+ this.serializedStepGraph = params.serializedStepGraph;
30
49
  this.#mastra = params.mastra;
31
50
  }
32
51
  async getRuns(eventId) {
33
- const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
52
+ const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
34
53
  headers: {
35
54
  Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
36
55
  }
@@ -40,35 +59,96 @@ var InngestRun = class extends vNext.Run {
40
59
  }
41
60
  async getRunOutput(eventId) {
42
61
  let runs = await this.getRuns(eventId);
43
- while (runs?.[0]?.status !== "Completed") {
62
+ while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
44
63
  await new Promise((resolve) => setTimeout(resolve, 1e3));
45
64
  runs = await this.getRuns(eventId);
46
- if (runs?.[0]?.status === "Failed" || runs?.[0]?.status === "Cancelled") {
47
- throw new Error(`Function run ${runs?.[0]?.status}`);
65
+ if (runs?.[0]?.status === "Failed") {
66
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
67
+ workflowName: this.workflowId,
68
+ runId: this.runId
69
+ });
70
+ return {
71
+ output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
72
+ };
73
+ }
74
+ if (runs?.[0]?.status === "Cancelled") {
75
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
76
+ workflowName: this.workflowId,
77
+ runId: this.runId
78
+ });
79
+ return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
48
80
  }
49
81
  }
50
82
  return runs?.[0];
51
83
  }
52
- async start({
53
- inputData
84
+ async sendEvent(event, data) {
85
+ await this.inngest.send({
86
+ name: `user-event-${event}`,
87
+ data
88
+ });
89
+ }
90
+ async cancel() {
91
+ await this.inngest.send({
92
+ name: `cancel.workflow.${this.workflowId}`,
93
+ data: {
94
+ runId: this.runId
95
+ }
96
+ });
97
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
98
+ workflowName: this.workflowId,
99
+ runId: this.runId
100
+ });
101
+ if (snapshot) {
102
+ await this.#mastra?.storage?.persistWorkflowSnapshot({
103
+ workflowName: this.workflowId,
104
+ runId: this.runId,
105
+ resourceId: this.resourceId,
106
+ snapshot: {
107
+ ...snapshot,
108
+ status: "canceled"
109
+ }
110
+ });
111
+ }
112
+ }
113
+ async start(params) {
114
+ return this._start(params);
115
+ }
116
+ async _start({
117
+ inputData,
118
+ initialState,
119
+ outputOptions,
120
+ tracingOptions,
121
+ format
54
122
  }) {
55
123
  await this.#mastra.getStorage()?.persistWorkflowSnapshot({
56
124
  workflowName: this.workflowId,
57
125
  runId: this.runId,
126
+ resourceId: this.resourceId,
58
127
  snapshot: {
59
128
  runId: this.runId,
129
+ serializedStepGraph: this.serializedStepGraph,
60
130
  value: {},
61
131
  context: {},
62
132
  activePaths: [],
63
133
  suspendedPaths: {},
64
- timestamp: Date.now()
134
+ resumeLabels: {},
135
+ waitingPaths: {},
136
+ timestamp: Date.now(),
137
+ status: "running"
65
138
  }
66
139
  });
140
+ const inputDataToUse = await this._validateInput(inputData);
141
+ const initialStateToUse = await this._validateInitialState(initialState ?? {});
67
142
  const eventOutput = await this.inngest.send({
68
143
  name: `workflow.${this.workflowId}`,
69
144
  data: {
70
- inputData,
71
- runId: this.runId
145
+ inputData: inputDataToUse,
146
+ initialState: initialStateToUse,
147
+ runId: this.runId,
148
+ resourceId: this.resourceId,
149
+ outputOptions,
150
+ tracingOptions,
151
+ format
72
152
  }
73
153
  });
74
154
  const eventId = eventOutput.ids[0];
@@ -80,10 +160,23 @@ var InngestRun = class extends vNext.Run {
80
160
  if (result.status === "failed") {
81
161
  result.error = new Error(result.error);
82
162
  }
83
- this.cleanup?.();
163
+ if (result.status !== "suspended") {
164
+ this.cleanup?.();
165
+ }
84
166
  return result;
85
167
  }
86
168
  async resume(params) {
169
+ const p = this._resume(params).then((result) => {
170
+ if (result.status !== "suspended") {
171
+ this.closeStreamAction?.().catch(() => {
172
+ });
173
+ }
174
+ return result;
175
+ });
176
+ this.executionResults = p;
177
+ return p;
178
+ }
179
+ async _resume(params) {
87
180
  const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
88
181
  (step) => typeof step === "string" ? step : step?.id
89
182
  );
@@ -91,16 +184,20 @@ var InngestRun = class extends vNext.Run {
91
184
  workflowName: this.workflowId,
92
185
  runId: this.runId
93
186
  });
187
+ const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
188
+ const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
94
189
  const eventOutput = await this.inngest.send({
95
190
  name: `workflow.${this.workflowId}`,
96
191
  data: {
97
- inputData: params.resumeData,
192
+ inputData: resumeDataToUse,
193
+ initialState: snapshot?.value ?? {},
98
194
  runId: this.runId,
195
+ workflowId: this.workflowId,
99
196
  stepResults: snapshot?.context,
100
197
  resume: {
101
198
  steps,
102
199
  stepResults: snapshot?.context,
103
- resumePayload: params.resumeData,
200
+ resumePayload: resumeDataToUse,
104
201
  // @ts-ignore
105
202
  resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
106
203
  }
@@ -117,48 +214,184 @@ var InngestRun = class extends vNext.Run {
117
214
  }
118
215
  return result;
119
216
  }
120
- watch(cb) {
217
+ watch(cb, type = "watch") {
218
+ let active = true;
121
219
  const streamPromise = realtime.subscribe(
122
220
  {
123
221
  channel: `workflow:${this.workflowId}:${this.runId}`,
124
- topics: ["watch"],
222
+ topics: [type],
125
223
  app: this.inngest
126
224
  },
127
225
  (message) => {
128
- cb(message.data);
226
+ if (active) {
227
+ cb(message.data);
228
+ }
129
229
  }
130
230
  );
131
231
  return () => {
132
- streamPromise.then((stream) => {
133
- stream.cancel();
232
+ active = false;
233
+ streamPromise.then(async (stream) => {
234
+ return stream.cancel();
134
235
  }).catch((err) => {
135
236
  console.error(err);
136
237
  });
137
238
  };
138
239
  }
240
+ streamLegacy({ inputData, requestContext } = {}) {
241
+ const { readable, writable } = new TransformStream();
242
+ const writer = writable.getWriter();
243
+ const unwatch = this.watch(async (event) => {
244
+ try {
245
+ await writer.write({
246
+ // @ts-ignore
247
+ type: "start",
248
+ // @ts-ignore
249
+ payload: { runId: this.runId }
250
+ });
251
+ const e = {
252
+ ...event,
253
+ type: event.type.replace("workflow-", "")
254
+ };
255
+ if (e.type === "step-output") {
256
+ e.type = e.payload.output.type;
257
+ e.payload = e.payload.output.payload;
258
+ }
259
+ await writer.write(e);
260
+ } catch {
261
+ }
262
+ }, "watch-v2");
263
+ this.closeStreamAction = async () => {
264
+ await writer.write({
265
+ type: "finish",
266
+ // @ts-ignore
267
+ payload: { runId: this.runId }
268
+ });
269
+ unwatch();
270
+ try {
271
+ await writer.close();
272
+ } catch (err) {
273
+ console.error("Error closing stream:", err);
274
+ } finally {
275
+ writer.releaseLock();
276
+ }
277
+ };
278
+ this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
279
+ if (result.status !== "suspended") {
280
+ this.closeStreamAction?.().catch(() => {
281
+ });
282
+ }
283
+ return result;
284
+ });
285
+ return {
286
+ stream: readable,
287
+ getWorkflowState: () => this.executionResults
288
+ };
289
+ }
290
+ stream({
291
+ inputData,
292
+ requestContext,
293
+ tracingOptions,
294
+ closeOnSuspend = true,
295
+ initialState,
296
+ outputOptions
297
+ } = {}) {
298
+ if (this.closeStreamAction && this.streamOutput) {
299
+ return this.streamOutput;
300
+ }
301
+ this.closeStreamAction = async () => {
302
+ };
303
+ const self = this;
304
+ const stream$1 = new web.ReadableStream({
305
+ async start(controller) {
306
+ const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
307
+ controller.enqueue({
308
+ type,
309
+ runId: self.runId,
310
+ from,
311
+ payload: {
312
+ stepName: payload?.id,
313
+ ...payload
314
+ }
315
+ });
316
+ }, "watch-v2");
317
+ self.closeStreamAction = async () => {
318
+ unwatch();
319
+ try {
320
+ await controller.close();
321
+ } catch (err) {
322
+ console.error("Error closing stream:", err);
323
+ }
324
+ };
325
+ const executionResultsPromise = self._start({
326
+ inputData,
327
+ requestContext,
328
+ // tracingContext, // We are not able to pass a reference to a span here, what to do?
329
+ initialState,
330
+ tracingOptions,
331
+ outputOptions,
332
+ format: "vnext"
333
+ });
334
+ let executionResults;
335
+ try {
336
+ executionResults = await executionResultsPromise;
337
+ if (closeOnSuspend) {
338
+ self.closeStreamAction?.().catch(() => {
339
+ });
340
+ } else if (executionResults.status !== "suspended") {
341
+ self.closeStreamAction?.().catch(() => {
342
+ });
343
+ }
344
+ if (self.streamOutput) {
345
+ self.streamOutput.updateResults(
346
+ executionResults
347
+ );
348
+ }
349
+ } catch (err) {
350
+ self.streamOutput?.rejectResults(err);
351
+ self.closeStreamAction?.().catch(() => {
352
+ });
353
+ }
354
+ }
355
+ });
356
+ this.streamOutput = new stream.WorkflowRunOutput({
357
+ runId: this.runId,
358
+ workflowId: this.workflowId,
359
+ stream: stream$1
360
+ });
361
+ return this.streamOutput;
362
+ }
363
+ streamVNext(args = {}) {
364
+ return this.stream(args);
365
+ }
139
366
  };
140
- var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
367
+ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
141
368
  #mastra;
142
369
  inngest;
143
370
  function;
371
+ flowControlConfig;
144
372
  constructor(params, inngest) {
145
- super(params);
373
+ const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
374
+ super(workflowParams);
375
+ const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
376
+ ([_, value]) => value !== void 0
377
+ );
378
+ this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
146
379
  this.#mastra = params.mastra;
147
380
  this.inngest = inngest;
148
381
  }
149
- async getWorkflowRuns(args) {
382
+ async listWorkflowRuns(args) {
150
383
  const storage = this.#mastra?.getStorage();
151
384
  if (!storage) {
152
385
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
153
386
  return { runs: [], total: 0 };
154
387
  }
155
- return storage.getWorkflowRuns({ workflowName: this.id, ...args ?? {} });
388
+ return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
156
389
  }
157
390
  async getWorkflowRunById(runId) {
158
391
  const storage = this.#mastra?.getStorage();
159
392
  if (!storage) {
160
393
  this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
161
- return null;
394
+ return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
162
395
  }
163
396
  const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
164
397
  return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
@@ -181,21 +414,60 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
181
414
  }
182
415
  }
183
416
  }
184
- createRun(options) {
417
+ /**
418
+ * @deprecated Use createRunAsync() instead.
419
+ * @throws {Error} Always throws an error directing users to use createRunAsync()
420
+ */
421
+ createRun(_options) {
422
+ throw new Error(
423
+ "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."
424
+ );
425
+ }
426
+ async createRunAsync(options) {
185
427
  const runIdToUse = options?.runId || crypto.randomUUID();
186
428
  const run = this.runs.get(runIdToUse) ?? new InngestRun(
187
429
  {
188
430
  workflowId: this.id,
189
431
  runId: runIdToUse,
432
+ resourceId: options?.resourceId,
190
433
  executionEngine: this.executionEngine,
191
434
  executionGraph: this.executionGraph,
435
+ serializedStepGraph: this.serializedStepGraph,
192
436
  mastra: this.#mastra,
193
437
  retryConfig: this.retryConfig,
194
- cleanup: () => this.runs.delete(runIdToUse)
438
+ cleanup: () => this.runs.delete(runIdToUse),
439
+ workflowSteps: this.steps
195
440
  },
196
441
  this.inngest
197
442
  );
198
443
  this.runs.set(runIdToUse, run);
444
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
445
+ workflowStatus: run.workflowRunStatus,
446
+ stepResults: {}
447
+ });
448
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
449
+ if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
450
+ await this.mastra?.getStorage()?.persistWorkflowSnapshot({
451
+ workflowName: this.id,
452
+ runId: runIdToUse,
453
+ resourceId: options?.resourceId,
454
+ snapshot: {
455
+ runId: runIdToUse,
456
+ status: "pending",
457
+ value: {},
458
+ context: {},
459
+ activePaths: [],
460
+ waitingPaths: {},
461
+ serializedStepGraph: this.serializedStepGraph,
462
+ suspendedPaths: {},
463
+ resumeLabels: {},
464
+ result: void 0,
465
+ error: void 0,
466
+ // @ts-ignore
467
+ timestamp: Date.now()
468
+ }
469
+ });
470
+ }
199
471
  return run;
200
472
  }
201
473
  getFunction() {
@@ -203,11 +475,17 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
203
475
  return this.function;
204
476
  }
205
477
  this.function = this.inngest.createFunction(
206
- // @ts-ignore
207
- { id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
478
+ {
479
+ id: `workflow.${this.id}`,
480
+ // @ts-ignore
481
+ retries: this.retryConfig?.attempts ?? 0,
482
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
483
+ // Spread flow control configuration
484
+ ...this.flowControlConfig
485
+ },
208
486
  { event: `workflow.${this.id}` },
209
487
  async ({ event, step, attempt, publish }) => {
210
- let { inputData, runId, resume } = event.data;
488
+ let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
211
489
  if (!runId) {
212
490
  runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
213
491
  return crypto.randomUUID();
@@ -221,25 +499,52 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
221
499
  try {
222
500
  await publish({
223
501
  channel: `workflow:${this.id}:${runId}`,
224
- topic: "watch",
502
+ topic: event2,
225
503
  data
226
504
  });
227
505
  } catch (err) {
228
506
  this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
229
507
  }
508
+ },
509
+ on: (_event, _callback) => {
510
+ },
511
+ off: (_event, _callback) => {
512
+ },
513
+ once: (_event, _callback) => {
230
514
  }
231
515
  };
232
- const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
516
+ const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
233
517
  const result = await engine.execute({
234
518
  workflowId: this.id,
235
519
  runId,
520
+ resourceId,
236
521
  graph: this.executionGraph,
522
+ serializedStepGraph: this.serializedStepGraph,
237
523
  input: inputData,
524
+ initialState,
238
525
  emitter,
239
526
  retryConfig: this.retryConfig,
240
- runtimeContext: new di.RuntimeContext(),
527
+ requestContext: new di.RequestContext(),
241
528
  // TODO
242
- resume
529
+ resume,
530
+ format,
531
+ abortController: new AbortController(),
532
+ // currentSpan: undefined, // TODO: Pass actual parent AI span from workflow execution context
533
+ outputOptions,
534
+ writableStream: new WritableStream({
535
+ write(chunk) {
536
+ void emitter.emit("watch-v2", chunk).catch(() => {
537
+ });
538
+ }
539
+ })
540
+ });
541
+ await step.run(`workflow.${this.id}.finalize`, async () => {
542
+ if (result.status === "failed") {
543
+ throw new inngest.NonRetriableError(`Workflow failed`, {
544
+ cause: result
545
+ });
546
+ }
547
+ return result;
243
548
  });
244
549
  return { result, runId };
245
550
  }
@@ -263,40 +568,186 @@ var InngestWorkflow = class _InngestWorkflow extends vNext.NewWorkflow {
263
568
  return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
264
569
  }
265
570
  };
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;
571
+ function isAgent(params) {
572
+ return params?.component === "AGENT";
573
+ }
574
+ function isTool(params) {
575
+ return params instanceof tools.Tool;
576
+ }
577
+ function createStep(params, agentOptions) {
578
+ if (isAgent(params)) {
579
+ return {
580
+ id: params.name,
581
+ description: params.getDescription(),
582
+ // @ts-ignore
583
+ inputSchema: zod.z.object({
584
+ prompt: zod.z.string()
585
+ // resourceId: z.string().optional(),
586
+ // threadId: z.string().optional(),
587
+ }),
588
+ // @ts-ignore
589
+ outputSchema: zod.z.object({
590
+ text: zod.z.string()
591
+ }),
592
+ execute: async ({
593
+ inputData,
594
+ [_constants.EMITTER_SYMBOL]: emitter,
595
+ [_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
596
+ requestContext,
597
+ tracingContext,
598
+ abortSignal,
599
+ abort,
600
+ writer
601
+ }) => {
602
+ let streamPromise = {};
603
+ streamPromise.promise = new Promise((resolve, reject) => {
604
+ streamPromise.resolve = resolve;
605
+ streamPromise.reject = reject;
606
+ });
607
+ const toolData = {
608
+ name: params.name,
609
+ args: inputData
610
+ };
611
+ let stream;
612
+ if ((await params.getModel()).specificationVersion === "v1") {
613
+ const { fullStream } = await params.streamLegacy(inputData.prompt, {
614
+ ...agentOptions ?? {},
615
+ // resourceId: inputData.resourceId,
616
+ // threadId: inputData.threadId,
617
+ requestContext,
618
+ tracingContext,
619
+ onFinish: (result) => {
620
+ streamPromise.resolve(result.text);
621
+ void agentOptions?.onFinish?.(result);
622
+ },
623
+ abortSignal
624
+ });
625
+ stream = fullStream;
626
+ } else {
627
+ const modelOutput = await params.stream(inputData.prompt, {
628
+ ...agentOptions ?? {},
629
+ requestContext,
630
+ tracingContext,
631
+ onFinish: (result) => {
632
+ streamPromise.resolve(result.text);
633
+ void agentOptions?.onFinish?.(result);
634
+ },
635
+ abortSignal
636
+ });
637
+ stream = modelOutput.fullStream;
638
+ }
639
+ if (streamFormat === "legacy") {
640
+ await emitter.emit("watch-v2", {
641
+ type: "tool-call-streaming-start",
642
+ ...toolData ?? {}
643
+ });
644
+ for await (const chunk of stream) {
645
+ if (chunk.type === "text-delta") {
646
+ await emitter.emit("watch-v2", {
647
+ type: "tool-call-delta",
648
+ ...toolData ?? {},
649
+ argsTextDelta: chunk.textDelta
650
+ });
651
+ }
652
+ }
653
+ await emitter.emit("watch-v2", {
654
+ type: "tool-call-streaming-finish",
655
+ ...toolData ?? {}
656
+ });
657
+ } else {
658
+ for await (const chunk of stream) {
659
+ await writer.write(chunk);
660
+ }
661
+ }
662
+ if (abortSignal.aborted) {
663
+ return abort();
664
+ }
665
+ return {
666
+ text: await streamPromise.promise
667
+ };
668
+ },
669
+ component: params.component
670
+ };
671
+ }
672
+ if (isTool(params)) {
673
+ if (!params.inputSchema || !params.outputSchema) {
674
+ throw new Error("Tool must have input and output schemas defined");
675
+ }
676
+ return {
677
+ // TODO: tool probably should have strong id type
678
+ // @ts-ignore
679
+ id: params.id,
680
+ description: params.description,
681
+ inputSchema: params.inputSchema,
682
+ outputSchema: params.outputSchema,
683
+ execute: async ({ inputData, mastra, requestContext, tracingContext, suspend, resumeData }) => {
684
+ return params.execute({
685
+ context: inputData,
686
+ mastra: aiTracing.wrapMastra(mastra, tracingContext),
687
+ requestContext,
688
+ tracingContext,
689
+ suspend,
690
+ resumeData
691
+ });
692
+ },
693
+ component: "TOOL"
694
+ };
695
+ }
696
+ return {
697
+ id: params.id,
698
+ description: params.description,
699
+ inputSchema: params.inputSchema,
700
+ outputSchema: params.outputSchema,
701
+ resumeSchema: params.resumeSchema,
702
+ suspendSchema: params.suspendSchema,
703
+ execute: params.execute
704
+ };
280
705
  }
281
706
  function init(inngest) {
282
707
  return {
283
708
  createWorkflow(params) {
284
- return new InngestWorkflow(params, inngest);
709
+ return new InngestWorkflow(
710
+ params,
711
+ inngest
712
+ );
713
+ },
714
+ createStep,
715
+ cloneStep(step, opts) {
716
+ return {
717
+ id: opts.id,
718
+ description: step.description,
719
+ inputSchema: step.inputSchema,
720
+ outputSchema: step.outputSchema,
721
+ resumeSchema: step.resumeSchema,
722
+ suspendSchema: step.suspendSchema,
723
+ stateSchema: step.stateSchema,
724
+ execute: step.execute,
725
+ component: step.component
726
+ };
285
727
  },
286
- createStep: vNext.createStep,
287
- cloneStep: vNext.cloneStep,
288
- cloneWorkflow
728
+ cloneWorkflow(workflow, opts) {
729
+ const wf = new workflows.Workflow({
730
+ id: opts.id,
731
+ inputSchema: workflow.inputSchema,
732
+ outputSchema: workflow.outputSchema,
733
+ steps: workflow.stepDefs,
734
+ mastra: workflow.mastra
735
+ });
736
+ wf.setStepFlow(workflow.stepGraph);
737
+ wf.commit();
738
+ return wf;
739
+ }
289
740
  };
290
741
  }
291
- var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
742
+ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
292
743
  inngestStep;
293
744
  inngestAttempts;
294
- constructor(mastra, inngestStep, inngestAttempts = 0) {
295
- super({ mastra });
745
+ constructor(mastra, inngestStep, inngestAttempts = 0, options) {
746
+ super({ mastra, options });
296
747
  this.inngestStep = inngestStep;
297
748
  this.inngestAttempts = inngestAttempts;
298
749
  }
299
- async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
750
+ async fmtReturnValue(emitter, stepResults, lastOutput, error) {
300
751
  const base = {
301
752
  status: lastOutput.status,
302
753
  steps: stepResults
@@ -343,38 +794,214 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
343
794
  });
344
795
  const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
345
796
  if (stepResult?.status === "suspended") {
346
- const nestedPath = stepResult?.payload?.__workflow_meta?.path;
797
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
347
798
  return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
348
799
  }
349
800
  return [];
350
801
  });
351
802
  base.suspended = suspendedStepIds;
352
803
  }
353
- executionSpan?.end();
354
804
  return base;
355
805
  }
356
- async superExecuteStep({
806
+ // async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
807
+ // await this.inngestStep.sleep(id, duration);
808
+ // }
809
+ async executeSleep({
357
810
  workflowId,
358
811
  runId,
359
- step,
812
+ entry,
813
+ prevOutput,
360
814
  stepResults,
815
+ emitter,
816
+ abortController,
817
+ requestContext,
361
818
  executionContext,
362
- resume,
819
+ writableStream,
820
+ tracingContext
821
+ }) {
822
+ let { duration, fn } = entry;
823
+ const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
824
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
825
+ name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
826
+ attributes: {
827
+ durationMs: duration,
828
+ sleepType: fn ? "dynamic" : "fixed"
829
+ },
830
+ tracingPolicy: this.options?.tracingPolicy
831
+ });
832
+ if (fn) {
833
+ const stepCallId = crypto.randomUUID();
834
+ duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
835
+ return await fn(
836
+ workflows.createDeprecationProxy(
837
+ {
838
+ runId,
839
+ workflowId,
840
+ mastra: this.mastra,
841
+ requestContext,
842
+ inputData: prevOutput,
843
+ state: executionContext.state,
844
+ setState: (state) => {
845
+ executionContext.state = state;
846
+ },
847
+ runCount: -1,
848
+ retryCount: -1,
849
+ tracingContext: {
850
+ currentSpan: sleepSpan
851
+ },
852
+ getInitData: () => stepResults?.input,
853
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
854
+ // TODO: this function shouldn't have suspend probably?
855
+ suspend: async (_suspendPayload) => {
856
+ },
857
+ bail: () => {
858
+ },
859
+ abort: () => {
860
+ abortController?.abort();
861
+ },
862
+ [_constants.EMITTER_SYMBOL]: emitter,
863
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
864
+ engine: { step: this.inngestStep },
865
+ abortSignal: abortController?.signal,
866
+ writer: new tools.ToolStream(
867
+ {
868
+ prefix: "workflow-step",
869
+ callId: stepCallId,
870
+ name: "sleep",
871
+ runId
872
+ },
873
+ writableStream
874
+ )
875
+ },
876
+ {
877
+ paramName: "runCount",
878
+ deprecationMessage: workflows.runCountDeprecationMessage,
879
+ logger: this.logger
880
+ }
881
+ )
882
+ );
883
+ });
884
+ sleepSpan?.update({
885
+ attributes: {
886
+ durationMs: duration
887
+ }
888
+ });
889
+ }
890
+ try {
891
+ await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
892
+ sleepSpan?.end();
893
+ } catch (e) {
894
+ sleepSpan?.error({ error: e });
895
+ throw e;
896
+ }
897
+ }
898
+ async executeSleepUntil({
899
+ workflowId,
900
+ runId,
901
+ entry,
363
902
  prevOutput,
903
+ stepResults,
364
904
  emitter,
365
- runtimeContext
905
+ abortController,
906
+ requestContext,
907
+ executionContext,
908
+ writableStream,
909
+ tracingContext
366
910
  }) {
367
- return super.executeStep({
368
- workflowId,
369
- runId,
370
- step,
371
- stepResults,
372
- executionContext,
373
- resume,
374
- prevOutput,
375
- emitter,
376
- runtimeContext
911
+ let { date, fn } = entry;
912
+ const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
913
+ type: aiTracing.AISpanType.WORKFLOW_SLEEP,
914
+ name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
915
+ attributes: {
916
+ untilDate: date,
917
+ durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
918
+ sleepType: fn ? "dynamic" : "fixed"
919
+ },
920
+ tracingPolicy: this.options?.tracingPolicy
921
+ });
922
+ if (fn) {
923
+ date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
924
+ const stepCallId = crypto.randomUUID();
925
+ return await fn(
926
+ workflows.createDeprecationProxy(
927
+ {
928
+ runId,
929
+ workflowId,
930
+ mastra: this.mastra,
931
+ requestContext,
932
+ inputData: prevOutput,
933
+ state: executionContext.state,
934
+ setState: (state) => {
935
+ executionContext.state = state;
936
+ },
937
+ runCount: -1,
938
+ retryCount: -1,
939
+ tracingContext: {
940
+ currentSpan: sleepUntilSpan
941
+ },
942
+ getInitData: () => stepResults?.input,
943
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
944
+ // TODO: this function shouldn't have suspend probably?
945
+ suspend: async (_suspendPayload) => {
946
+ },
947
+ bail: () => {
948
+ },
949
+ abort: () => {
950
+ abortController?.abort();
951
+ },
952
+ [_constants.EMITTER_SYMBOL]: emitter,
953
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
954
+ engine: { step: this.inngestStep },
955
+ abortSignal: abortController?.signal,
956
+ writer: new tools.ToolStream(
957
+ {
958
+ prefix: "workflow-step",
959
+ callId: stepCallId,
960
+ name: "sleep",
961
+ runId
962
+ },
963
+ writableStream
964
+ )
965
+ },
966
+ {
967
+ paramName: "runCount",
968
+ deprecationMessage: workflows.runCountDeprecationMessage,
969
+ logger: this.logger
970
+ }
971
+ )
972
+ );
973
+ });
974
+ if (date && !(date instanceof Date)) {
975
+ date = new Date(date);
976
+ }
977
+ const time = !date ? 0 : date.getTime() - Date.now();
978
+ sleepUntilSpan?.update({
979
+ attributes: {
980
+ durationMs: Math.max(0, time)
981
+ }
982
+ });
983
+ }
984
+ if (!(date instanceof Date)) {
985
+ sleepUntilSpan?.end();
986
+ return;
987
+ }
988
+ try {
989
+ await this.inngestStep.sleepUntil(entry.id, date);
990
+ sleepUntilSpan?.end();
991
+ } catch (e) {
992
+ sleepUntilSpan?.error({ error: e });
993
+ throw e;
994
+ }
995
+ }
996
+ async executeWaitForEvent({ event, timeout }) {
997
+ const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
998
+ event: `user-event-${event}`,
999
+ timeout: timeout ?? 5e3
377
1000
  });
1001
+ if (eventData === null) {
1002
+ throw "Timeout waiting for event";
1003
+ }
1004
+ return eventData?.data;
378
1005
  }
379
1006
  async executeStep({
380
1007
  step,
@@ -383,11 +1010,30 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
383
1010
  resume,
384
1011
  prevOutput,
385
1012
  emitter,
386
- runtimeContext
1013
+ abortController,
1014
+ requestContext,
1015
+ tracingContext,
1016
+ writableStream,
1017
+ disableScorers
387
1018
  }) {
388
- await this.inngestStep.run(
1019
+ const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
1020
+ name: `workflow step: '${step.id}'`,
1021
+ type: aiTracing.AISpanType.WORKFLOW_STEP,
1022
+ input: prevOutput,
1023
+ attributes: {
1024
+ stepId: step.id
1025
+ },
1026
+ tracingPolicy: this.options?.tracingPolicy
1027
+ });
1028
+ const { inputData, validationError } = await workflows.validateStepInput({
1029
+ prevOutput,
1030
+ step,
1031
+ validateInputs: this.options?.validateInputs ?? false
1032
+ });
1033
+ const startedAt = await this.inngestStep.run(
389
1034
  `workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
390
1035
  async () => {
1036
+ const startedAt2 = Date.now();
391
1037
  await emitter.emit("watch", {
392
1038
  type: "watch",
393
1039
  payload: {
@@ -409,44 +1055,76 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
409
1055
  },
410
1056
  eventTimestamp: Date.now()
411
1057
  });
1058
+ await emitter.emit("watch-v2", {
1059
+ type: "workflow-step-start",
1060
+ payload: {
1061
+ id: step.id,
1062
+ status: "running",
1063
+ payload: inputData,
1064
+ startedAt: startedAt2
1065
+ }
1066
+ });
1067
+ return startedAt2;
412
1068
  }
413
1069
  );
414
1070
  if (step instanceof InngestWorkflow) {
415
1071
  const isResume = !!resume?.steps?.length;
416
1072
  let result;
417
1073
  let runId;
418
- if (isResume) {
419
- runId = stepResults[resume?.steps?.[0]]?.payload?.__workflow_meta?.runId ?? crypto.randomUUID();
420
- const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
421
- workflowName: step.id,
422
- runId
423
- });
424
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
425
- function: step.getFunction(),
426
- data: {
427
- inputData: prevOutput,
428
- runId,
429
- resume: {
1074
+ try {
1075
+ if (isResume) {
1076
+ runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
1077
+ const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
1078
+ workflowName: step.id,
1079
+ runId
1080
+ });
1081
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1082
+ function: step.getFunction(),
1083
+ data: {
1084
+ inputData,
1085
+ initialState: executionContext.state ?? snapshot?.value ?? {},
430
1086
  runId,
431
- steps: resume.steps.slice(1),
432
- stepResults: snapshot?.context,
433
- resumePayload: resume.resumePayload,
434
- // @ts-ignore
435
- resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1087
+ resume: {
1088
+ runId,
1089
+ steps: resume.steps.slice(1),
1090
+ stepResults: snapshot?.context,
1091
+ resumePayload: resume.resumePayload,
1092
+ // @ts-ignore
1093
+ resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
1094
+ },
1095
+ outputOptions: { includeState: true }
436
1096
  }
437
- }
438
- });
439
- result = invokeResp.result;
440
- runId = invokeResp.runId;
441
- } else {
442
- const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
443
- function: step.getFunction(),
444
- data: {
445
- inputData: prevOutput
446
- }
447
- });
448
- result = invokeResp.result;
449
- runId = invokeResp.runId;
1097
+ });
1098
+ result = invokeResp.result;
1099
+ runId = invokeResp.runId;
1100
+ executionContext.state = invokeResp.result.state;
1101
+ } else {
1102
+ const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
1103
+ function: step.getFunction(),
1104
+ data: {
1105
+ inputData,
1106
+ initialState: executionContext.state ?? {},
1107
+ outputOptions: { includeState: true }
1108
+ }
1109
+ });
1110
+ result = invokeResp.result;
1111
+ runId = invokeResp.runId;
1112
+ executionContext.state = invokeResp.result.state;
1113
+ }
1114
+ } catch (e) {
1115
+ const errorCause = e?.cause;
1116
+ if (errorCause && typeof errorCause === "object") {
1117
+ result = errorCause;
1118
+ runId = errorCause.runId || crypto.randomUUID();
1119
+ } else {
1120
+ runId = crypto.randomUUID();
1121
+ result = {
1122
+ status: "failed",
1123
+ error: e instanceof Error ? e : new Error(String(e)),
1124
+ steps: {},
1125
+ input: inputData
1126
+ };
1127
+ }
450
1128
  }
451
1129
  const res = await this.inngestStep.run(
452
1130
  `workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
@@ -469,6 +1147,15 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
469
1147
  },
470
1148
  eventTimestamp: Date.now()
471
1149
  });
1150
+ await emitter.emit("watch-v2", {
1151
+ type: "workflow-step-result",
1152
+ payload: {
1153
+ id: step.id,
1154
+ status: "failed",
1155
+ error: result?.error,
1156
+ payload: prevOutput
1157
+ }
1158
+ });
472
1159
  return { executionContext, result: { status: "failed", error: result?.error } };
473
1160
  } else if (result.status === "suspended") {
474
1161
  const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
@@ -476,7 +1163,7 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
476
1163
  return stepRes2?.status === "suspended";
477
1164
  });
478
1165
  for (const [stepName, stepResult] of suspendedSteps) {
479
- const suspendPath = [stepName, ...stepResult?.payload?.__workflow_meta?.path ?? []];
1166
+ const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
480
1167
  executionContext.suspendedPaths[step.id] = executionContext.executionPath;
481
1168
  await emitter.emit("watch", {
482
1169
  type: "watch",
@@ -484,7 +1171,11 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
484
1171
  currentStep: {
485
1172
  id: step.id,
486
1173
  status: "suspended",
487
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1174
+ payload: stepResult.payload,
1175
+ suspendPayload: {
1176
+ ...stepResult?.suspendPayload,
1177
+ __workflow_meta: { runId, path: suspendPath }
1178
+ }
488
1179
  },
489
1180
  workflowState: {
490
1181
  status: "running",
@@ -495,11 +1186,22 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
495
1186
  },
496
1187
  eventTimestamp: Date.now()
497
1188
  });
1189
+ await emitter.emit("watch-v2", {
1190
+ type: "workflow-step-suspended",
1191
+ payload: {
1192
+ id: step.id,
1193
+ status: "suspended"
1194
+ }
1195
+ });
498
1196
  return {
499
1197
  executionContext,
500
1198
  result: {
501
1199
  status: "suspended",
502
- payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
1200
+ payload: stepResult.payload,
1201
+ suspendPayload: {
1202
+ ...stepResult?.suspendPayload,
1203
+ __workflow_meta: { runId, path: suspendPath }
1204
+ }
503
1205
  }
504
1206
  };
505
1207
  }
@@ -545,94 +1247,260 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
545
1247
  },
546
1248
  eventTimestamp: Date.now()
547
1249
  });
1250
+ await emitter.emit("watch-v2", {
1251
+ type: "workflow-step-result",
1252
+ payload: {
1253
+ id: step.id,
1254
+ status: "success",
1255
+ output: result?.result
1256
+ }
1257
+ });
1258
+ await emitter.emit("watch-v2", {
1259
+ type: "workflow-step-finish",
1260
+ payload: {
1261
+ id: step.id,
1262
+ metadata: {}
1263
+ }
1264
+ });
548
1265
  return { executionContext, result: { status: "success", output: result?.result } };
549
1266
  }
550
1267
  );
551
1268
  Object.assign(executionContext, res.executionContext);
552
- return res.result;
1269
+ return {
1270
+ ...res.result,
1271
+ startedAt,
1272
+ endedAt: Date.now(),
1273
+ payload: inputData,
1274
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1275
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1276
+ };
553
1277
  }
554
- const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
555
- let execResults;
556
- let suspended;
557
- try {
558
- const result = await step.execute({
559
- mastra: this.mastra,
560
- runtimeContext,
561
- inputData: prevOutput,
562
- 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;
1278
+ const stepCallId = crypto.randomUUID();
1279
+ let stepRes;
1280
+ try {
1281
+ stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
1282
+ let execResults;
1283
+ let suspended;
1284
+ let bailed;
1285
+ try {
1286
+ if (validationError) {
1287
+ throw validationError;
1288
+ }
1289
+ const result = await step.execute({
1290
+ runId: executionContext.runId,
1291
+ mastra: this.mastra,
1292
+ requestContext,
1293
+ writer: new tools.ToolStream(
1294
+ {
1295
+ prefix: "workflow-step",
1296
+ callId: stepCallId,
1297
+ name: step.id,
1298
+ runId: executionContext.runId
1299
+ },
1300
+ writableStream
1301
+ ),
1302
+ state: executionContext?.state ?? {},
1303
+ setState: (state) => {
1304
+ executionContext.state = state;
1305
+ },
1306
+ inputData,
1307
+ resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
1308
+ tracingContext: {
1309
+ currentSpan: stepAISpan
1310
+ },
1311
+ getInitData: () => stepResults?.input,
1312
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1313
+ suspend: async (suspendPayload, suspendOptions) => {
1314
+ executionContext.suspendedPaths[step.id] = executionContext.executionPath;
1315
+ if (suspendOptions?.resumeLabel) {
1316
+ const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
1317
+ for (const label of resumeLabel) {
1318
+ executionContext.resumeLabels[label] = {
1319
+ stepId: step.id,
1320
+ foreachIndex: executionContext.foreachIndex
1321
+ };
1322
+ }
1323
+ }
1324
+ suspended = { payload: suspendPayload };
1325
+ },
1326
+ bail: (result2) => {
1327
+ bailed = { payload: result2 };
1328
+ },
1329
+ resume: {
1330
+ steps: resume?.steps?.slice(1) || [],
1331
+ resumePayload: resume?.resumePayload,
1332
+ // @ts-ignore
1333
+ runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
1334
+ },
1335
+ [_constants.EMITTER_SYMBOL]: emitter,
1336
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1337
+ engine: {
1338
+ step: this.inngestStep
1339
+ },
1340
+ abortSignal: abortController.signal
1341
+ });
1342
+ const endedAt = Date.now();
1343
+ execResults = {
1344
+ status: "success",
1345
+ output: result,
1346
+ startedAt,
1347
+ endedAt,
1348
+ payload: inputData,
1349
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1350
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1351
+ };
1352
+ } catch (e) {
1353
+ const stepFailure = {
1354
+ status: "failed",
1355
+ payload: inputData,
1356
+ error: e instanceof Error ? e.message : String(e),
1357
+ endedAt: Date.now(),
1358
+ startedAt,
1359
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1360
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1361
+ };
1362
+ execResults = stepFailure;
1363
+ const fallbackErrorMessage = `Step ${step.id} failed`;
1364
+ stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
1365
+ throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
1366
+ cause: execResults
1367
+ });
1368
+ }
1369
+ if (suspended) {
1370
+ execResults = {
1371
+ status: "suspended",
1372
+ suspendPayload: suspended.payload,
1373
+ payload: inputData,
1374
+ suspendedAt: Date.now(),
1375
+ startedAt,
1376
+ resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
1377
+ resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
1378
+ };
1379
+ } else if (bailed) {
1380
+ execResults = {
1381
+ status: "bailed",
1382
+ output: bailed.payload,
1383
+ payload: inputData,
1384
+ endedAt: Date.now(),
1385
+ startedAt
1386
+ };
1387
+ }
1388
+ await emitter.emit("watch", {
1389
+ type: "watch",
1390
+ payload: {
1391
+ currentStep: {
1392
+ id: step.id,
1393
+ ...execResults
1394
+ },
1395
+ workflowState: {
1396
+ status: "running",
1397
+ steps: { ...stepResults, [step.id]: execResults },
1398
+ result: null,
1399
+ error: null
568
1400
  }
569
- return null;
570
- },
571
- suspend: async (suspendPayload) => {
572
- executionContext.suspendedPaths[step.id] = executionContext.executionPath;
573
- suspended = { payload: suspendPayload };
574
- },
575
- resume: {
576
- steps: resume?.steps?.slice(1) || [],
577
- resumePayload: resume?.resumePayload,
578
- // @ts-ignore
579
- runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
580
1401
  },
581
- emitter
1402
+ eventTimestamp: Date.now()
582
1403
  });
583
- execResults = { status: "success", output: result };
584
- } catch (e) {
585
- execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
586
- }
587
- if (suspended) {
588
- execResults = { status: "suspended", payload: suspended.payload };
589
- }
590
- if (execResults.status === "failed") {
591
- if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
592
- throw execResults.error;
1404
+ if (execResults.status === "suspended") {
1405
+ await emitter.emit("watch-v2", {
1406
+ type: "workflow-step-suspended",
1407
+ payload: {
1408
+ id: step.id,
1409
+ ...execResults
1410
+ }
1411
+ });
1412
+ } else {
1413
+ await emitter.emit("watch-v2", {
1414
+ type: "workflow-step-result",
1415
+ payload: {
1416
+ id: step.id,
1417
+ ...execResults
1418
+ }
1419
+ });
1420
+ await emitter.emit("watch-v2", {
1421
+ type: "workflow-step-finish",
1422
+ payload: {
1423
+ id: step.id,
1424
+ metadata: {}
1425
+ }
1426
+ });
593
1427
  }
594
- }
595
- await emitter.emit("watch", {
596
- type: "watch",
597
- payload: {
598
- currentStep: {
599
- id: step.id,
600
- status: execResults.status,
601
- output: execResults.output
602
- },
603
- workflowState: {
604
- status: "running",
605
- steps: stepResults,
606
- result: null,
607
- error: null
608
- }
609
- },
610
- eventTimestamp: Date.now()
1428
+ stepAISpan?.end({ output: execResults });
1429
+ return { result: execResults, executionContext, stepResults };
611
1430
  });
612
- return { result: execResults, executionContext, stepResults };
613
- });
1431
+ } catch (e) {
1432
+ const stepFailure = e instanceof Error ? e?.cause : {
1433
+ status: "failed",
1434
+ error: e instanceof Error ? e.message : String(e),
1435
+ payload: inputData,
1436
+ startedAt,
1437
+ endedAt: Date.now()
1438
+ };
1439
+ stepRes = {
1440
+ result: stepFailure,
1441
+ executionContext,
1442
+ stepResults: {
1443
+ ...stepResults,
1444
+ [step.id]: stepFailure
1445
+ }
1446
+ };
1447
+ }
1448
+ if (disableScorers !== false && stepRes.result.status === "success") {
1449
+ await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
1450
+ if (step.scorers) {
1451
+ await this.runScorers({
1452
+ scorers: step.scorers,
1453
+ runId: executionContext.runId,
1454
+ input: inputData,
1455
+ output: stepRes.result,
1456
+ workflowId: executionContext.workflowId,
1457
+ stepId: step.id,
1458
+ requestContext,
1459
+ disableScorers,
1460
+ tracingContext: { currentSpan: stepAISpan }
1461
+ });
1462
+ }
1463
+ });
1464
+ }
614
1465
  Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
615
1466
  Object.assign(stepResults, stepRes.stepResults);
1467
+ executionContext.state = stepRes.executionContext.state;
616
1468
  return stepRes.result;
617
1469
  }
618
1470
  async persistStepUpdate({
619
1471
  workflowId,
620
1472
  runId,
621
1473
  stepResults,
622
- executionContext
1474
+ resourceId,
1475
+ executionContext,
1476
+ serializedStepGraph,
1477
+ workflowStatus,
1478
+ result,
1479
+ error
623
1480
  }) {
624
1481
  await this.inngestStep.run(
625
1482
  `workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
626
1483
  async () => {
1484
+ const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
1485
+ if (!shouldPersistSnapshot) {
1486
+ return;
1487
+ }
627
1488
  await this.mastra?.getStorage()?.persistWorkflowSnapshot({
628
1489
  workflowName: workflowId,
629
1490
  runId,
1491
+ resourceId,
630
1492
  snapshot: {
631
1493
  runId,
632
- value: {},
1494
+ value: executionContext.state,
633
1495
  context: stepResults,
634
1496
  activePaths: [],
635
1497
  suspendedPaths: executionContext.suspendedPaths,
1498
+ resumeLabels: executionContext.resumeLabels,
1499
+ waitingPaths: {},
1500
+ serializedStepGraph,
1501
+ status: workflowStatus,
1502
+ result,
1503
+ error,
636
1504
  // @ts-ignore
637
1505
  timestamp: Date.now()
638
1506
  }
@@ -645,53 +1513,124 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
645
1513
  runId,
646
1514
  entry,
647
1515
  prevOutput,
648
- prevStep,
649
1516
  stepResults,
650
1517
  resume,
651
1518
  executionContext,
652
1519
  emitter,
653
- runtimeContext
1520
+ abortController,
1521
+ requestContext,
1522
+ writableStream,
1523
+ disableScorers,
1524
+ tracingContext
654
1525
  }) {
1526
+ const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
1527
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
1528
+ name: `conditional: '${entry.conditions.length} conditions'`,
1529
+ input: prevOutput,
1530
+ attributes: {
1531
+ conditionCount: entry.conditions.length
1532
+ },
1533
+ tracingPolicy: this.options?.tracingPolicy
1534
+ });
655
1535
  let execResults;
656
1536
  const truthyIndexes = (await Promise.all(
657
1537
  entry.conditions.map(
658
1538
  (cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
1539
+ const evalSpan = conditionalSpan?.createChildSpan({
1540
+ type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
1541
+ name: `condition: '${index}'`,
1542
+ input: prevOutput,
1543
+ attributes: {
1544
+ conditionIndex: index
1545
+ },
1546
+ tracingPolicy: this.options?.tracingPolicy
1547
+ });
659
1548
  try {
660
- const result = await cond({
661
- mastra: this.mastra,
662
- runtimeContext,
663
- 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;
1549
+ const result = await cond(
1550
+ workflows.createDeprecationProxy(
1551
+ {
1552
+ runId,
1553
+ workflowId,
1554
+ mastra: this.mastra,
1555
+ requestContext,
1556
+ runCount: -1,
1557
+ retryCount: -1,
1558
+ inputData: prevOutput,
1559
+ state: executionContext.state,
1560
+ setState: (state) => {
1561
+ executionContext.state = state;
1562
+ },
1563
+ tracingContext: {
1564
+ currentSpan: evalSpan
1565
+ },
1566
+ getInitData: () => stepResults?.input,
1567
+ getStepResult: workflows.getStepResult.bind(this, stepResults),
1568
+ // TODO: this function shouldn't have suspend probably?
1569
+ suspend: async (_suspendPayload) => {
1570
+ },
1571
+ bail: () => {
1572
+ },
1573
+ abort: () => {
1574
+ abortController.abort();
1575
+ },
1576
+ [_constants.EMITTER_SYMBOL]: emitter,
1577
+ [_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
1578
+ engine: {
1579
+ step: this.inngestStep
1580
+ },
1581
+ abortSignal: abortController.signal,
1582
+ writer: new tools.ToolStream(
1583
+ {
1584
+ prefix: "workflow-step",
1585
+ callId: crypto.randomUUID(),
1586
+ name: "conditional",
1587
+ runId
1588
+ },
1589
+ writableStream
1590
+ )
1591
+ },
1592
+ {
1593
+ paramName: "runCount",
1594
+ deprecationMessage: workflows.runCountDeprecationMessage,
1595
+ logger: this.logger
672
1596
  }
673
- return null;
674
- },
675
- // TODO: this function shouldn't have suspend probably?
676
- suspend: async (_suspendPayload) => {
677
- },
678
- emitter
1597
+ )
1598
+ );
1599
+ evalSpan?.end({
1600
+ output: result,
1601
+ attributes: {
1602
+ result: !!result
1603
+ }
679
1604
  });
680
1605
  return result ? index : null;
681
1606
  } catch (e) {
1607
+ evalSpan?.error({
1608
+ error: e instanceof Error ? e : new Error(String(e)),
1609
+ attributes: {
1610
+ result: false
1611
+ }
1612
+ });
682
1613
  return null;
683
1614
  }
684
1615
  })
685
1616
  )
686
1617
  )).filter((index) => index !== null);
687
1618
  const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
1619
+ conditionalSpan?.update({
1620
+ attributes: {
1621
+ truthyIndexes,
1622
+ selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
1623
+ }
1624
+ });
688
1625
  const results = await Promise.all(
689
- stepsToRun.map(
690
- (step, index) => this.executeEntry({
691
- workflowId,
692
- runId,
693
- entry: step,
694
- prevStep,
1626
+ stepsToRun.map(async (step, index) => {
1627
+ const currStepResult = stepResults[step.step.id];
1628
+ if (currStepResult && currStepResult.status === "success") {
1629
+ return currStepResult;
1630
+ }
1631
+ const result = await this.executeStep({
1632
+ step: step.step,
1633
+ prevOutput,
695
1634
  stepResults,
696
1635
  resume,
697
1636
  executionContext: {
@@ -699,20 +1638,29 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
699
1638
  runId,
700
1639
  executionPath: [...executionContext.executionPath, index],
701
1640
  suspendedPaths: executionContext.suspendedPaths,
1641
+ resumeLabels: executionContext.resumeLabels,
702
1642
  retryConfig: executionContext.retryConfig,
703
- executionSpan: executionContext.executionSpan
1643
+ state: executionContext.state
704
1644
  },
705
1645
  emitter,
706
- runtimeContext
707
- })
708
- )
1646
+ abortController,
1647
+ requestContext,
1648
+ writableStream,
1649
+ disableScorers,
1650
+ tracingContext: {
1651
+ currentSpan: conditionalSpan
1652
+ }
1653
+ });
1654
+ stepResults[step.step.id] = result;
1655
+ return result;
1656
+ })
709
1657
  );
710
1658
  const hasFailed = results.find((result) => result.status === "failed");
711
1659
  const hasSuspended = results.find((result) => result.status === "suspended");
712
1660
  if (hasFailed) {
713
1661
  execResults = { status: "failed", error: hasFailed.error };
714
1662
  } else if (hasSuspended) {
715
- execResults = { status: "suspended", payload: hasSuspended.payload };
1663
+ execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
716
1664
  } else {
717
1665
  execResults = {
718
1666
  status: "success",
@@ -724,6 +1672,15 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
724
1672
  }, {})
725
1673
  };
726
1674
  }
1675
+ if (execResults.status === "failed") {
1676
+ conditionalSpan?.error({
1677
+ error: new Error(execResults.error)
1678
+ });
1679
+ } else {
1680
+ conditionalSpan?.end({
1681
+ output: execResults.output || execResults
1682
+ });
1683
+ }
727
1684
  return execResults;
728
1685
  }
729
1686
  };
@@ -731,5 +1688,8 @@ var InngestExecutionEngine = class extends vNext.DefaultExecutionEngine {
731
1688
  exports.InngestExecutionEngine = InngestExecutionEngine;
732
1689
  exports.InngestRun = InngestRun;
733
1690
  exports.InngestWorkflow = InngestWorkflow;
1691
+ exports.createStep = createStep;
734
1692
  exports.init = init;
735
1693
  exports.serve = serve;
1694
+ //# sourceMappingURL=index.cjs.map
1695
+ //# sourceMappingURL=index.cjs.map