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