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