@mastra/inngest 0.0.0-course-20250527170450 → 0.0.0-createToolOptions-20250926094418
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 +980 -2
- package/LICENSE.md +11 -42
- package/dist/index.cjs +766 -104
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +295 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +767 -106
- package/dist/index.js.map +1 -0
- package/package.json +38 -22
- 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
|
@@ -2,36 +2,51 @@
|
|
|
2
2
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
4
|
var realtime = require('@inngest/realtime');
|
|
5
|
+
var aiTracing = require('@mastra/core/ai-tracing');
|
|
5
6
|
var di = require('@mastra/core/di');
|
|
7
|
+
var tools = require('@mastra/core/tools');
|
|
6
8
|
var workflows = require('@mastra/core/workflows');
|
|
7
9
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
8
10
|
var hono = require('inngest/hono');
|
|
11
|
+
var zod = require('zod');
|
|
9
12
|
|
|
10
13
|
// src/index.ts
|
|
11
|
-
function serve({
|
|
14
|
+
function serve({
|
|
15
|
+
mastra,
|
|
16
|
+
inngest,
|
|
17
|
+
functions: userFunctions = [],
|
|
18
|
+
registerOptions
|
|
19
|
+
}) {
|
|
12
20
|
const wfs = mastra.getWorkflows();
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
const workflowFunctions = Array.from(
|
|
22
|
+
new Set(
|
|
23
|
+
Object.values(wfs).flatMap((wf) => {
|
|
24
|
+
if (wf instanceof InngestWorkflow) {
|
|
25
|
+
wf.__registerMastra(mastra);
|
|
26
|
+
return wf.getFunctions();
|
|
27
|
+
}
|
|
28
|
+
return [];
|
|
29
|
+
})
|
|
30
|
+
)
|
|
31
|
+
);
|
|
20
32
|
return hono.serve({
|
|
33
|
+
...registerOptions,
|
|
21
34
|
client: inngest,
|
|
22
|
-
functions
|
|
35
|
+
functions: [...workflowFunctions, ...userFunctions]
|
|
23
36
|
});
|
|
24
37
|
}
|
|
25
38
|
var InngestRun = class extends workflows.Run {
|
|
26
39
|
inngest;
|
|
40
|
+
serializedStepGraph;
|
|
27
41
|
#mastra;
|
|
28
42
|
constructor(params, inngest) {
|
|
29
43
|
super(params);
|
|
30
44
|
this.inngest = inngest;
|
|
45
|
+
this.serializedStepGraph = params.serializedStepGraph;
|
|
31
46
|
this.#mastra = params.mastra;
|
|
32
47
|
}
|
|
33
48
|
async getRuns(eventId) {
|
|
34
|
-
const response = await fetch(`${this.inngest.apiBaseUrl}/v1/events/${eventId}/runs`, {
|
|
49
|
+
const response = await fetch(`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`, {
|
|
35
50
|
headers: {
|
|
36
51
|
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
37
52
|
}
|
|
@@ -41,35 +56,76 @@ var InngestRun = class extends workflows.Run {
|
|
|
41
56
|
}
|
|
42
57
|
async getRunOutput(eventId) {
|
|
43
58
|
let runs = await this.getRuns(eventId);
|
|
44
|
-
while (runs?.[0]?.status !== "Completed") {
|
|
59
|
+
while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
|
|
45
60
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
46
61
|
runs = await this.getRuns(eventId);
|
|
47
|
-
if (runs?.[0]?.status === "Failed"
|
|
62
|
+
if (runs?.[0]?.status === "Failed") {
|
|
48
63
|
throw new Error(`Function run ${runs?.[0]?.status}`);
|
|
64
|
+
} else if (runs?.[0]?.status === "Cancelled") {
|
|
65
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
66
|
+
workflowName: this.workflowId,
|
|
67
|
+
runId: this.runId
|
|
68
|
+
});
|
|
69
|
+
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
49
70
|
}
|
|
50
71
|
}
|
|
51
72
|
return runs?.[0];
|
|
52
73
|
}
|
|
74
|
+
async sendEvent(event, data) {
|
|
75
|
+
await this.inngest.send({
|
|
76
|
+
name: `user-event-${event}`,
|
|
77
|
+
data
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async cancel() {
|
|
81
|
+
await this.inngest.send({
|
|
82
|
+
name: `cancel.workflow.${this.workflowId}`,
|
|
83
|
+
data: {
|
|
84
|
+
runId: this.runId
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
88
|
+
workflowName: this.workflowId,
|
|
89
|
+
runId: this.runId
|
|
90
|
+
});
|
|
91
|
+
if (snapshot) {
|
|
92
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
93
|
+
workflowName: this.workflowId,
|
|
94
|
+
runId: this.runId,
|
|
95
|
+
resourceId: this.resourceId,
|
|
96
|
+
snapshot: {
|
|
97
|
+
...snapshot,
|
|
98
|
+
status: "canceled"
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
53
103
|
async start({
|
|
54
104
|
inputData
|
|
55
105
|
}) {
|
|
56
106
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
57
107
|
workflowName: this.workflowId,
|
|
58
108
|
runId: this.runId,
|
|
109
|
+
resourceId: this.resourceId,
|
|
59
110
|
snapshot: {
|
|
60
111
|
runId: this.runId,
|
|
112
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
61
113
|
value: {},
|
|
62
114
|
context: {},
|
|
63
115
|
activePaths: [],
|
|
64
116
|
suspendedPaths: {},
|
|
65
|
-
|
|
117
|
+
waitingPaths: {},
|
|
118
|
+
timestamp: Date.now(),
|
|
119
|
+
status: "running"
|
|
66
120
|
}
|
|
67
121
|
});
|
|
122
|
+
const inputDataToUse = await this._validateInput(inputData);
|
|
68
123
|
const eventOutput = await this.inngest.send({
|
|
69
124
|
name: `workflow.${this.workflowId}`,
|
|
70
125
|
data: {
|
|
71
|
-
inputData,
|
|
72
|
-
runId: this.runId
|
|
126
|
+
inputData: inputDataToUse,
|
|
127
|
+
runId: this.runId,
|
|
128
|
+
resourceId: this.resourceId
|
|
73
129
|
}
|
|
74
130
|
});
|
|
75
131
|
const eventId = eventOutput.ids[0];
|
|
@@ -81,10 +137,23 @@ var InngestRun = class extends workflows.Run {
|
|
|
81
137
|
if (result.status === "failed") {
|
|
82
138
|
result.error = new Error(result.error);
|
|
83
139
|
}
|
|
84
|
-
|
|
140
|
+
if (result.status !== "suspended") {
|
|
141
|
+
this.cleanup?.();
|
|
142
|
+
}
|
|
85
143
|
return result;
|
|
86
144
|
}
|
|
87
145
|
async resume(params) {
|
|
146
|
+
const p = this._resume(params).then((result) => {
|
|
147
|
+
if (result.status !== "suspended") {
|
|
148
|
+
this.closeStreamAction?.().catch(() => {
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
});
|
|
153
|
+
this.executionResults = p;
|
|
154
|
+
return p;
|
|
155
|
+
}
|
|
156
|
+
async _resume(params) {
|
|
88
157
|
const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
89
158
|
(step) => typeof step === "string" ? step : step?.id
|
|
90
159
|
);
|
|
@@ -92,16 +161,19 @@ var InngestRun = class extends workflows.Run {
|
|
|
92
161
|
workflowName: this.workflowId,
|
|
93
162
|
runId: this.runId
|
|
94
163
|
});
|
|
164
|
+
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
165
|
+
const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
|
|
95
166
|
const eventOutput = await this.inngest.send({
|
|
96
167
|
name: `workflow.${this.workflowId}`,
|
|
97
168
|
data: {
|
|
98
|
-
inputData:
|
|
169
|
+
inputData: resumeDataToUse,
|
|
99
170
|
runId: this.runId,
|
|
171
|
+
workflowId: this.workflowId,
|
|
100
172
|
stepResults: snapshot?.context,
|
|
101
173
|
resume: {
|
|
102
174
|
steps,
|
|
103
175
|
stepResults: snapshot?.context,
|
|
104
|
-
resumePayload:
|
|
176
|
+
resumePayload: resumeDataToUse,
|
|
105
177
|
// @ts-ignore
|
|
106
178
|
resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
|
|
107
179
|
}
|
|
@@ -118,32 +190,77 @@ var InngestRun = class extends workflows.Run {
|
|
|
118
190
|
}
|
|
119
191
|
return result;
|
|
120
192
|
}
|
|
121
|
-
watch(cb) {
|
|
193
|
+
watch(cb, type = "watch") {
|
|
194
|
+
let active = true;
|
|
122
195
|
const streamPromise = realtime.subscribe(
|
|
123
196
|
{
|
|
124
197
|
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
125
|
-
topics: [
|
|
198
|
+
topics: [type],
|
|
126
199
|
app: this.inngest
|
|
127
200
|
},
|
|
128
201
|
(message) => {
|
|
129
|
-
|
|
202
|
+
if (active) {
|
|
203
|
+
cb(message.data);
|
|
204
|
+
}
|
|
130
205
|
}
|
|
131
206
|
);
|
|
132
207
|
return () => {
|
|
133
|
-
|
|
134
|
-
|
|
208
|
+
active = false;
|
|
209
|
+
streamPromise.then(async (stream) => {
|
|
210
|
+
return stream.cancel();
|
|
135
211
|
}).catch((err) => {
|
|
136
212
|
console.error(err);
|
|
137
213
|
});
|
|
138
214
|
};
|
|
139
215
|
}
|
|
216
|
+
stream({ inputData, runtimeContext } = {}) {
|
|
217
|
+
const { readable, writable } = new TransformStream();
|
|
218
|
+
const writer = writable.getWriter();
|
|
219
|
+
const unwatch = this.watch(async (event) => {
|
|
220
|
+
try {
|
|
221
|
+
const e = {
|
|
222
|
+
...event,
|
|
223
|
+
type: event.type.replace("workflow-", "")
|
|
224
|
+
};
|
|
225
|
+
await writer.write(e);
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
}, "watch-v2");
|
|
229
|
+
this.closeStreamAction = async () => {
|
|
230
|
+
unwatch();
|
|
231
|
+
try {
|
|
232
|
+
await writer.close();
|
|
233
|
+
} catch (err) {
|
|
234
|
+
console.error("Error closing stream:", err);
|
|
235
|
+
} finally {
|
|
236
|
+
writer.releaseLock();
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
this.executionResults = this.start({ inputData, runtimeContext }).then((result) => {
|
|
240
|
+
if (result.status !== "suspended") {
|
|
241
|
+
this.closeStreamAction?.().catch(() => {
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return result;
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
stream: readable,
|
|
248
|
+
getWorkflowState: () => this.executionResults
|
|
249
|
+
};
|
|
250
|
+
}
|
|
140
251
|
};
|
|
141
252
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
142
253
|
#mastra;
|
|
143
254
|
inngest;
|
|
144
255
|
function;
|
|
256
|
+
flowControlConfig;
|
|
145
257
|
constructor(params, inngest) {
|
|
146
|
-
|
|
258
|
+
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
259
|
+
super(workflowParams);
|
|
260
|
+
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
261
|
+
([_, value]) => value !== void 0
|
|
262
|
+
);
|
|
263
|
+
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
147
264
|
this.#mastra = params.mastra;
|
|
148
265
|
this.inngest = inngest;
|
|
149
266
|
}
|
|
@@ -159,7 +276,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
159
276
|
const storage = this.#mastra?.getStorage();
|
|
160
277
|
if (!storage) {
|
|
161
278
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
162
|
-
return null;
|
|
279
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
163
280
|
}
|
|
164
281
|
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
165
282
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
@@ -182,21 +299,55 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
182
299
|
}
|
|
183
300
|
}
|
|
184
301
|
}
|
|
185
|
-
|
|
302
|
+
/**
|
|
303
|
+
* @deprecated Use createRunAsync() instead.
|
|
304
|
+
* @throws {Error} Always throws an error directing users to use createRunAsync()
|
|
305
|
+
*/
|
|
306
|
+
createRun(_options) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
"createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
async createRunAsync(options) {
|
|
186
312
|
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
187
313
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
188
314
|
{
|
|
189
315
|
workflowId: this.id,
|
|
190
316
|
runId: runIdToUse,
|
|
317
|
+
resourceId: options?.resourceId,
|
|
191
318
|
executionEngine: this.executionEngine,
|
|
192
319
|
executionGraph: this.executionGraph,
|
|
320
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
193
321
|
mastra: this.#mastra,
|
|
194
322
|
retryConfig: this.retryConfig,
|
|
195
|
-
cleanup: () => this.runs.delete(runIdToUse)
|
|
323
|
+
cleanup: () => this.runs.delete(runIdToUse),
|
|
324
|
+
workflowSteps: this.steps
|
|
196
325
|
},
|
|
197
326
|
this.inngest
|
|
198
327
|
);
|
|
199
328
|
this.runs.set(runIdToUse, run);
|
|
329
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
|
|
330
|
+
if (!workflowSnapshotInStorage) {
|
|
331
|
+
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
332
|
+
workflowName: this.id,
|
|
333
|
+
runId: runIdToUse,
|
|
334
|
+
resourceId: options?.resourceId,
|
|
335
|
+
snapshot: {
|
|
336
|
+
runId: runIdToUse,
|
|
337
|
+
status: "pending",
|
|
338
|
+
value: {},
|
|
339
|
+
context: {},
|
|
340
|
+
activePaths: [],
|
|
341
|
+
waitingPaths: {},
|
|
342
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
343
|
+
suspendedPaths: {},
|
|
344
|
+
result: void 0,
|
|
345
|
+
error: void 0,
|
|
346
|
+
// @ts-ignore
|
|
347
|
+
timestamp: Date.now()
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
200
351
|
return run;
|
|
201
352
|
}
|
|
202
353
|
getFunction() {
|
|
@@ -204,11 +355,17 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
204
355
|
return this.function;
|
|
205
356
|
}
|
|
206
357
|
this.function = this.inngest.createFunction(
|
|
207
|
-
|
|
208
|
-
|
|
358
|
+
{
|
|
359
|
+
id: `workflow.${this.id}`,
|
|
360
|
+
// @ts-ignore
|
|
361
|
+
retries: this.retryConfig?.attempts ?? 0,
|
|
362
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
363
|
+
// Spread flow control configuration
|
|
364
|
+
...this.flowControlConfig
|
|
365
|
+
},
|
|
209
366
|
{ event: `workflow.${this.id}` },
|
|
210
367
|
async ({ event, step, attempt, publish }) => {
|
|
211
|
-
let { inputData, runId, resume } = event.data;
|
|
368
|
+
let { inputData, runId, resourceId, resume } = event.data;
|
|
212
369
|
if (!runId) {
|
|
213
370
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
214
371
|
return crypto.randomUUID();
|
|
@@ -222,25 +379,36 @@ 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);
|
|
234
397
|
const result = await engine.execute({
|
|
235
398
|
workflowId: this.id,
|
|
236
399
|
runId,
|
|
400
|
+
resourceId,
|
|
237
401
|
graph: this.executionGraph,
|
|
402
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
238
403
|
input: inputData,
|
|
239
404
|
emitter,
|
|
240
405
|
retryConfig: this.retryConfig,
|
|
241
406
|
runtimeContext: new di.RuntimeContext(),
|
|
242
407
|
// TODO
|
|
243
|
-
resume
|
|
408
|
+
resume,
|
|
409
|
+
abortController: new AbortController(),
|
|
410
|
+
currentSpan: void 0
|
|
411
|
+
// TODO: Pass actual parent AI span from workflow execution context
|
|
244
412
|
});
|
|
245
413
|
return { result, runId };
|
|
246
414
|
}
|
|
@@ -264,39 +432,154 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
264
432
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
265
433
|
}
|
|
266
434
|
};
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
435
|
+
function isAgent(params) {
|
|
436
|
+
return params?.component === "AGENT";
|
|
437
|
+
}
|
|
438
|
+
function isTool(params) {
|
|
439
|
+
return params instanceof tools.Tool;
|
|
440
|
+
}
|
|
441
|
+
function createStep(params) {
|
|
442
|
+
if (isAgent(params)) {
|
|
443
|
+
return {
|
|
444
|
+
id: params.name,
|
|
445
|
+
description: params.getDescription(),
|
|
446
|
+
// @ts-ignore
|
|
447
|
+
inputSchema: zod.z.object({
|
|
448
|
+
prompt: zod.z.string()
|
|
449
|
+
}),
|
|
450
|
+
// @ts-ignore
|
|
451
|
+
outputSchema: zod.z.object({
|
|
452
|
+
text: zod.z.string()
|
|
453
|
+
}),
|
|
454
|
+
execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
|
|
455
|
+
let streamPromise = {};
|
|
456
|
+
streamPromise.promise = new Promise((resolve, reject) => {
|
|
457
|
+
streamPromise.resolve = resolve;
|
|
458
|
+
streamPromise.reject = reject;
|
|
459
|
+
});
|
|
460
|
+
const toolData = {
|
|
461
|
+
name: params.name,
|
|
462
|
+
args: inputData
|
|
463
|
+
};
|
|
464
|
+
const { fullStream } = await params.stream(inputData.prompt, {
|
|
465
|
+
runtimeContext,
|
|
466
|
+
tracingContext,
|
|
467
|
+
onFinish: (result) => {
|
|
468
|
+
streamPromise.resolve(result.text);
|
|
469
|
+
},
|
|
470
|
+
abortSignal
|
|
471
|
+
});
|
|
472
|
+
if (abortSignal.aborted) {
|
|
473
|
+
return abort();
|
|
474
|
+
}
|
|
475
|
+
await emitter.emit("watch-v2", {
|
|
476
|
+
type: "tool-call-streaming-start",
|
|
477
|
+
...toolData ?? {}
|
|
478
|
+
});
|
|
479
|
+
for await (const chunk of fullStream) {
|
|
480
|
+
if (chunk.type === "text-delta") {
|
|
481
|
+
await emitter.emit("watch-v2", {
|
|
482
|
+
type: "tool-call-delta",
|
|
483
|
+
...toolData ?? {},
|
|
484
|
+
argsTextDelta: chunk.textDelta
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
await emitter.emit("watch-v2", {
|
|
489
|
+
type: "tool-call-streaming-finish",
|
|
490
|
+
...toolData ?? {}
|
|
491
|
+
});
|
|
492
|
+
return {
|
|
493
|
+
text: await streamPromise.promise
|
|
494
|
+
};
|
|
495
|
+
},
|
|
496
|
+
component: params.component
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
if (isTool(params)) {
|
|
500
|
+
if (!params.inputSchema || !params.outputSchema) {
|
|
501
|
+
throw new Error("Tool must have input and output schemas defined");
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
// TODO: tool probably should have strong id type
|
|
505
|
+
// @ts-ignore
|
|
506
|
+
id: params.id,
|
|
507
|
+
description: params.description,
|
|
508
|
+
inputSchema: params.inputSchema,
|
|
509
|
+
outputSchema: params.outputSchema,
|
|
510
|
+
execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
|
|
511
|
+
return params.execute({
|
|
512
|
+
context: inputData,
|
|
513
|
+
mastra: aiTracing.wrapMastra(mastra, tracingContext),
|
|
514
|
+
runtimeContext,
|
|
515
|
+
tracingContext,
|
|
516
|
+
suspend,
|
|
517
|
+
resumeData
|
|
518
|
+
});
|
|
519
|
+
},
|
|
520
|
+
component: "TOOL"
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
return {
|
|
524
|
+
id: params.id,
|
|
525
|
+
description: params.description,
|
|
526
|
+
inputSchema: params.inputSchema,
|
|
527
|
+
outputSchema: params.outputSchema,
|
|
528
|
+
resumeSchema: params.resumeSchema,
|
|
529
|
+
suspendSchema: params.suspendSchema,
|
|
530
|
+
execute: params.execute
|
|
531
|
+
};
|
|
281
532
|
}
|
|
282
533
|
function init(inngest) {
|
|
283
534
|
return {
|
|
284
535
|
createWorkflow(params) {
|
|
285
536
|
return new InngestWorkflow(params, inngest);
|
|
286
537
|
},
|
|
287
|
-
createStep
|
|
288
|
-
cloneStep
|
|
289
|
-
|
|
538
|
+
createStep,
|
|
539
|
+
cloneStep(step, opts) {
|
|
540
|
+
return {
|
|
541
|
+
id: opts.id,
|
|
542
|
+
description: step.description,
|
|
543
|
+
inputSchema: step.inputSchema,
|
|
544
|
+
outputSchema: step.outputSchema,
|
|
545
|
+
execute: step.execute,
|
|
546
|
+
component: step.component
|
|
547
|
+
};
|
|
548
|
+
},
|
|
549
|
+
cloneWorkflow(workflow, opts) {
|
|
550
|
+
const wf = new workflows.Workflow({
|
|
551
|
+
id: opts.id,
|
|
552
|
+
inputSchema: workflow.inputSchema,
|
|
553
|
+
outputSchema: workflow.outputSchema,
|
|
554
|
+
steps: workflow.stepDefs,
|
|
555
|
+
mastra: workflow.mastra
|
|
556
|
+
});
|
|
557
|
+
wf.setStepFlow(workflow.stepGraph);
|
|
558
|
+
wf.commit();
|
|
559
|
+
return wf;
|
|
560
|
+
}
|
|
290
561
|
};
|
|
291
562
|
}
|
|
292
563
|
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
293
564
|
inngestStep;
|
|
294
565
|
inngestAttempts;
|
|
295
|
-
constructor(mastra, inngestStep, inngestAttempts = 0) {
|
|
296
|
-
super({ mastra });
|
|
566
|
+
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
567
|
+
super({ mastra, options });
|
|
297
568
|
this.inngestStep = inngestStep;
|
|
298
569
|
this.inngestAttempts = inngestAttempts;
|
|
299
570
|
}
|
|
571
|
+
async execute(params) {
|
|
572
|
+
await params.emitter.emit("watch-v2", {
|
|
573
|
+
type: "workflow-start",
|
|
574
|
+
payload: { runId: params.runId }
|
|
575
|
+
});
|
|
576
|
+
const result = await super.execute(params);
|
|
577
|
+
await params.emitter.emit("watch-v2", {
|
|
578
|
+
type: "workflow-finish",
|
|
579
|
+
payload: { runId: params.runId }
|
|
580
|
+
});
|
|
581
|
+
return result;
|
|
582
|
+
}
|
|
300
583
|
async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
|
|
301
584
|
const base = {
|
|
302
585
|
status: lastOutput.status,
|
|
@@ -354,28 +637,179 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
354
637
|
executionSpan?.end();
|
|
355
638
|
return base;
|
|
356
639
|
}
|
|
357
|
-
async
|
|
640
|
+
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
641
|
+
// await this.inngestStep.sleep(id, duration);
|
|
642
|
+
// }
|
|
643
|
+
async executeSleep({
|
|
358
644
|
workflowId,
|
|
359
645
|
runId,
|
|
360
|
-
|
|
646
|
+
entry,
|
|
647
|
+
prevOutput,
|
|
361
648
|
stepResults,
|
|
649
|
+
emitter,
|
|
650
|
+
abortController,
|
|
651
|
+
runtimeContext,
|
|
362
652
|
executionContext,
|
|
363
|
-
|
|
653
|
+
writableStream,
|
|
654
|
+
tracingContext
|
|
655
|
+
}) {
|
|
656
|
+
let { duration, fn } = entry;
|
|
657
|
+
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
658
|
+
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
659
|
+
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
660
|
+
attributes: {
|
|
661
|
+
durationMs: duration,
|
|
662
|
+
sleepType: fn ? "dynamic" : "fixed"
|
|
663
|
+
},
|
|
664
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
665
|
+
});
|
|
666
|
+
if (fn) {
|
|
667
|
+
const stepCallId = crypto.randomUUID();
|
|
668
|
+
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
669
|
+
return await fn({
|
|
670
|
+
runId,
|
|
671
|
+
workflowId,
|
|
672
|
+
mastra: this.mastra,
|
|
673
|
+
runtimeContext,
|
|
674
|
+
inputData: prevOutput,
|
|
675
|
+
runCount: -1,
|
|
676
|
+
tracingContext: {
|
|
677
|
+
currentSpan: sleepSpan
|
|
678
|
+
},
|
|
679
|
+
getInitData: () => stepResults?.input,
|
|
680
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
681
|
+
// TODO: this function shouldn't have suspend probably?
|
|
682
|
+
suspend: async (_suspendPayload) => {
|
|
683
|
+
},
|
|
684
|
+
bail: () => {
|
|
685
|
+
},
|
|
686
|
+
abort: () => {
|
|
687
|
+
abortController?.abort();
|
|
688
|
+
},
|
|
689
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
690
|
+
// TODO: add streamVNext support
|
|
691
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
692
|
+
engine: { step: this.inngestStep },
|
|
693
|
+
abortSignal: abortController?.signal,
|
|
694
|
+
writer: new tools.ToolStream(
|
|
695
|
+
{
|
|
696
|
+
prefix: "workflow-step",
|
|
697
|
+
callId: stepCallId,
|
|
698
|
+
name: "sleep",
|
|
699
|
+
runId
|
|
700
|
+
},
|
|
701
|
+
writableStream
|
|
702
|
+
)
|
|
703
|
+
});
|
|
704
|
+
});
|
|
705
|
+
sleepSpan?.update({
|
|
706
|
+
attributes: {
|
|
707
|
+
durationMs: duration
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
try {
|
|
712
|
+
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
713
|
+
sleepSpan?.end();
|
|
714
|
+
} catch (e) {
|
|
715
|
+
sleepSpan?.error({ error: e });
|
|
716
|
+
throw e;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
async executeSleepUntil({
|
|
720
|
+
workflowId,
|
|
721
|
+
runId,
|
|
722
|
+
entry,
|
|
364
723
|
prevOutput,
|
|
724
|
+
stepResults,
|
|
365
725
|
emitter,
|
|
366
|
-
|
|
726
|
+
abortController,
|
|
727
|
+
runtimeContext,
|
|
728
|
+
executionContext,
|
|
729
|
+
writableStream,
|
|
730
|
+
tracingContext
|
|
367
731
|
}) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
732
|
+
let { date, fn } = entry;
|
|
733
|
+
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
734
|
+
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
735
|
+
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
736
|
+
attributes: {
|
|
737
|
+
untilDate: date,
|
|
738
|
+
durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
|
|
739
|
+
sleepType: fn ? "dynamic" : "fixed"
|
|
740
|
+
},
|
|
741
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
742
|
+
});
|
|
743
|
+
if (fn) {
|
|
744
|
+
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
745
|
+
const stepCallId = crypto.randomUUID();
|
|
746
|
+
return await fn({
|
|
747
|
+
runId,
|
|
748
|
+
workflowId,
|
|
749
|
+
mastra: this.mastra,
|
|
750
|
+
runtimeContext,
|
|
751
|
+
inputData: prevOutput,
|
|
752
|
+
runCount: -1,
|
|
753
|
+
tracingContext: {
|
|
754
|
+
currentSpan: sleepUntilSpan
|
|
755
|
+
},
|
|
756
|
+
getInitData: () => stepResults?.input,
|
|
757
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
758
|
+
// TODO: this function shouldn't have suspend probably?
|
|
759
|
+
suspend: async (_suspendPayload) => {
|
|
760
|
+
},
|
|
761
|
+
bail: () => {
|
|
762
|
+
},
|
|
763
|
+
abort: () => {
|
|
764
|
+
abortController?.abort();
|
|
765
|
+
},
|
|
766
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
767
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
768
|
+
// TODO: add streamVNext support
|
|
769
|
+
engine: { step: this.inngestStep },
|
|
770
|
+
abortSignal: abortController?.signal,
|
|
771
|
+
writer: new tools.ToolStream(
|
|
772
|
+
{
|
|
773
|
+
prefix: "workflow-step",
|
|
774
|
+
callId: stepCallId,
|
|
775
|
+
name: "sleep",
|
|
776
|
+
runId
|
|
777
|
+
},
|
|
778
|
+
writableStream
|
|
779
|
+
)
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
if (date && !(date instanceof Date)) {
|
|
783
|
+
date = new Date(date);
|
|
784
|
+
}
|
|
785
|
+
const time = !date ? 0 : date.getTime() - Date.now();
|
|
786
|
+
sleepUntilSpan?.update({
|
|
787
|
+
attributes: {
|
|
788
|
+
durationMs: Math.max(0, time)
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
if (!(date instanceof Date)) {
|
|
793
|
+
sleepUntilSpan?.end();
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
try {
|
|
797
|
+
await this.inngestStep.sleepUntil(entry.id, date);
|
|
798
|
+
sleepUntilSpan?.end();
|
|
799
|
+
} catch (e) {
|
|
800
|
+
sleepUntilSpan?.error({ error: e });
|
|
801
|
+
throw e;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
async executeWaitForEvent({ event, timeout }) {
|
|
805
|
+
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
806
|
+
event: `user-event-${event}`,
|
|
807
|
+
timeout: timeout ?? 5e3
|
|
378
808
|
});
|
|
809
|
+
if (eventData === null) {
|
|
810
|
+
throw "Timeout waiting for event";
|
|
811
|
+
}
|
|
812
|
+
return eventData?.data;
|
|
379
813
|
}
|
|
380
814
|
async executeStep({
|
|
381
815
|
step,
|
|
@@ -384,11 +818,30 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
384
818
|
resume,
|
|
385
819
|
prevOutput,
|
|
386
820
|
emitter,
|
|
387
|
-
|
|
821
|
+
abortController,
|
|
822
|
+
runtimeContext,
|
|
823
|
+
tracingContext,
|
|
824
|
+
writableStream,
|
|
825
|
+
disableScorers
|
|
388
826
|
}) {
|
|
389
|
-
|
|
827
|
+
const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
|
|
828
|
+
name: `workflow step: '${step.id}'`,
|
|
829
|
+
type: aiTracing.AISpanType.WORKFLOW_STEP,
|
|
830
|
+
input: prevOutput,
|
|
831
|
+
attributes: {
|
|
832
|
+
stepId: step.id
|
|
833
|
+
},
|
|
834
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
835
|
+
});
|
|
836
|
+
const { inputData, validationError } = await workflows.validateStepInput({
|
|
837
|
+
prevOutput,
|
|
838
|
+
step,
|
|
839
|
+
validateInputs: this.options?.validateInputs ?? false
|
|
840
|
+
});
|
|
841
|
+
const startedAt = await this.inngestStep.run(
|
|
390
842
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
391
843
|
async () => {
|
|
844
|
+
const startedAt2 = Date.now();
|
|
392
845
|
await emitter.emit("watch", {
|
|
393
846
|
type: "watch",
|
|
394
847
|
payload: {
|
|
@@ -410,6 +863,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
410
863
|
},
|
|
411
864
|
eventTimestamp: Date.now()
|
|
412
865
|
});
|
|
866
|
+
await emitter.emit("watch-v2", {
|
|
867
|
+
type: "workflow-step-start",
|
|
868
|
+
payload: {
|
|
869
|
+
id: step.id,
|
|
870
|
+
status: "running",
|
|
871
|
+
payload: inputData,
|
|
872
|
+
startedAt: startedAt2
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
return startedAt2;
|
|
413
876
|
}
|
|
414
877
|
);
|
|
415
878
|
if (step instanceof InngestWorkflow) {
|
|
@@ -425,7 +888,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
425
888
|
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
426
889
|
function: step.getFunction(),
|
|
427
890
|
data: {
|
|
428
|
-
inputData
|
|
891
|
+
inputData,
|
|
429
892
|
runId,
|
|
430
893
|
resume: {
|
|
431
894
|
runId,
|
|
@@ -443,7 +906,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
443
906
|
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
444
907
|
function: step.getFunction(),
|
|
445
908
|
data: {
|
|
446
|
-
inputData
|
|
909
|
+
inputData
|
|
447
910
|
}
|
|
448
911
|
});
|
|
449
912
|
result = invokeResp.result;
|
|
@@ -470,6 +933,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
470
933
|
},
|
|
471
934
|
eventTimestamp: Date.now()
|
|
472
935
|
});
|
|
936
|
+
await emitter.emit("watch-v2", {
|
|
937
|
+
type: "workflow-step-result",
|
|
938
|
+
payload: {
|
|
939
|
+
id: step.id,
|
|
940
|
+
status: "failed",
|
|
941
|
+
error: result?.error,
|
|
942
|
+
payload: prevOutput
|
|
943
|
+
}
|
|
944
|
+
});
|
|
473
945
|
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
474
946
|
} else if (result.status === "suspended") {
|
|
475
947
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
@@ -496,6 +968,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
496
968
|
},
|
|
497
969
|
eventTimestamp: Date.now()
|
|
498
970
|
});
|
|
971
|
+
await emitter.emit("watch-v2", {
|
|
972
|
+
type: "workflow-step-suspended",
|
|
973
|
+
payload: {
|
|
974
|
+
id: step.id,
|
|
975
|
+
status: "suspended"
|
|
976
|
+
}
|
|
977
|
+
});
|
|
499
978
|
return {
|
|
500
979
|
executionContext,
|
|
501
980
|
result: {
|
|
@@ -546,6 +1025,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
546
1025
|
},
|
|
547
1026
|
eventTimestamp: Date.now()
|
|
548
1027
|
});
|
|
1028
|
+
await emitter.emit("watch-v2", {
|
|
1029
|
+
type: "workflow-step-result",
|
|
1030
|
+
payload: {
|
|
1031
|
+
id: step.id,
|
|
1032
|
+
status: "success",
|
|
1033
|
+
output: result?.result
|
|
1034
|
+
}
|
|
1035
|
+
});
|
|
1036
|
+
await emitter.emit("watch-v2", {
|
|
1037
|
+
type: "workflow-step-finish",
|
|
1038
|
+
payload: {
|
|
1039
|
+
id: step.id,
|
|
1040
|
+
metadata: {}
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
549
1043
|
return { executionContext, result: { status: "success", output: result?.result } };
|
|
550
1044
|
}
|
|
551
1045
|
);
|
|
@@ -555,42 +1049,81 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
555
1049
|
const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
556
1050
|
let execResults;
|
|
557
1051
|
let suspended;
|
|
1052
|
+
let bailed;
|
|
558
1053
|
try {
|
|
1054
|
+
if (validationError) {
|
|
1055
|
+
throw validationError;
|
|
1056
|
+
}
|
|
559
1057
|
const result = await step.execute({
|
|
1058
|
+
runId: executionContext.runId,
|
|
560
1059
|
mastra: this.mastra,
|
|
561
1060
|
runtimeContext,
|
|
562
|
-
|
|
1061
|
+
writableStream,
|
|
1062
|
+
inputData,
|
|
563
1063
|
resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const result2 = stepResults[step2.id];
|
|
567
|
-
if (result2?.status === "success") {
|
|
568
|
-
return result2.output;
|
|
569
|
-
}
|
|
570
|
-
return null;
|
|
1064
|
+
tracingContext: {
|
|
1065
|
+
currentSpan: stepAISpan
|
|
571
1066
|
},
|
|
1067
|
+
getInitData: () => stepResults?.input,
|
|
1068
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
572
1069
|
suspend: async (suspendPayload) => {
|
|
573
1070
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
574
1071
|
suspended = { payload: suspendPayload };
|
|
575
1072
|
},
|
|
1073
|
+
bail: (result2) => {
|
|
1074
|
+
bailed = { payload: result2 };
|
|
1075
|
+
},
|
|
576
1076
|
resume: {
|
|
577
1077
|
steps: resume?.steps?.slice(1) || [],
|
|
578
1078
|
resumePayload: resume?.resumePayload,
|
|
579
1079
|
// @ts-ignore
|
|
580
1080
|
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
|
|
581
1081
|
},
|
|
582
|
-
emitter
|
|
1082
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1083
|
+
engine: {
|
|
1084
|
+
step: this.inngestStep
|
|
1085
|
+
},
|
|
1086
|
+
abortSignal: abortController.signal
|
|
583
1087
|
});
|
|
584
|
-
|
|
1088
|
+
const endedAt = Date.now();
|
|
1089
|
+
execResults = {
|
|
1090
|
+
status: "success",
|
|
1091
|
+
output: result,
|
|
1092
|
+
startedAt,
|
|
1093
|
+
endedAt,
|
|
1094
|
+
payload: inputData,
|
|
1095
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1096
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1097
|
+
};
|
|
585
1098
|
} catch (e) {
|
|
586
|
-
execResults = {
|
|
1099
|
+
execResults = {
|
|
1100
|
+
status: "failed",
|
|
1101
|
+
payload: inputData,
|
|
1102
|
+
error: e instanceof Error ? e.message : String(e),
|
|
1103
|
+
endedAt: Date.now(),
|
|
1104
|
+
startedAt,
|
|
1105
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1106
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1107
|
+
};
|
|
587
1108
|
}
|
|
588
1109
|
if (suspended) {
|
|
589
|
-
execResults = {
|
|
1110
|
+
execResults = {
|
|
1111
|
+
status: "suspended",
|
|
1112
|
+
suspendedPayload: suspended.payload,
|
|
1113
|
+
payload: inputData,
|
|
1114
|
+
suspendedAt: Date.now(),
|
|
1115
|
+
startedAt,
|
|
1116
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1117
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1118
|
+
};
|
|
1119
|
+
} else if (bailed) {
|
|
1120
|
+
execResults = { status: "bailed", output: bailed.payload, payload: inputData, endedAt: Date.now(), startedAt };
|
|
590
1121
|
}
|
|
591
1122
|
if (execResults.status === "failed") {
|
|
592
1123
|
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
593
|
-
|
|
1124
|
+
const error = new Error(execResults.error);
|
|
1125
|
+
stepAISpan?.error({ error });
|
|
1126
|
+
throw error;
|
|
594
1127
|
}
|
|
595
1128
|
}
|
|
596
1129
|
await emitter.emit("watch", {
|
|
@@ -598,20 +1131,61 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
598
1131
|
payload: {
|
|
599
1132
|
currentStep: {
|
|
600
1133
|
id: step.id,
|
|
601
|
-
|
|
602
|
-
output: execResults.output
|
|
1134
|
+
...execResults
|
|
603
1135
|
},
|
|
604
1136
|
workflowState: {
|
|
605
1137
|
status: "running",
|
|
606
|
-
steps: stepResults,
|
|
1138
|
+
steps: { ...stepResults, [step.id]: execResults },
|
|
607
1139
|
result: null,
|
|
608
1140
|
error: null
|
|
609
1141
|
}
|
|
610
1142
|
},
|
|
611
1143
|
eventTimestamp: Date.now()
|
|
612
1144
|
});
|
|
1145
|
+
if (execResults.status === "suspended") {
|
|
1146
|
+
await emitter.emit("watch-v2", {
|
|
1147
|
+
type: "workflow-step-suspended",
|
|
1148
|
+
payload: {
|
|
1149
|
+
id: step.id,
|
|
1150
|
+
...execResults
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
} else {
|
|
1154
|
+
await emitter.emit("watch-v2", {
|
|
1155
|
+
type: "workflow-step-result",
|
|
1156
|
+
payload: {
|
|
1157
|
+
id: step.id,
|
|
1158
|
+
...execResults
|
|
1159
|
+
}
|
|
1160
|
+
});
|
|
1161
|
+
await emitter.emit("watch-v2", {
|
|
1162
|
+
type: "workflow-step-finish",
|
|
1163
|
+
payload: {
|
|
1164
|
+
id: step.id,
|
|
1165
|
+
metadata: {}
|
|
1166
|
+
}
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
stepAISpan?.end({ output: execResults });
|
|
613
1170
|
return { result: execResults, executionContext, stepResults };
|
|
614
1171
|
});
|
|
1172
|
+
if (disableScorers !== false) {
|
|
1173
|
+
await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
|
|
1174
|
+
if (step.scorers) {
|
|
1175
|
+
await this.runScorers({
|
|
1176
|
+
scorers: step.scorers,
|
|
1177
|
+
runId: executionContext.runId,
|
|
1178
|
+
input: inputData,
|
|
1179
|
+
output: stepRes.result,
|
|
1180
|
+
workflowId: executionContext.workflowId,
|
|
1181
|
+
stepId: step.id,
|
|
1182
|
+
runtimeContext,
|
|
1183
|
+
disableScorers,
|
|
1184
|
+
tracingContext: { currentSpan: stepAISpan }
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
615
1189
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
616
1190
|
Object.assign(stepResults, stepRes.stepResults);
|
|
617
1191
|
return stepRes.result;
|
|
@@ -620,7 +1194,12 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
620
1194
|
workflowId,
|
|
621
1195
|
runId,
|
|
622
1196
|
stepResults,
|
|
623
|
-
|
|
1197
|
+
resourceId,
|
|
1198
|
+
executionContext,
|
|
1199
|
+
serializedStepGraph,
|
|
1200
|
+
workflowStatus,
|
|
1201
|
+
result,
|
|
1202
|
+
error
|
|
624
1203
|
}) {
|
|
625
1204
|
await this.inngestStep.run(
|
|
626
1205
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
@@ -628,12 +1207,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
628
1207
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
629
1208
|
workflowName: workflowId,
|
|
630
1209
|
runId,
|
|
1210
|
+
resourceId,
|
|
631
1211
|
snapshot: {
|
|
632
1212
|
runId,
|
|
633
1213
|
value: {},
|
|
634
1214
|
context: stepResults,
|
|
635
1215
|
activePaths: [],
|
|
636
1216
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1217
|
+
waitingPaths: {},
|
|
1218
|
+
serializedStepGraph,
|
|
1219
|
+
status: workflowStatus,
|
|
1220
|
+
result,
|
|
1221
|
+
error,
|
|
637
1222
|
// @ts-ignore
|
|
638
1223
|
timestamp: Date.now()
|
|
639
1224
|
}
|
|
@@ -648,50 +1233,109 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
648
1233
|
prevOutput,
|
|
649
1234
|
prevStep,
|
|
650
1235
|
stepResults,
|
|
1236
|
+
serializedStepGraph,
|
|
651
1237
|
resume,
|
|
652
1238
|
executionContext,
|
|
653
1239
|
emitter,
|
|
654
|
-
|
|
1240
|
+
abortController,
|
|
1241
|
+
runtimeContext,
|
|
1242
|
+
writableStream,
|
|
1243
|
+
disableScorers,
|
|
1244
|
+
tracingContext
|
|
655
1245
|
}) {
|
|
1246
|
+
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1247
|
+
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
|
|
1248
|
+
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1249
|
+
input: prevOutput,
|
|
1250
|
+
attributes: {
|
|
1251
|
+
conditionCount: entry.conditions.length
|
|
1252
|
+
},
|
|
1253
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1254
|
+
});
|
|
656
1255
|
let execResults;
|
|
657
1256
|
const truthyIndexes = (await Promise.all(
|
|
658
1257
|
entry.conditions.map(
|
|
659
1258
|
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1259
|
+
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1260
|
+
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1261
|
+
name: `condition: '${index}'`,
|
|
1262
|
+
input: prevOutput,
|
|
1263
|
+
attributes: {
|
|
1264
|
+
conditionIndex: index
|
|
1265
|
+
},
|
|
1266
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1267
|
+
});
|
|
660
1268
|
try {
|
|
661
1269
|
const result = await cond({
|
|
1270
|
+
runId,
|
|
1271
|
+
workflowId,
|
|
662
1272
|
mastra: this.mastra,
|
|
663
1273
|
runtimeContext,
|
|
1274
|
+
runCount: -1,
|
|
664
1275
|
inputData: prevOutput,
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
if (!step?.id) {
|
|
668
|
-
return null;
|
|
669
|
-
}
|
|
670
|
-
const result2 = stepResults[step.id];
|
|
671
|
-
if (result2?.status === "success") {
|
|
672
|
-
return result2.output;
|
|
673
|
-
}
|
|
674
|
-
return null;
|
|
1276
|
+
tracingContext: {
|
|
1277
|
+
currentSpan: evalSpan
|
|
675
1278
|
},
|
|
1279
|
+
getInitData: () => stepResults?.input,
|
|
1280
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
676
1281
|
// TODO: this function shouldn't have suspend probably?
|
|
677
1282
|
suspend: async (_suspendPayload) => {
|
|
678
1283
|
},
|
|
679
|
-
|
|
1284
|
+
bail: () => {
|
|
1285
|
+
},
|
|
1286
|
+
abort: () => {
|
|
1287
|
+
abortController.abort();
|
|
1288
|
+
},
|
|
1289
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1290
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1291
|
+
// TODO: add streamVNext support
|
|
1292
|
+
engine: {
|
|
1293
|
+
step: this.inngestStep
|
|
1294
|
+
},
|
|
1295
|
+
abortSignal: abortController.signal,
|
|
1296
|
+
writer: new tools.ToolStream(
|
|
1297
|
+
{
|
|
1298
|
+
prefix: "workflow-step",
|
|
1299
|
+
callId: crypto.randomUUID(),
|
|
1300
|
+
name: "conditional",
|
|
1301
|
+
runId
|
|
1302
|
+
},
|
|
1303
|
+
writableStream
|
|
1304
|
+
)
|
|
1305
|
+
});
|
|
1306
|
+
evalSpan?.end({
|
|
1307
|
+
output: result,
|
|
1308
|
+
attributes: {
|
|
1309
|
+
result: !!result
|
|
1310
|
+
}
|
|
680
1311
|
});
|
|
681
1312
|
return result ? index : null;
|
|
682
1313
|
} catch (e) {
|
|
1314
|
+
evalSpan?.error({
|
|
1315
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
1316
|
+
attributes: {
|
|
1317
|
+
result: false
|
|
1318
|
+
}
|
|
1319
|
+
});
|
|
683
1320
|
return null;
|
|
684
1321
|
}
|
|
685
1322
|
})
|
|
686
1323
|
)
|
|
687
1324
|
)).filter((index) => index !== null);
|
|
688
1325
|
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
1326
|
+
conditionalSpan?.update({
|
|
1327
|
+
attributes: {
|
|
1328
|
+
truthyIndexes,
|
|
1329
|
+
selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
|
|
1330
|
+
}
|
|
1331
|
+
});
|
|
689
1332
|
const results = await Promise.all(
|
|
690
1333
|
stepsToRun.map(
|
|
691
1334
|
(step, index) => this.executeEntry({
|
|
692
1335
|
workflowId,
|
|
693
1336
|
runId,
|
|
694
1337
|
entry: step,
|
|
1338
|
+
serializedStepGraph,
|
|
695
1339
|
prevStep,
|
|
696
1340
|
stepResults,
|
|
697
1341
|
resume,
|
|
@@ -704,27 +1348,42 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
704
1348
|
executionSpan: executionContext.executionSpan
|
|
705
1349
|
},
|
|
706
1350
|
emitter,
|
|
707
|
-
|
|
1351
|
+
abortController,
|
|
1352
|
+
runtimeContext,
|
|
1353
|
+
writableStream,
|
|
1354
|
+
disableScorers,
|
|
1355
|
+
tracingContext: {
|
|
1356
|
+
currentSpan: conditionalSpan
|
|
1357
|
+
}
|
|
708
1358
|
})
|
|
709
1359
|
)
|
|
710
1360
|
);
|
|
711
|
-
const hasFailed = results.find((result) => result.status === "failed");
|
|
712
|
-
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
1361
|
+
const hasFailed = results.find((result) => result.result.status === "failed");
|
|
1362
|
+
const hasSuspended = results.find((result) => result.result.status === "suspended");
|
|
713
1363
|
if (hasFailed) {
|
|
714
|
-
execResults = { status: "failed", error: hasFailed.error };
|
|
1364
|
+
execResults = { status: "failed", error: hasFailed.result.error };
|
|
715
1365
|
} else if (hasSuspended) {
|
|
716
|
-
execResults = { status: "suspended", payload: hasSuspended.
|
|
1366
|
+
execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
|
|
717
1367
|
} else {
|
|
718
1368
|
execResults = {
|
|
719
1369
|
status: "success",
|
|
720
1370
|
output: results.reduce((acc, result, index) => {
|
|
721
|
-
if (result.status === "success") {
|
|
1371
|
+
if (result.result.status === "success") {
|
|
722
1372
|
acc[stepsToRun[index].step.id] = result.output;
|
|
723
1373
|
}
|
|
724
1374
|
return acc;
|
|
725
1375
|
}, {})
|
|
726
1376
|
};
|
|
727
1377
|
}
|
|
1378
|
+
if (execResults.status === "failed") {
|
|
1379
|
+
conditionalSpan?.error({
|
|
1380
|
+
error: new Error(execResults.error)
|
|
1381
|
+
});
|
|
1382
|
+
} else {
|
|
1383
|
+
conditionalSpan?.end({
|
|
1384
|
+
output: execResults.output || execResults
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
728
1387
|
return execResults;
|
|
729
1388
|
}
|
|
730
1389
|
};
|
|
@@ -732,5 +1391,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
732
1391
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
733
1392
|
exports.InngestRun = InngestRun;
|
|
734
1393
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1394
|
+
exports.createStep = createStep;
|
|
735
1395
|
exports.init = init;
|
|
736
1396
|
exports.serve = serve;
|
|
1397
|
+
//# sourceMappingURL=index.cjs.map
|
|
1398
|
+
//# sourceMappingURL=index.cjs.map
|