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