@mastra/inngest 0.0.0-experimental-agent-builder-20250815195917 → 0.0.0-export-agent-memory-from-local-studio-20251112153946

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