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