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