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