@mastra/inngest 0.0.0-course-20250527170450 → 0.0.0-custom-instrumentation-20250708222033
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 +385 -2
- package/LICENSE.md +11 -42
- package/dist/_tsup-dts-rollup.d.cts +155 -40
- package/dist/_tsup-dts-rollup.d.ts +155 -40
- package/dist/index.cjs +576 -54
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +576 -55
- package/docker-compose.yaml +3 -3
- package/package.json +21 -19
- package/src/index.test.ts +5599 -3509
- package/src/index.ts +859 -79
- package/vitest.config.ts +6 -0
package/dist/index.cjs
CHANGED
|
@@ -3,20 +3,26 @@
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
4
|
var realtime = require('@inngest/realtime');
|
|
5
5
|
var di = require('@mastra/core/di');
|
|
6
|
+
var tools = require('@mastra/core/tools');
|
|
6
7
|
var workflows = require('@mastra/core/workflows');
|
|
7
8
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
8
9
|
var hono = require('inngest/hono');
|
|
10
|
+
var zod = require('zod');
|
|
9
11
|
|
|
10
12
|
// src/index.ts
|
|
11
13
|
function serve({ mastra, inngest }) {
|
|
12
14
|
const wfs = mastra.getWorkflows();
|
|
13
|
-
const functions =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const functions = Array.from(
|
|
16
|
+
new Set(
|
|
17
|
+
Object.values(wfs).flatMap((wf) => {
|
|
18
|
+
if (wf instanceof InngestWorkflow) {
|
|
19
|
+
wf.__registerMastra(mastra);
|
|
20
|
+
return wf.getFunctions();
|
|
21
|
+
}
|
|
22
|
+
return [];
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
);
|
|
20
26
|
return hono.serve({
|
|
21
27
|
client: inngest,
|
|
22
28
|
functions
|
|
@@ -24,14 +30,16 @@ function serve({ mastra, inngest }) {
|
|
|
24
30
|
}
|
|
25
31
|
var InngestRun = class extends workflows.Run {
|
|
26
32
|
inngest;
|
|
33
|
+
serializedStepGraph;
|
|
27
34
|
#mastra;
|
|
28
35
|
constructor(params, inngest) {
|
|
29
36
|
super(params);
|
|
30
37
|
this.inngest = inngest;
|
|
38
|
+
this.serializedStepGraph = params.serializedStepGraph;
|
|
31
39
|
this.#mastra = params.mastra;
|
|
32
40
|
}
|
|
33
41
|
async getRuns(eventId) {
|
|
34
|
-
const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
|
|
42
|
+
const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
|
|
35
43
|
headers: {
|
|
36
44
|
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
37
45
|
}
|
|
@@ -41,15 +49,50 @@ var InngestRun = class extends workflows.Run {
|
|
|
41
49
|
}
|
|
42
50
|
async getRunOutput(eventId) {
|
|
43
51
|
let runs = await this.getRuns(eventId);
|
|
44
|
-
while (runs?.[0]?.status !== "Completed") {
|
|
52
|
+
while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
|
|
45
53
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
46
54
|
runs = await this.getRuns(eventId);
|
|
47
|
-
if (runs?.[0]?.status === "Failed"
|
|
55
|
+
if (runs?.[0]?.status === "Failed") {
|
|
56
|
+
console.log("run", runs?.[0]);
|
|
48
57
|
throw new Error(`Function run ${runs?.[0]?.status}`);
|
|
58
|
+
} else if (runs?.[0]?.status === "Cancelled") {
|
|
59
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
60
|
+
workflowName: this.workflowId,
|
|
61
|
+
runId: this.runId
|
|
62
|
+
});
|
|
63
|
+
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
49
64
|
}
|
|
50
65
|
}
|
|
51
66
|
return runs?.[0];
|
|
52
67
|
}
|
|
68
|
+
async sendEvent(event, data) {
|
|
69
|
+
await this.inngest.send({
|
|
70
|
+
name: `user-event-${event}`,
|
|
71
|
+
data
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async cancel() {
|
|
75
|
+
await this.inngest.send({
|
|
76
|
+
name: `cancel.workflow.${this.workflowId}`,
|
|
77
|
+
data: {
|
|
78
|
+
runId: this.runId
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
82
|
+
workflowName: this.workflowId,
|
|
83
|
+
runId: this.runId
|
|
84
|
+
});
|
|
85
|
+
if (snapshot) {
|
|
86
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
87
|
+
workflowName: this.workflowId,
|
|
88
|
+
runId: this.runId,
|
|
89
|
+
snapshot: {
|
|
90
|
+
...snapshot,
|
|
91
|
+
status: "canceled"
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
53
96
|
async start({
|
|
54
97
|
inputData
|
|
55
98
|
}) {
|
|
@@ -58,11 +101,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
58
101
|
runId: this.runId,
|
|
59
102
|
snapshot: {
|
|
60
103
|
runId: this.runId,
|
|
104
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
61
105
|
value: {},
|
|
62
106
|
context: {},
|
|
63
107
|
activePaths: [],
|
|
64
108
|
suspendedPaths: {},
|
|
65
|
-
timestamp: Date.now()
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
status: "running"
|
|
66
111
|
}
|
|
67
112
|
});
|
|
68
113
|
const eventOutput = await this.inngest.send({
|
|
@@ -81,10 +126,23 @@ var InngestRun = class extends workflows.Run {
|
|
|
81
126
|
if (result.status === "failed") {
|
|
82
127
|
result.error = new Error(result.error);
|
|
83
128
|
}
|
|
84
|
-
|
|
129
|
+
if (result.status !== "suspended") {
|
|
130
|
+
this.cleanup?.();
|
|
131
|
+
}
|
|
85
132
|
return result;
|
|
86
133
|
}
|
|
87
134
|
async resume(params) {
|
|
135
|
+
const p = this._resume(params).then((result) => {
|
|
136
|
+
if (result.status !== "suspended") {
|
|
137
|
+
this.closeStreamAction?.().catch(() => {
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
});
|
|
142
|
+
this.executionResults = p;
|
|
143
|
+
return p;
|
|
144
|
+
}
|
|
145
|
+
async _resume(params) {
|
|
88
146
|
const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
89
147
|
(step) => typeof step === "string" ? step : step?.id
|
|
90
148
|
);
|
|
@@ -118,25 +176,60 @@ var InngestRun = class extends workflows.Run {
|
|
|
118
176
|
}
|
|
119
177
|
return result;
|
|
120
178
|
}
|
|
121
|
-
watch(cb) {
|
|
179
|
+
watch(cb, type = "watch") {
|
|
180
|
+
let active = true;
|
|
122
181
|
const streamPromise = realtime.subscribe(
|
|
123
182
|
{
|
|
124
183
|
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
125
|
-
topics: [
|
|
184
|
+
topics: [type],
|
|
126
185
|
app: this.inngest
|
|
127
186
|
},
|
|
128
187
|
(message) => {
|
|
129
|
-
|
|
188
|
+
if (active) {
|
|
189
|
+
cb(message.data);
|
|
190
|
+
}
|
|
130
191
|
}
|
|
131
192
|
);
|
|
132
193
|
return () => {
|
|
133
|
-
|
|
134
|
-
|
|
194
|
+
active = false;
|
|
195
|
+
streamPromise.then(async (stream) => {
|
|
196
|
+
return stream.cancel();
|
|
135
197
|
}).catch((err) => {
|
|
136
198
|
console.error(err);
|
|
137
199
|
});
|
|
138
200
|
};
|
|
139
201
|
}
|
|
202
|
+
stream({ inputData, runtimeContext } = {}) {
|
|
203
|
+
const { readable, writable } = new TransformStream();
|
|
204
|
+
const writer = writable.getWriter();
|
|
205
|
+
const unwatch = this.watch(async (event) => {
|
|
206
|
+
try {
|
|
207
|
+
await writer.write(event);
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
}, "watch-v2");
|
|
211
|
+
this.closeStreamAction = async () => {
|
|
212
|
+
unwatch();
|
|
213
|
+
try {
|
|
214
|
+
await writer.close();
|
|
215
|
+
} catch (err) {
|
|
216
|
+
console.error("Error closing stream:", err);
|
|
217
|
+
} finally {
|
|
218
|
+
writer.releaseLock();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
|
|
222
|
+
if (result.status !== "suspended") {
|
|
223
|
+
this.closeStreamAction?.().catch(() => {
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
});
|
|
228
|
+
return {
|
|
229
|
+
stream: readable,
|
|
230
|
+
getWorkflowState: () => this.executionResults
|
|
231
|
+
};
|
|
232
|
+
}
|
|
140
233
|
};
|
|
141
234
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
142
235
|
#mastra;
|
|
@@ -159,11 +252,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
159
252
|
const storage = this.#mastra?.getStorage();
|
|
160
253
|
if (!storage) {
|
|
161
254
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
162
|
-
return null;
|
|
255
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
163
256
|
}
|
|
164
257
|
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
165
258
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
166
259
|
}
|
|
260
|
+
async getWorkflowRunExecutionResult(runId) {
|
|
261
|
+
const storage = this.#mastra?.getStorage();
|
|
262
|
+
if (!storage) {
|
|
263
|
+
this.logger.debug("Cannot get workflow run execution result. Mastra storage is not initialized");
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
267
|
+
if (!run?.snapshot) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
if (typeof run.snapshot === "string") {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
status: run.snapshot.status,
|
|
275
|
+
result: run.snapshot.result,
|
|
276
|
+
error: run.snapshot.error,
|
|
277
|
+
payload: run.snapshot.context?.input,
|
|
278
|
+
steps: run.snapshot.context
|
|
279
|
+
};
|
|
280
|
+
}
|
|
167
281
|
__registerMastra(mastra) {
|
|
168
282
|
this.#mastra = mastra;
|
|
169
283
|
this.executionEngine.__registerMastra(mastra);
|
|
@@ -190,6 +304,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
190
304
|
runId: runIdToUse,
|
|
191
305
|
executionEngine: this.executionEngine,
|
|
192
306
|
executionGraph: this.executionGraph,
|
|
307
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
193
308
|
mastra: this.#mastra,
|
|
194
309
|
retryConfig: this.retryConfig,
|
|
195
310
|
cleanup: () => this.runs.delete(runIdToUse)
|
|
@@ -199,13 +314,55 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
199
314
|
this.runs.set(runIdToUse, run);
|
|
200
315
|
return run;
|
|
201
316
|
}
|
|
317
|
+
async createRunAsync(options) {
|
|
318
|
+
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
319
|
+
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
320
|
+
{
|
|
321
|
+
workflowId: this.id,
|
|
322
|
+
runId: runIdToUse,
|
|
323
|
+
executionEngine: this.executionEngine,
|
|
324
|
+
executionGraph: this.executionGraph,
|
|
325
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
326
|
+
mastra: this.#mastra,
|
|
327
|
+
retryConfig: this.retryConfig,
|
|
328
|
+
cleanup: () => this.runs.delete(runIdToUse)
|
|
329
|
+
},
|
|
330
|
+
this.inngest
|
|
331
|
+
);
|
|
332
|
+
this.runs.set(runIdToUse, run);
|
|
333
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
|
|
334
|
+
if (!workflowSnapshotInStorage) {
|
|
335
|
+
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
336
|
+
workflowName: this.id,
|
|
337
|
+
runId: runIdToUse,
|
|
338
|
+
snapshot: {
|
|
339
|
+
runId: runIdToUse,
|
|
340
|
+
status: "pending",
|
|
341
|
+
value: {},
|
|
342
|
+
context: {},
|
|
343
|
+
activePaths: [],
|
|
344
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
345
|
+
suspendedPaths: {},
|
|
346
|
+
result: void 0,
|
|
347
|
+
error: void 0,
|
|
348
|
+
// @ts-ignore
|
|
349
|
+
timestamp: Date.now()
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
return run;
|
|
354
|
+
}
|
|
202
355
|
getFunction() {
|
|
203
356
|
if (this.function) {
|
|
204
357
|
return this.function;
|
|
205
358
|
}
|
|
206
359
|
this.function = this.inngest.createFunction(
|
|
207
|
-
|
|
208
|
-
|
|
360
|
+
{
|
|
361
|
+
id: `workflow.${this.id}`,
|
|
362
|
+
// @ts-ignore
|
|
363
|
+
retries: this.retryConfig?.attempts ?? 0,
|
|
364
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }]
|
|
365
|
+
},
|
|
209
366
|
{ event: `workflow.${this.id}` },
|
|
210
367
|
async ({ event, step, attempt, publish }) => {
|
|
211
368
|
let { inputData, runId, resume } = event.data;
|
|
@@ -222,12 +379,18 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
222
379
|
try {
|
|
223
380
|
await publish({
|
|
224
381
|
channel: `workflow:${this.id}:${runId}`,
|
|
225
|
-
topic:
|
|
382
|
+
topic: event2,
|
|
226
383
|
data
|
|
227
384
|
});
|
|
228
385
|
} catch (err) {
|
|
229
386
|
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
230
387
|
}
|
|
388
|
+
},
|
|
389
|
+
on: (_event, _callback) => {
|
|
390
|
+
},
|
|
391
|
+
off: (_event, _callback) => {
|
|
392
|
+
},
|
|
393
|
+
once: (_event, _callback) => {
|
|
231
394
|
}
|
|
232
395
|
};
|
|
233
396
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
@@ -235,12 +398,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
235
398
|
workflowId: this.id,
|
|
236
399
|
runId,
|
|
237
400
|
graph: this.executionGraph,
|
|
401
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
238
402
|
input: inputData,
|
|
239
403
|
emitter,
|
|
240
404
|
retryConfig: this.retryConfig,
|
|
241
405
|
runtimeContext: new di.RuntimeContext(),
|
|
242
406
|
// TODO
|
|
243
|
-
resume
|
|
407
|
+
resume,
|
|
408
|
+
abortController: new AbortController()
|
|
244
409
|
});
|
|
245
410
|
return { result, runId };
|
|
246
411
|
}
|
|
@@ -264,29 +429,138 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
264
429
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
265
430
|
}
|
|
266
431
|
};
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
432
|
+
function isAgent(params) {
|
|
433
|
+
return params?.component === "AGENT";
|
|
434
|
+
}
|
|
435
|
+
function isTool(params) {
|
|
436
|
+
return params instanceof tools.Tool;
|
|
437
|
+
}
|
|
438
|
+
function createStep(params) {
|
|
439
|
+
if (isAgent(params)) {
|
|
440
|
+
return {
|
|
441
|
+
id: params.name,
|
|
442
|
+
// @ts-ignore
|
|
443
|
+
inputSchema: zod.z.object({
|
|
444
|
+
prompt: zod.z.string()
|
|
445
|
+
// resourceId: z.string().optional(),
|
|
446
|
+
// threadId: z.string().optional(),
|
|
447
|
+
}),
|
|
448
|
+
// @ts-ignore
|
|
449
|
+
outputSchema: zod.z.object({
|
|
450
|
+
text: zod.z.string()
|
|
451
|
+
}),
|
|
452
|
+
execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
|
|
453
|
+
let streamPromise = {};
|
|
454
|
+
streamPromise.promise = new Promise((resolve, reject) => {
|
|
455
|
+
streamPromise.resolve = resolve;
|
|
456
|
+
streamPromise.reject = reject;
|
|
457
|
+
});
|
|
458
|
+
const toolData = {
|
|
459
|
+
name: params.name,
|
|
460
|
+
args: inputData
|
|
461
|
+
};
|
|
462
|
+
await emitter.emit("watch-v2", {
|
|
463
|
+
type: "tool-call-streaming-start",
|
|
464
|
+
...toolData
|
|
465
|
+
});
|
|
466
|
+
const { fullStream } = await params.stream(inputData.prompt, {
|
|
467
|
+
// resourceId: inputData.resourceId,
|
|
468
|
+
// threadId: inputData.threadId,
|
|
469
|
+
runtimeContext,
|
|
470
|
+
onFinish: (result) => {
|
|
471
|
+
streamPromise.resolve(result.text);
|
|
472
|
+
},
|
|
473
|
+
abortSignal
|
|
474
|
+
});
|
|
475
|
+
if (abortSignal.aborted) {
|
|
476
|
+
return abort();
|
|
477
|
+
}
|
|
478
|
+
for await (const chunk of fullStream) {
|
|
479
|
+
switch (chunk.type) {
|
|
480
|
+
case "text-delta":
|
|
481
|
+
await emitter.emit("watch-v2", {
|
|
482
|
+
type: "tool-call-delta",
|
|
483
|
+
...toolData,
|
|
484
|
+
argsTextDelta: chunk.textDelta
|
|
485
|
+
});
|
|
486
|
+
break;
|
|
487
|
+
case "step-start":
|
|
488
|
+
case "step-finish":
|
|
489
|
+
case "finish":
|
|
490
|
+
break;
|
|
491
|
+
case "tool-call":
|
|
492
|
+
case "tool-result":
|
|
493
|
+
case "tool-call-streaming-start":
|
|
494
|
+
case "tool-call-delta":
|
|
495
|
+
case "source":
|
|
496
|
+
case "file":
|
|
497
|
+
default:
|
|
498
|
+
await emitter.emit("watch-v2", chunk);
|
|
499
|
+
break;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
text: await streamPromise.promise
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
if (isTool(params)) {
|
|
509
|
+
if (!params.inputSchema || !params.outputSchema) {
|
|
510
|
+
throw new Error("Tool must have input and output schemas defined");
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
// TODO: tool probably should have strong id type
|
|
514
|
+
// @ts-ignore
|
|
515
|
+
id: params.id,
|
|
516
|
+
inputSchema: params.inputSchema,
|
|
517
|
+
outputSchema: params.outputSchema,
|
|
518
|
+
execute: async ({ inputData, mastra, runtimeContext }) => {
|
|
519
|
+
return params.execute({
|
|
520
|
+
context: inputData,
|
|
521
|
+
mastra,
|
|
522
|
+
runtimeContext
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
id: params.id,
|
|
529
|
+
description: params.description,
|
|
530
|
+
inputSchema: params.inputSchema,
|
|
531
|
+
outputSchema: params.outputSchema,
|
|
532
|
+
resumeSchema: params.resumeSchema,
|
|
533
|
+
suspendSchema: params.suspendSchema,
|
|
534
|
+
execute: params.execute
|
|
535
|
+
};
|
|
281
536
|
}
|
|
282
537
|
function init(inngest) {
|
|
283
538
|
return {
|
|
284
539
|
createWorkflow(params) {
|
|
285
540
|
return new InngestWorkflow(params, inngest);
|
|
286
541
|
},
|
|
287
|
-
createStep
|
|
288
|
-
cloneStep
|
|
289
|
-
|
|
542
|
+
createStep,
|
|
543
|
+
cloneStep(step, opts) {
|
|
544
|
+
return {
|
|
545
|
+
id: opts.id,
|
|
546
|
+
description: step.description,
|
|
547
|
+
inputSchema: step.inputSchema,
|
|
548
|
+
outputSchema: step.outputSchema,
|
|
549
|
+
execute: step.execute
|
|
550
|
+
};
|
|
551
|
+
},
|
|
552
|
+
cloneWorkflow(workflow, opts) {
|
|
553
|
+
const wf = new workflows.Workflow({
|
|
554
|
+
id: opts.id,
|
|
555
|
+
inputSchema: workflow.inputSchema,
|
|
556
|
+
outputSchema: workflow.outputSchema,
|
|
557
|
+
steps: workflow.stepDefs,
|
|
558
|
+
mastra: workflow.mastra
|
|
559
|
+
});
|
|
560
|
+
wf.setStepFlow(workflow.stepGraph);
|
|
561
|
+
wf.commit();
|
|
562
|
+
return wf;
|
|
563
|
+
}
|
|
290
564
|
};
|
|
291
565
|
}
|
|
292
566
|
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
@@ -297,6 +571,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
297
571
|
this.inngestStep = inngestStep;
|
|
298
572
|
this.inngestAttempts = inngestAttempts;
|
|
299
573
|
}
|
|
574
|
+
async execute(params) {
|
|
575
|
+
await params.emitter.emit("watch-v2", {
|
|
576
|
+
type: "start",
|
|
577
|
+
payload: { runId: params.runId }
|
|
578
|
+
});
|
|
579
|
+
const result = await super.execute(params);
|
|
580
|
+
await params.emitter.emit("watch-v2", {
|
|
581
|
+
type: "finish",
|
|
582
|
+
payload: { runId: params.runId }
|
|
583
|
+
});
|
|
584
|
+
return result;
|
|
585
|
+
}
|
|
300
586
|
async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
|
|
301
587
|
const base = {
|
|
302
588
|
status: lastOutput.status,
|
|
@@ -363,6 +649,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
363
649
|
resume,
|
|
364
650
|
prevOutput,
|
|
365
651
|
emitter,
|
|
652
|
+
abortController,
|
|
366
653
|
runtimeContext
|
|
367
654
|
}) {
|
|
368
655
|
return super.executeStep({
|
|
@@ -374,9 +661,118 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
374
661
|
resume,
|
|
375
662
|
prevOutput,
|
|
376
663
|
emitter,
|
|
664
|
+
abortController,
|
|
377
665
|
runtimeContext
|
|
378
666
|
});
|
|
379
667
|
}
|
|
668
|
+
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
669
|
+
// await this.inngestStep.sleep(id, duration);
|
|
670
|
+
// }
|
|
671
|
+
async executeSleep({
|
|
672
|
+
workflowId,
|
|
673
|
+
runId,
|
|
674
|
+
entry,
|
|
675
|
+
prevOutput,
|
|
676
|
+
stepResults,
|
|
677
|
+
emitter,
|
|
678
|
+
abortController,
|
|
679
|
+
runtimeContext
|
|
680
|
+
}) {
|
|
681
|
+
let { duration, fn } = entry;
|
|
682
|
+
if (fn) {
|
|
683
|
+
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
684
|
+
return await fn({
|
|
685
|
+
runId,
|
|
686
|
+
mastra: this.mastra,
|
|
687
|
+
runtimeContext,
|
|
688
|
+
inputData: prevOutput,
|
|
689
|
+
runCount: -1,
|
|
690
|
+
getInitData: () => stepResults?.input,
|
|
691
|
+
getStepResult: (step) => {
|
|
692
|
+
if (!step?.id) {
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
const result = stepResults[step.id];
|
|
696
|
+
if (result?.status === "success") {
|
|
697
|
+
return result.output;
|
|
698
|
+
}
|
|
699
|
+
return null;
|
|
700
|
+
},
|
|
701
|
+
// TODO: this function shouldn't have suspend probably?
|
|
702
|
+
suspend: async (_suspendPayload) => {
|
|
703
|
+
},
|
|
704
|
+
bail: () => {
|
|
705
|
+
},
|
|
706
|
+
abort: () => {
|
|
707
|
+
abortController?.abort();
|
|
708
|
+
},
|
|
709
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
710
|
+
engine: { step: this.inngestStep },
|
|
711
|
+
abortSignal: abortController?.signal
|
|
712
|
+
});
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
716
|
+
}
|
|
717
|
+
async executeSleepUntil({
|
|
718
|
+
workflowId,
|
|
719
|
+
runId,
|
|
720
|
+
entry,
|
|
721
|
+
prevOutput,
|
|
722
|
+
stepResults,
|
|
723
|
+
emitter,
|
|
724
|
+
abortController,
|
|
725
|
+
runtimeContext
|
|
726
|
+
}) {
|
|
727
|
+
let { date, fn } = entry;
|
|
728
|
+
if (fn) {
|
|
729
|
+
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
730
|
+
return await fn({
|
|
731
|
+
runId,
|
|
732
|
+
mastra: this.mastra,
|
|
733
|
+
runtimeContext,
|
|
734
|
+
inputData: prevOutput,
|
|
735
|
+
runCount: -1,
|
|
736
|
+
getInitData: () => stepResults?.input,
|
|
737
|
+
getStepResult: (step) => {
|
|
738
|
+
if (!step?.id) {
|
|
739
|
+
return null;
|
|
740
|
+
}
|
|
741
|
+
const result = stepResults[step.id];
|
|
742
|
+
if (result?.status === "success") {
|
|
743
|
+
return result.output;
|
|
744
|
+
}
|
|
745
|
+
return null;
|
|
746
|
+
},
|
|
747
|
+
// TODO: this function shouldn't have suspend probably?
|
|
748
|
+
suspend: async (_suspendPayload) => {
|
|
749
|
+
},
|
|
750
|
+
bail: () => {
|
|
751
|
+
},
|
|
752
|
+
abort: () => {
|
|
753
|
+
abortController?.abort();
|
|
754
|
+
},
|
|
755
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
756
|
+
engine: { step: this.inngestStep },
|
|
757
|
+
abortSignal: abortController?.signal
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
if (!(date instanceof Date)) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
await this.inngestStep.sleepUntil(entry.id, date);
|
|
765
|
+
}
|
|
766
|
+
async executeWaitForEvent({ event, timeout }) {
|
|
767
|
+
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
768
|
+
event: `user-event-${event}`,
|
|
769
|
+
timeout: timeout ?? 5e3
|
|
770
|
+
});
|
|
771
|
+
if (eventData === null) {
|
|
772
|
+
throw "Timeout waiting for event";
|
|
773
|
+
}
|
|
774
|
+
return eventData?.data;
|
|
775
|
+
}
|
|
380
776
|
async executeStep({
|
|
381
777
|
step,
|
|
382
778
|
stepResults,
|
|
@@ -384,11 +780,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
384
780
|
resume,
|
|
385
781
|
prevOutput,
|
|
386
782
|
emitter,
|
|
783
|
+
abortController,
|
|
387
784
|
runtimeContext
|
|
388
785
|
}) {
|
|
389
|
-
await this.inngestStep.run(
|
|
786
|
+
const startedAt = await this.inngestStep.run(
|
|
390
787
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
391
788
|
async () => {
|
|
789
|
+
const startedAt2 = Date.now();
|
|
392
790
|
await emitter.emit("watch", {
|
|
393
791
|
type: "watch",
|
|
394
792
|
payload: {
|
|
@@ -410,6 +808,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
410
808
|
},
|
|
411
809
|
eventTimestamp: Date.now()
|
|
412
810
|
});
|
|
811
|
+
await emitter.emit("watch-v2", {
|
|
812
|
+
type: "step-start",
|
|
813
|
+
payload: {
|
|
814
|
+
id: step.id,
|
|
815
|
+
status: "running",
|
|
816
|
+
payload: prevOutput,
|
|
817
|
+
startedAt: startedAt2
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
return startedAt2;
|
|
413
821
|
}
|
|
414
822
|
);
|
|
415
823
|
if (step instanceof InngestWorkflow) {
|
|
@@ -470,6 +878,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
470
878
|
},
|
|
471
879
|
eventTimestamp: Date.now()
|
|
472
880
|
});
|
|
881
|
+
await emitter.emit("watch-v2", {
|
|
882
|
+
type: "step-result",
|
|
883
|
+
payload: {
|
|
884
|
+
id: step.id,
|
|
885
|
+
status: "failed",
|
|
886
|
+
error: result?.error,
|
|
887
|
+
payload: prevOutput
|
|
888
|
+
}
|
|
889
|
+
});
|
|
473
890
|
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
474
891
|
} else if (result.status === "suspended") {
|
|
475
892
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
@@ -496,6 +913,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
496
913
|
},
|
|
497
914
|
eventTimestamp: Date.now()
|
|
498
915
|
});
|
|
916
|
+
await emitter.emit("watch-v2", {
|
|
917
|
+
type: "step-suspended",
|
|
918
|
+
payload: {
|
|
919
|
+
id: step.id,
|
|
920
|
+
status: "suspended"
|
|
921
|
+
}
|
|
922
|
+
});
|
|
499
923
|
return {
|
|
500
924
|
executionContext,
|
|
501
925
|
result: {
|
|
@@ -546,6 +970,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
546
970
|
},
|
|
547
971
|
eventTimestamp: Date.now()
|
|
548
972
|
});
|
|
973
|
+
await emitter.emit("watch-v2", {
|
|
974
|
+
type: "step-result",
|
|
975
|
+
payload: {
|
|
976
|
+
id: step.id,
|
|
977
|
+
status: "success",
|
|
978
|
+
output: result?.result
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
await emitter.emit("watch-v2", {
|
|
982
|
+
type: "step-finish",
|
|
983
|
+
payload: {
|
|
984
|
+
id: step.id,
|
|
985
|
+
metadata: {}
|
|
986
|
+
}
|
|
987
|
+
});
|
|
549
988
|
return { executionContext, result: { status: "success", output: result?.result } };
|
|
550
989
|
}
|
|
551
990
|
);
|
|
@@ -555,8 +994,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
555
994
|
const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
556
995
|
let execResults;
|
|
557
996
|
let suspended;
|
|
997
|
+
let bailed;
|
|
558
998
|
try {
|
|
559
999
|
const result = await step.execute({
|
|
1000
|
+
runId: executionContext.runId,
|
|
560
1001
|
mastra: this.mastra,
|
|
561
1002
|
runtimeContext,
|
|
562
1003
|
inputData: prevOutput,
|
|
@@ -573,20 +1014,54 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
573
1014
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
574
1015
|
suspended = { payload: suspendPayload };
|
|
575
1016
|
},
|
|
1017
|
+
bail: (result2) => {
|
|
1018
|
+
bailed = { payload: result2 };
|
|
1019
|
+
},
|
|
576
1020
|
resume: {
|
|
577
1021
|
steps: resume?.steps?.slice(1) || [],
|
|
578
1022
|
resumePayload: resume?.resumePayload,
|
|
579
1023
|
// @ts-ignore
|
|
580
1024
|
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
|
|
581
1025
|
},
|
|
582
|
-
emitter
|
|
1026
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1027
|
+
engine: {
|
|
1028
|
+
step: this.inngestStep
|
|
1029
|
+
},
|
|
1030
|
+
abortSignal: abortController.signal
|
|
583
1031
|
});
|
|
584
|
-
|
|
1032
|
+
const endedAt = Date.now();
|
|
1033
|
+
execResults = {
|
|
1034
|
+
status: "success",
|
|
1035
|
+
output: result,
|
|
1036
|
+
startedAt,
|
|
1037
|
+
endedAt,
|
|
1038
|
+
payload: prevOutput,
|
|
1039
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1040
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1041
|
+
};
|
|
585
1042
|
} catch (e) {
|
|
586
|
-
execResults = {
|
|
1043
|
+
execResults = {
|
|
1044
|
+
status: "failed",
|
|
1045
|
+
payload: prevOutput,
|
|
1046
|
+
error: e instanceof Error ? e.message : String(e),
|
|
1047
|
+
endedAt: Date.now(),
|
|
1048
|
+
startedAt,
|
|
1049
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1050
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1051
|
+
};
|
|
587
1052
|
}
|
|
588
1053
|
if (suspended) {
|
|
589
|
-
execResults = {
|
|
1054
|
+
execResults = {
|
|
1055
|
+
status: "suspended",
|
|
1056
|
+
suspendedPayload: suspended.payload,
|
|
1057
|
+
payload: prevOutput,
|
|
1058
|
+
suspendedAt: Date.now(),
|
|
1059
|
+
startedAt,
|
|
1060
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1061
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1062
|
+
};
|
|
1063
|
+
} else if (bailed) {
|
|
1064
|
+
execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
|
|
590
1065
|
}
|
|
591
1066
|
if (execResults.status === "failed") {
|
|
592
1067
|
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
@@ -598,18 +1073,41 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
598
1073
|
payload: {
|
|
599
1074
|
currentStep: {
|
|
600
1075
|
id: step.id,
|
|
601
|
-
|
|
602
|
-
output: execResults.output
|
|
1076
|
+
...execResults
|
|
603
1077
|
},
|
|
604
1078
|
workflowState: {
|
|
605
1079
|
status: "running",
|
|
606
|
-
steps: stepResults,
|
|
1080
|
+
steps: { ...stepResults, [step.id]: execResults },
|
|
607
1081
|
result: null,
|
|
608
1082
|
error: null
|
|
609
1083
|
}
|
|
610
1084
|
},
|
|
611
1085
|
eventTimestamp: Date.now()
|
|
612
1086
|
});
|
|
1087
|
+
if (execResults.status === "suspended") {
|
|
1088
|
+
await emitter.emit("watch-v2", {
|
|
1089
|
+
type: "step-suspended",
|
|
1090
|
+
payload: {
|
|
1091
|
+
id: step.id,
|
|
1092
|
+
...execResults
|
|
1093
|
+
}
|
|
1094
|
+
});
|
|
1095
|
+
} else {
|
|
1096
|
+
await emitter.emit("watch-v2", {
|
|
1097
|
+
type: "step-result",
|
|
1098
|
+
payload: {
|
|
1099
|
+
id: step.id,
|
|
1100
|
+
...execResults
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
await emitter.emit("watch-v2", {
|
|
1104
|
+
type: "step-finish",
|
|
1105
|
+
payload: {
|
|
1106
|
+
id: step.id,
|
|
1107
|
+
metadata: {}
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
613
1111
|
return { result: execResults, executionContext, stepResults };
|
|
614
1112
|
});
|
|
615
1113
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
@@ -620,7 +1118,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
620
1118
|
workflowId,
|
|
621
1119
|
runId,
|
|
622
1120
|
stepResults,
|
|
623
|
-
executionContext
|
|
1121
|
+
executionContext,
|
|
1122
|
+
serializedStepGraph,
|
|
1123
|
+
workflowStatus,
|
|
1124
|
+
result,
|
|
1125
|
+
error
|
|
624
1126
|
}) {
|
|
625
1127
|
await this.inngestStep.run(
|
|
626
1128
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
@@ -634,6 +1136,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
634
1136
|
context: stepResults,
|
|
635
1137
|
activePaths: [],
|
|
636
1138
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1139
|
+
serializedStepGraph,
|
|
1140
|
+
status: workflowStatus,
|
|
1141
|
+
result,
|
|
1142
|
+
error,
|
|
637
1143
|
// @ts-ignore
|
|
638
1144
|
timestamp: Date.now()
|
|
639
1145
|
}
|
|
@@ -648,9 +1154,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
648
1154
|
prevOutput,
|
|
649
1155
|
prevStep,
|
|
650
1156
|
stepResults,
|
|
1157
|
+
serializedStepGraph,
|
|
651
1158
|
resume,
|
|
652
1159
|
executionContext,
|
|
653
1160
|
emitter,
|
|
1161
|
+
abortController,
|
|
654
1162
|
runtimeContext
|
|
655
1163
|
}) {
|
|
656
1164
|
let execResults;
|
|
@@ -659,8 +1167,10 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
659
1167
|
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
660
1168
|
try {
|
|
661
1169
|
const result = await cond({
|
|
1170
|
+
runId,
|
|
662
1171
|
mastra: this.mastra,
|
|
663
1172
|
runtimeContext,
|
|
1173
|
+
runCount: -1,
|
|
664
1174
|
inputData: prevOutput,
|
|
665
1175
|
getInitData: () => stepResults?.input,
|
|
666
1176
|
getStepResult: (step) => {
|
|
@@ -676,7 +1186,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
676
1186
|
// TODO: this function shouldn't have suspend probably?
|
|
677
1187
|
suspend: async (_suspendPayload) => {
|
|
678
1188
|
},
|
|
679
|
-
|
|
1189
|
+
bail: () => {
|
|
1190
|
+
},
|
|
1191
|
+
abort: () => {
|
|
1192
|
+
abortController.abort();
|
|
1193
|
+
},
|
|
1194
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1195
|
+
engine: {
|
|
1196
|
+
step: this.inngestStep
|
|
1197
|
+
},
|
|
1198
|
+
abortSignal: abortController.signal
|
|
680
1199
|
});
|
|
681
1200
|
return result ? index : null;
|
|
682
1201
|
} catch (e) {
|
|
@@ -695,6 +1214,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
695
1214
|
prevStep,
|
|
696
1215
|
stepResults,
|
|
697
1216
|
resume,
|
|
1217
|
+
serializedStepGraph,
|
|
698
1218
|
executionContext: {
|
|
699
1219
|
workflowId,
|
|
700
1220
|
runId,
|
|
@@ -704,21 +1224,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
704
1224
|
executionSpan: executionContext.executionSpan
|
|
705
1225
|
},
|
|
706
1226
|
emitter,
|
|
1227
|
+
abortController,
|
|
707
1228
|
runtimeContext
|
|
708
1229
|
})
|
|
709
1230
|
)
|
|
710
1231
|
);
|
|
711
|
-
const hasFailed = results.find((result) => result.status === "failed");
|
|
712
|
-
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
1232
|
+
const hasFailed = results.find((result) => result.result.status === "failed");
|
|
1233
|
+
const hasSuspended = results.find((result) => result.result.status === "suspended");
|
|
713
1234
|
if (hasFailed) {
|
|
714
|
-
execResults = { status: "failed", error: hasFailed.error };
|
|
1235
|
+
execResults = { status: "failed", error: hasFailed.result.error };
|
|
715
1236
|
} else if (hasSuspended) {
|
|
716
|
-
execResults = { status: "suspended", payload: hasSuspended.
|
|
1237
|
+
execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
|
|
717
1238
|
} else {
|
|
718
1239
|
execResults = {
|
|
719
1240
|
status: "success",
|
|
720
1241
|
output: results.reduce((acc, result, index) => {
|
|
721
|
-
if (result.status === "success") {
|
|
1242
|
+
if (result.result.status === "success") {
|
|
722
1243
|
acc[stepsToRun[index].step.id] = result.output;
|
|
723
1244
|
}
|
|
724
1245
|
return acc;
|
|
@@ -732,5 +1253,6 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
732
1253
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
733
1254
|
exports.InngestRun = InngestRun;
|
|
734
1255
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1256
|
+
exports.createStep = createStep;
|
|
735
1257
|
exports.init = init;
|
|
736
1258
|
exports.serve = serve;
|