@mastra/inngest 0.0.0-cloud-transporter-20250513033346 → 0.0.0-cloud-storage-adapter-20251106204059

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