@mastra/inngest 0.0.0-redis-cloud-transporter-20250508203756 → 0.0.0-roamin-openaivoice-speak-options-passing-20250926163614
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 +1154 -2
- package/LICENSE.md +11 -42
- package/dist/index.cjs +772 -109
- 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 +769 -107
- package/dist/index.js.map +1 -0
- package/package.json +39 -20
- 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,34 +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 { 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';
|
|
5
8
|
import { serve as serve$1 } from 'inngest/hono';
|
|
9
|
+
import { z } from 'zod';
|
|
6
10
|
|
|
7
11
|
// src/index.ts
|
|
8
|
-
function serve({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
function serve({
|
|
13
|
+
mastra,
|
|
14
|
+
inngest,
|
|
15
|
+
functions: userFunctions = [],
|
|
16
|
+
registerOptions
|
|
17
|
+
}) {
|
|
18
|
+
const wfs = mastra.getWorkflows();
|
|
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
|
+
);
|
|
17
30
|
return serve$1({
|
|
31
|
+
...registerOptions,
|
|
18
32
|
client: inngest,
|
|
19
|
-
functions
|
|
33
|
+
functions: [...workflowFunctions, ...userFunctions]
|
|
20
34
|
});
|
|
21
35
|
}
|
|
22
36
|
var InngestRun = class extends Run {
|
|
23
37
|
inngest;
|
|
38
|
+
serializedStepGraph;
|
|
24
39
|
#mastra;
|
|
25
40
|
constructor(params, inngest) {
|
|
26
41
|
super(params);
|
|
27
42
|
this.inngest = inngest;
|
|
43
|
+
this.serializedStepGraph = params.serializedStepGraph;
|
|
28
44
|
this.#mastra = params.mastra;
|
|
29
45
|
}
|
|
30
46
|
async getRuns(eventId) {
|
|
31
|
-
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`, {
|
|
32
48
|
headers: {
|
|
33
49
|
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
34
50
|
}
|
|
@@ -38,35 +54,76 @@ var InngestRun = class extends Run {
|
|
|
38
54
|
}
|
|
39
55
|
async getRunOutput(eventId) {
|
|
40
56
|
let runs = await this.getRuns(eventId);
|
|
41
|
-
while (runs?.[0]?.status !== "Completed") {
|
|
57
|
+
while (runs?.[0]?.status !== "Completed" || runs?.[0]?.event_id !== eventId) {
|
|
42
58
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
43
59
|
runs = await this.getRuns(eventId);
|
|
44
|
-
if (runs?.[0]?.status === "Failed"
|
|
60
|
+
if (runs?.[0]?.status === "Failed") {
|
|
45
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" } } };
|
|
46
68
|
}
|
|
47
69
|
}
|
|
48
70
|
return runs?.[0];
|
|
49
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
|
+
}
|
|
50
101
|
async start({
|
|
51
102
|
inputData
|
|
52
103
|
}) {
|
|
53
104
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
54
105
|
workflowName: this.workflowId,
|
|
55
106
|
runId: this.runId,
|
|
107
|
+
resourceId: this.resourceId,
|
|
56
108
|
snapshot: {
|
|
57
109
|
runId: this.runId,
|
|
110
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
58
111
|
value: {},
|
|
59
112
|
context: {},
|
|
60
113
|
activePaths: [],
|
|
61
114
|
suspendedPaths: {},
|
|
62
|
-
|
|
115
|
+
waitingPaths: {},
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
status: "running"
|
|
63
118
|
}
|
|
64
119
|
});
|
|
120
|
+
const inputDataToUse = await this._validateInput(inputData);
|
|
65
121
|
const eventOutput = await this.inngest.send({
|
|
66
122
|
name: `workflow.${this.workflowId}`,
|
|
67
123
|
data: {
|
|
68
|
-
inputData,
|
|
69
|
-
runId: this.runId
|
|
124
|
+
inputData: inputDataToUse,
|
|
125
|
+
runId: this.runId,
|
|
126
|
+
resourceId: this.resourceId
|
|
70
127
|
}
|
|
71
128
|
});
|
|
72
129
|
const eventId = eventOutput.ids[0];
|
|
@@ -78,10 +135,23 @@ var InngestRun = class extends Run {
|
|
|
78
135
|
if (result.status === "failed") {
|
|
79
136
|
result.error = new Error(result.error);
|
|
80
137
|
}
|
|
81
|
-
|
|
138
|
+
if (result.status !== "suspended") {
|
|
139
|
+
this.cleanup?.();
|
|
140
|
+
}
|
|
82
141
|
return result;
|
|
83
142
|
}
|
|
84
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) {
|
|
85
155
|
const steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
86
156
|
(step) => typeof step === "string" ? step : step?.id
|
|
87
157
|
);
|
|
@@ -89,16 +159,19 @@ var InngestRun = class extends Run {
|
|
|
89
159
|
workflowName: this.workflowId,
|
|
90
160
|
runId: this.runId
|
|
91
161
|
});
|
|
162
|
+
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
163
|
+
const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
|
|
92
164
|
const eventOutput = await this.inngest.send({
|
|
93
165
|
name: `workflow.${this.workflowId}`,
|
|
94
166
|
data: {
|
|
95
|
-
inputData:
|
|
167
|
+
inputData: resumeDataToUse,
|
|
96
168
|
runId: this.runId,
|
|
169
|
+
workflowId: this.workflowId,
|
|
97
170
|
stepResults: snapshot?.context,
|
|
98
171
|
resume: {
|
|
99
172
|
steps,
|
|
100
173
|
stepResults: snapshot?.context,
|
|
101
|
-
resumePayload:
|
|
174
|
+
resumePayload: resumeDataToUse,
|
|
102
175
|
// @ts-ignore
|
|
103
176
|
resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
|
|
104
177
|
}
|
|
@@ -115,32 +188,77 @@ var InngestRun = class extends Run {
|
|
|
115
188
|
}
|
|
116
189
|
return result;
|
|
117
190
|
}
|
|
118
|
-
watch(cb) {
|
|
191
|
+
watch(cb, type = "watch") {
|
|
192
|
+
let active = true;
|
|
119
193
|
const streamPromise = subscribe(
|
|
120
194
|
{
|
|
121
195
|
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
122
|
-
topics: [
|
|
196
|
+
topics: [type],
|
|
123
197
|
app: this.inngest
|
|
124
198
|
},
|
|
125
199
|
(message) => {
|
|
126
|
-
|
|
200
|
+
if (active) {
|
|
201
|
+
cb(message.data);
|
|
202
|
+
}
|
|
127
203
|
}
|
|
128
204
|
);
|
|
129
205
|
return () => {
|
|
130
|
-
|
|
131
|
-
|
|
206
|
+
active = false;
|
|
207
|
+
streamPromise.then(async (stream) => {
|
|
208
|
+
return stream.cancel();
|
|
132
209
|
}).catch((err) => {
|
|
133
210
|
console.error(err);
|
|
134
211
|
});
|
|
135
212
|
};
|
|
136
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
|
+
}
|
|
137
249
|
};
|
|
138
|
-
var InngestWorkflow = class _InngestWorkflow extends
|
|
250
|
+
var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
139
251
|
#mastra;
|
|
140
252
|
inngest;
|
|
141
253
|
function;
|
|
254
|
+
flowControlConfig;
|
|
142
255
|
constructor(params, inngest) {
|
|
143
|
-
|
|
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;
|
|
144
262
|
this.#mastra = params.mastra;
|
|
145
263
|
this.inngest = inngest;
|
|
146
264
|
}
|
|
@@ -156,7 +274,7 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
156
274
|
const storage = this.#mastra?.getStorage();
|
|
157
275
|
if (!storage) {
|
|
158
276
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
159
|
-
return null;
|
|
277
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
160
278
|
}
|
|
161
279
|
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
162
280
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
@@ -179,21 +297,55 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
179
297
|
}
|
|
180
298
|
}
|
|
181
299
|
}
|
|
182
|
-
|
|
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) {
|
|
183
310
|
const runIdToUse = options?.runId || randomUUID();
|
|
184
311
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
185
312
|
{
|
|
186
313
|
workflowId: this.id,
|
|
187
314
|
runId: runIdToUse,
|
|
315
|
+
resourceId: options?.resourceId,
|
|
188
316
|
executionEngine: this.executionEngine,
|
|
189
317
|
executionGraph: this.executionGraph,
|
|
318
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
190
319
|
mastra: this.#mastra,
|
|
191
320
|
retryConfig: this.retryConfig,
|
|
192
|
-
cleanup: () => this.runs.delete(runIdToUse)
|
|
321
|
+
cleanup: () => this.runs.delete(runIdToUse),
|
|
322
|
+
workflowSteps: this.steps
|
|
193
323
|
},
|
|
194
324
|
this.inngest
|
|
195
325
|
);
|
|
196
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
|
+
}
|
|
197
349
|
return run;
|
|
198
350
|
}
|
|
199
351
|
getFunction() {
|
|
@@ -201,11 +353,17 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
201
353
|
return this.function;
|
|
202
354
|
}
|
|
203
355
|
this.function = this.inngest.createFunction(
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
},
|
|
206
364
|
{ event: `workflow.${this.id}` },
|
|
207
365
|
async ({ event, step, attempt, publish }) => {
|
|
208
|
-
let { inputData, runId, resume } = event.data;
|
|
366
|
+
let { inputData, runId, resourceId, resume } = event.data;
|
|
209
367
|
if (!runId) {
|
|
210
368
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
211
369
|
return randomUUID();
|
|
@@ -219,25 +377,36 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
219
377
|
try {
|
|
220
378
|
await publish({
|
|
221
379
|
channel: `workflow:${this.id}:${runId}`,
|
|
222
|
-
topic:
|
|
380
|
+
topic: event2,
|
|
223
381
|
data
|
|
224
382
|
});
|
|
225
383
|
} catch (err) {
|
|
226
384
|
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
227
385
|
}
|
|
386
|
+
},
|
|
387
|
+
on: (_event, _callback) => {
|
|
388
|
+
},
|
|
389
|
+
off: (_event, _callback) => {
|
|
390
|
+
},
|
|
391
|
+
once: (_event, _callback) => {
|
|
228
392
|
}
|
|
229
393
|
};
|
|
230
394
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
231
395
|
const result = await engine.execute({
|
|
232
396
|
workflowId: this.id,
|
|
233
397
|
runId,
|
|
398
|
+
resourceId,
|
|
234
399
|
graph: this.executionGraph,
|
|
400
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
235
401
|
input: inputData,
|
|
236
402
|
emitter,
|
|
237
403
|
retryConfig: this.retryConfig,
|
|
238
404
|
runtimeContext: new RuntimeContext(),
|
|
239
405
|
// TODO
|
|
240
|
-
resume
|
|
406
|
+
resume,
|
|
407
|
+
abortController: new AbortController(),
|
|
408
|
+
currentSpan: void 0
|
|
409
|
+
// TODO: Pass actual parent AI span from workflow execution context
|
|
241
410
|
});
|
|
242
411
|
return { result, runId };
|
|
243
412
|
}
|
|
@@ -261,20 +430,103 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
261
430
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
262
431
|
}
|
|
263
432
|
};
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
+
};
|
|
278
530
|
}
|
|
279
531
|
function init(inngest) {
|
|
280
532
|
return {
|
|
@@ -282,18 +534,50 @@ function init(inngest) {
|
|
|
282
534
|
return new InngestWorkflow(params, inngest);
|
|
283
535
|
},
|
|
284
536
|
createStep,
|
|
285
|
-
cloneStep,
|
|
286
|
-
|
|
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
|
+
}
|
|
287
559
|
};
|
|
288
560
|
}
|
|
289
561
|
var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
290
562
|
inngestStep;
|
|
291
563
|
inngestAttempts;
|
|
292
|
-
constructor(mastra, inngestStep, inngestAttempts = 0) {
|
|
293
|
-
super({ mastra });
|
|
564
|
+
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
565
|
+
super({ mastra, options });
|
|
294
566
|
this.inngestStep = inngestStep;
|
|
295
567
|
this.inngestAttempts = inngestAttempts;
|
|
296
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
|
+
}
|
|
297
581
|
async fmtReturnValue(executionSpan, emitter, stepResults, lastOutput, error) {
|
|
298
582
|
const base = {
|
|
299
583
|
status: lastOutput.status,
|
|
@@ -351,28 +635,179 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
351
635
|
executionSpan?.end();
|
|
352
636
|
return base;
|
|
353
637
|
}
|
|
354
|
-
async
|
|
638
|
+
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
639
|
+
// await this.inngestStep.sleep(id, duration);
|
|
640
|
+
// }
|
|
641
|
+
async executeSleep({
|
|
355
642
|
workflowId,
|
|
356
643
|
runId,
|
|
357
|
-
|
|
644
|
+
entry,
|
|
645
|
+
prevOutput,
|
|
358
646
|
stepResults,
|
|
647
|
+
emitter,
|
|
648
|
+
abortController,
|
|
649
|
+
runtimeContext,
|
|
359
650
|
executionContext,
|
|
360
|
-
|
|
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,
|
|
361
721
|
prevOutput,
|
|
722
|
+
stepResults,
|
|
362
723
|
emitter,
|
|
363
|
-
|
|
724
|
+
abortController,
|
|
725
|
+
runtimeContext,
|
|
726
|
+
executionContext,
|
|
727
|
+
writableStream,
|
|
728
|
+
tracingContext
|
|
364
729
|
}) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
|
375
806
|
});
|
|
807
|
+
if (eventData === null) {
|
|
808
|
+
throw "Timeout waiting for event";
|
|
809
|
+
}
|
|
810
|
+
return eventData?.data;
|
|
376
811
|
}
|
|
377
812
|
async executeStep({
|
|
378
813
|
step,
|
|
@@ -381,11 +816,30 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
381
816
|
resume,
|
|
382
817
|
prevOutput,
|
|
383
818
|
emitter,
|
|
384
|
-
|
|
819
|
+
abortController,
|
|
820
|
+
runtimeContext,
|
|
821
|
+
tracingContext,
|
|
822
|
+
writableStream,
|
|
823
|
+
disableScorers
|
|
385
824
|
}) {
|
|
386
|
-
|
|
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(
|
|
387
840
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
388
841
|
async () => {
|
|
842
|
+
const startedAt2 = Date.now();
|
|
389
843
|
await emitter.emit("watch", {
|
|
390
844
|
type: "watch",
|
|
391
845
|
payload: {
|
|
@@ -407,6 +861,16 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
407
861
|
},
|
|
408
862
|
eventTimestamp: Date.now()
|
|
409
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;
|
|
410
874
|
}
|
|
411
875
|
);
|
|
412
876
|
if (step instanceof InngestWorkflow) {
|
|
@@ -422,7 +886,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
422
886
|
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
423
887
|
function: step.getFunction(),
|
|
424
888
|
data: {
|
|
425
|
-
inputData
|
|
889
|
+
inputData,
|
|
426
890
|
runId,
|
|
427
891
|
resume: {
|
|
428
892
|
runId,
|
|
@@ -440,7 +904,7 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
440
904
|
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
441
905
|
function: step.getFunction(),
|
|
442
906
|
data: {
|
|
443
|
-
inputData
|
|
907
|
+
inputData
|
|
444
908
|
}
|
|
445
909
|
});
|
|
446
910
|
result = invokeResp.result;
|
|
@@ -467,6 +931,15 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
467
931
|
},
|
|
468
932
|
eventTimestamp: Date.now()
|
|
469
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
|
+
});
|
|
470
943
|
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
471
944
|
} else if (result.status === "suspended") {
|
|
472
945
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
@@ -493,6 +966,13 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
493
966
|
},
|
|
494
967
|
eventTimestamp: Date.now()
|
|
495
968
|
});
|
|
969
|
+
await emitter.emit("watch-v2", {
|
|
970
|
+
type: "workflow-step-suspended",
|
|
971
|
+
payload: {
|
|
972
|
+
id: step.id,
|
|
973
|
+
status: "suspended"
|
|
974
|
+
}
|
|
975
|
+
});
|
|
496
976
|
return {
|
|
497
977
|
executionContext,
|
|
498
978
|
result: {
|
|
@@ -543,6 +1023,21 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
543
1023
|
},
|
|
544
1024
|
eventTimestamp: Date.now()
|
|
545
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
|
+
});
|
|
546
1041
|
return { executionContext, result: { status: "success", output: result?.result } };
|
|
547
1042
|
}
|
|
548
1043
|
);
|
|
@@ -552,42 +1047,81 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
552
1047
|
const stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
553
1048
|
let execResults;
|
|
554
1049
|
let suspended;
|
|
1050
|
+
let bailed;
|
|
555
1051
|
try {
|
|
1052
|
+
if (validationError) {
|
|
1053
|
+
throw validationError;
|
|
1054
|
+
}
|
|
556
1055
|
const result = await step.execute({
|
|
1056
|
+
runId: executionContext.runId,
|
|
557
1057
|
mastra: this.mastra,
|
|
558
1058
|
runtimeContext,
|
|
559
|
-
|
|
1059
|
+
writableStream,
|
|
1060
|
+
inputData,
|
|
560
1061
|
resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const result2 = stepResults[step2.id];
|
|
564
|
-
if (result2?.status === "success") {
|
|
565
|
-
return result2.output;
|
|
566
|
-
}
|
|
567
|
-
return null;
|
|
1062
|
+
tracingContext: {
|
|
1063
|
+
currentSpan: stepAISpan
|
|
568
1064
|
},
|
|
1065
|
+
getInitData: () => stepResults?.input,
|
|
1066
|
+
getStepResult: getStepResult.bind(this, stepResults),
|
|
569
1067
|
suspend: async (suspendPayload) => {
|
|
570
1068
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
571
1069
|
suspended = { payload: suspendPayload };
|
|
572
1070
|
},
|
|
1071
|
+
bail: (result2) => {
|
|
1072
|
+
bailed = { payload: result2 };
|
|
1073
|
+
},
|
|
573
1074
|
resume: {
|
|
574
1075
|
steps: resume?.steps?.slice(1) || [],
|
|
575
1076
|
resumePayload: resume?.resumePayload,
|
|
576
1077
|
// @ts-ignore
|
|
577
1078
|
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
|
|
578
1079
|
},
|
|
579
|
-
emitter
|
|
1080
|
+
[EMITTER_SYMBOL]: emitter,
|
|
1081
|
+
engine: {
|
|
1082
|
+
step: this.inngestStep
|
|
1083
|
+
},
|
|
1084
|
+
abortSignal: abortController.signal
|
|
580
1085
|
});
|
|
581
|
-
|
|
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
|
+
};
|
|
582
1096
|
} catch (e) {
|
|
583
|
-
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
|
+
};
|
|
584
1106
|
}
|
|
585
1107
|
if (suspended) {
|
|
586
|
-
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 };
|
|
587
1119
|
}
|
|
588
1120
|
if (execResults.status === "failed") {
|
|
589
1121
|
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
590
|
-
|
|
1122
|
+
const error = new Error(execResults.error);
|
|
1123
|
+
stepAISpan?.error({ error });
|
|
1124
|
+
throw error;
|
|
591
1125
|
}
|
|
592
1126
|
}
|
|
593
1127
|
await emitter.emit("watch", {
|
|
@@ -595,20 +1129,61 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
595
1129
|
payload: {
|
|
596
1130
|
currentStep: {
|
|
597
1131
|
id: step.id,
|
|
598
|
-
|
|
599
|
-
output: execResults.output
|
|
1132
|
+
...execResults
|
|
600
1133
|
},
|
|
601
1134
|
workflowState: {
|
|
602
1135
|
status: "running",
|
|
603
|
-
steps: stepResults,
|
|
1136
|
+
steps: { ...stepResults, [step.id]: execResults },
|
|
604
1137
|
result: null,
|
|
605
1138
|
error: null
|
|
606
1139
|
}
|
|
607
1140
|
},
|
|
608
1141
|
eventTimestamp: Date.now()
|
|
609
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 });
|
|
610
1168
|
return { result: execResults, executionContext, stepResults };
|
|
611
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
|
+
}
|
|
612
1187
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
613
1188
|
Object.assign(stepResults, stepRes.stepResults);
|
|
614
1189
|
return stepRes.result;
|
|
@@ -617,7 +1192,12 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
617
1192
|
workflowId,
|
|
618
1193
|
runId,
|
|
619
1194
|
stepResults,
|
|
620
|
-
|
|
1195
|
+
resourceId,
|
|
1196
|
+
executionContext,
|
|
1197
|
+
serializedStepGraph,
|
|
1198
|
+
workflowStatus,
|
|
1199
|
+
result,
|
|
1200
|
+
error
|
|
621
1201
|
}) {
|
|
622
1202
|
await this.inngestStep.run(
|
|
623
1203
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
@@ -625,12 +1205,18 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
625
1205
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
626
1206
|
workflowName: workflowId,
|
|
627
1207
|
runId,
|
|
1208
|
+
resourceId,
|
|
628
1209
|
snapshot: {
|
|
629
1210
|
runId,
|
|
630
1211
|
value: {},
|
|
631
1212
|
context: stepResults,
|
|
632
1213
|
activePaths: [],
|
|
633
1214
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1215
|
+
waitingPaths: {},
|
|
1216
|
+
serializedStepGraph,
|
|
1217
|
+
status: workflowStatus,
|
|
1218
|
+
result,
|
|
1219
|
+
error,
|
|
634
1220
|
// @ts-ignore
|
|
635
1221
|
timestamp: Date.now()
|
|
636
1222
|
}
|
|
@@ -645,50 +1231,109 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
645
1231
|
prevOutput,
|
|
646
1232
|
prevStep,
|
|
647
1233
|
stepResults,
|
|
1234
|
+
serializedStepGraph,
|
|
648
1235
|
resume,
|
|
649
1236
|
executionContext,
|
|
650
1237
|
emitter,
|
|
651
|
-
|
|
1238
|
+
abortController,
|
|
1239
|
+
runtimeContext,
|
|
1240
|
+
writableStream,
|
|
1241
|
+
disableScorers,
|
|
1242
|
+
tracingContext
|
|
652
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
|
+
});
|
|
653
1253
|
let execResults;
|
|
654
1254
|
const truthyIndexes = (await Promise.all(
|
|
655
1255
|
entry.conditions.map(
|
|
656
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
|
+
});
|
|
657
1266
|
try {
|
|
658
1267
|
const result = await cond({
|
|
1268
|
+
runId,
|
|
1269
|
+
workflowId,
|
|
659
1270
|
mastra: this.mastra,
|
|
660
1271
|
runtimeContext,
|
|
1272
|
+
runCount: -1,
|
|
661
1273
|
inputData: prevOutput,
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
if (!step?.id) {
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
667
|
-
const result2 = stepResults[step.id];
|
|
668
|
-
if (result2?.status === "success") {
|
|
669
|
-
return result2.output;
|
|
670
|
-
}
|
|
671
|
-
return null;
|
|
1274
|
+
tracingContext: {
|
|
1275
|
+
currentSpan: evalSpan
|
|
672
1276
|
},
|
|
1277
|
+
getInitData: () => stepResults?.input,
|
|
1278
|
+
getStepResult: getStepResult.bind(this, stepResults),
|
|
673
1279
|
// TODO: this function shouldn't have suspend probably?
|
|
674
1280
|
suspend: async (_suspendPayload) => {
|
|
675
1281
|
},
|
|
676
|
-
|
|
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
|
+
}
|
|
677
1309
|
});
|
|
678
1310
|
return result ? index : null;
|
|
679
1311
|
} catch (e) {
|
|
1312
|
+
evalSpan?.error({
|
|
1313
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
1314
|
+
attributes: {
|
|
1315
|
+
result: false
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
680
1318
|
return null;
|
|
681
1319
|
}
|
|
682
1320
|
})
|
|
683
1321
|
)
|
|
684
1322
|
)).filter((index) => index !== null);
|
|
685
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
|
+
});
|
|
686
1330
|
const results = await Promise.all(
|
|
687
1331
|
stepsToRun.map(
|
|
688
1332
|
(step, index) => this.executeEntry({
|
|
689
1333
|
workflowId,
|
|
690
1334
|
runId,
|
|
691
1335
|
entry: step,
|
|
1336
|
+
serializedStepGraph,
|
|
692
1337
|
prevStep,
|
|
693
1338
|
stepResults,
|
|
694
1339
|
resume,
|
|
@@ -701,29 +1346,46 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
701
1346
|
executionSpan: executionContext.executionSpan
|
|
702
1347
|
},
|
|
703
1348
|
emitter,
|
|
704
|
-
|
|
1349
|
+
abortController,
|
|
1350
|
+
runtimeContext,
|
|
1351
|
+
writableStream,
|
|
1352
|
+
disableScorers,
|
|
1353
|
+
tracingContext: {
|
|
1354
|
+
currentSpan: conditionalSpan
|
|
1355
|
+
}
|
|
705
1356
|
})
|
|
706
1357
|
)
|
|
707
1358
|
);
|
|
708
|
-
const hasFailed = results.find((result) => result.status === "failed");
|
|
709
|
-
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");
|
|
710
1361
|
if (hasFailed) {
|
|
711
|
-
execResults = { status: "failed", error: hasFailed.error };
|
|
1362
|
+
execResults = { status: "failed", error: hasFailed.result.error };
|
|
712
1363
|
} else if (hasSuspended) {
|
|
713
|
-
execResults = { status: "suspended", payload: hasSuspended.
|
|
1364
|
+
execResults = { status: "suspended", payload: hasSuspended.result.suspendPayload };
|
|
714
1365
|
} else {
|
|
715
1366
|
execResults = {
|
|
716
1367
|
status: "success",
|
|
717
1368
|
output: results.reduce((acc, result, index) => {
|
|
718
|
-
if (result.status === "success") {
|
|
1369
|
+
if (result.result.status === "success") {
|
|
719
1370
|
acc[stepsToRun[index].step.id] = result.output;
|
|
720
1371
|
}
|
|
721
1372
|
return acc;
|
|
722
1373
|
}, {})
|
|
723
1374
|
};
|
|
724
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
|
+
}
|
|
725
1385
|
return execResults;
|
|
726
1386
|
}
|
|
727
1387
|
};
|
|
728
1388
|
|
|
729
|
-
export { InngestExecutionEngine, InngestRun, InngestWorkflow, init, serve };
|
|
1389
|
+
export { InngestExecutionEngine, InngestRun, InngestWorkflow, createStep, init, serve };
|
|
1390
|
+
//# sourceMappingURL=index.js.map
|
|
1391
|
+
//# sourceMappingURL=index.js.map
|