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