@mastra/inngest 0.0.0-vnext-inngest-20250508131921 → 0.0.0-vnext-20251104230439
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1457 -2
- package/LICENSE.md +11 -42
- package/dist/index.cjs +1124 -317
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +317 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1122 -316
- package/dist/index.js.map +1 -0
- package/package.json +40 -21
- package/dist/_tsup-dts-rollup.d.cts +0 -194
- package/dist/_tsup-dts-rollup.d.ts +0 -194
- package/dist/index.d.cts +0 -5
- package/docker-compose.yaml +0 -10
- package/eslint.config.js +0 -6
- package/src/index.test.ts +0 -5437
- package/src/index.ts +0 -956
- package/tsconfig.json +0 -5
- package/vitest.config.ts +0 -8
package/dist/index.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,40 +224,175 @@ 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
|
}
|
|
147
|
-
async
|
|
383
|
+
async listWorkflowRuns(args) {
|
|
148
384
|
const storage = this.#mastra?.getStorage();
|
|
149
385
|
if (!storage) {
|
|
150
386
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
151
387
|
return { runs: [], total: 0 };
|
|
152
388
|
}
|
|
153
|
-
return storage.
|
|
389
|
+
return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
154
390
|
}
|
|
155
391
|
async getWorkflowRunById(runId) {
|
|
156
392
|
const storage = this.#mastra?.getStorage();
|
|
157
393
|
if (!storage) {
|
|
158
394
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
159
|
-
return null;
|
|
395
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
160
396
|
}
|
|
161
397
|
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
162
398
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
@@ -179,21 +415,51 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
179
415
|
}
|
|
180
416
|
}
|
|
181
417
|
}
|
|
182
|
-
createRun(options) {
|
|
418
|
+
async createRun(options) {
|
|
183
419
|
const runIdToUse = options?.runId || randomUUID();
|
|
184
420
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
185
421
|
{
|
|
186
422
|
workflowId: this.id,
|
|
187
423
|
runId: runIdToUse,
|
|
424
|
+
resourceId: options?.resourceId,
|
|
188
425
|
executionEngine: this.executionEngine,
|
|
189
426
|
executionGraph: this.executionGraph,
|
|
427
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
190
428
|
mastra: this.#mastra,
|
|
191
429
|
retryConfig: this.retryConfig,
|
|
192
|
-
cleanup: () => this.runs.delete(runIdToUse)
|
|
430
|
+
cleanup: () => this.runs.delete(runIdToUse),
|
|
431
|
+
workflowSteps: this.steps
|
|
193
432
|
},
|
|
194
433
|
this.inngest
|
|
195
434
|
);
|
|
196
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
|
+
}
|
|
197
463
|
return run;
|
|
198
464
|
}
|
|
199
465
|
getFunction() {
|
|
@@ -201,11 +467,17 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
201
467
|
return this.function;
|
|
202
468
|
}
|
|
203
469
|
this.function = this.inngest.createFunction(
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
},
|
|
206
478
|
{ event: `workflow.${this.id}` },
|
|
207
479
|
async ({ event, step, attempt, publish }) => {
|
|
208
|
-
let { inputData, runId, resume } = event.data;
|
|
480
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
|
|
209
481
|
if (!runId) {
|
|
210
482
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
211
483
|
return randomUUID();
|
|
@@ -219,25 +491,52 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
219
491
|
try {
|
|
220
492
|
await publish({
|
|
221
493
|
channel: `workflow:${this.id}:${runId}`,
|
|
222
|
-
topic:
|
|
494
|
+
topic: event2,
|
|
223
495
|
data
|
|
224
496
|
});
|
|
225
497
|
} catch (err) {
|
|
226
498
|
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
227
499
|
}
|
|
500
|
+
},
|
|
501
|
+
on: (_event, _callback) => {
|
|
502
|
+
},
|
|
503
|
+
off: (_event, _callback) => {
|
|
504
|
+
},
|
|
505
|
+
once: (_event, _callback) => {
|
|
228
506
|
}
|
|
229
507
|
};
|
|
230
|
-
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
508
|
+
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
231
509
|
const result = await engine.execute({
|
|
232
510
|
workflowId: this.id,
|
|
233
511
|
runId,
|
|
512
|
+
resourceId,
|
|
234
513
|
graph: this.executionGraph,
|
|
514
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
235
515
|
input: inputData,
|
|
516
|
+
initialState,
|
|
236
517
|
emitter,
|
|
237
518
|
retryConfig: this.retryConfig,
|
|
238
|
-
|
|
519
|
+
requestContext: new RequestContext(),
|
|
239
520
|
// TODO
|
|
240
|
-
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;
|
|
241
540
|
});
|
|
242
541
|
return { result, runId };
|
|
243
542
|
}
|
|
@@ -261,118 +560,403 @@ var InngestWorkflow = class _InngestWorkflow extends NewWorkflow {
|
|
|
261
560
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
262
561
|
}
|
|
263
562
|
};
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
+
};
|
|
278
697
|
}
|
|
279
698
|
function init(inngest) {
|
|
280
699
|
return {
|
|
281
700
|
createWorkflow(params) {
|
|
282
|
-
return new InngestWorkflow(
|
|
701
|
+
return new InngestWorkflow(
|
|
702
|
+
params,
|
|
703
|
+
inngest
|
|
704
|
+
);
|
|
283
705
|
},
|
|
284
706
|
createStep,
|
|
285
|
-
cloneStep,
|
|
286
|
-
|
|
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
|
+
}
|
|
287
732
|
};
|
|
288
733
|
}
|
|
289
734
|
var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
290
735
|
inngestStep;
|
|
291
736
|
inngestAttempts;
|
|
292
|
-
constructor(mastra, inngestStep, inngestAttempts = 0) {
|
|
293
|
-
super({ mastra });
|
|
737
|
+
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
738
|
+
super({ mastra, options });
|
|
294
739
|
this.inngestStep = inngestStep;
|
|
295
740
|
this.inngestAttempts = inngestAttempts;
|
|
296
741
|
}
|
|
297
|
-
async fmtReturnValue(
|
|
742
|
+
async fmtReturnValue(emitter, stepResults, lastOutput, error) {
|
|
298
743
|
const base = {
|
|
299
744
|
status: lastOutput.status,
|
|
300
745
|
steps: stepResults
|
|
301
746
|
};
|
|
302
747
|
if (lastOutput.status === "success") {
|
|
303
|
-
await emitter.emit("watch", {
|
|
304
|
-
type: "watch",
|
|
305
|
-
payload: {
|
|
306
|
-
workflowState: {
|
|
307
|
-
status: lastOutput.status,
|
|
308
|
-
steps: stepResults,
|
|
309
|
-
result: lastOutput.output
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
eventTimestamp: Date.now()
|
|
313
|
-
});
|
|
314
748
|
base.result = lastOutput.output;
|
|
315
749
|
} else if (lastOutput.status === "failed") {
|
|
316
750
|
base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
|
|
317
|
-
await emitter.emit("watch", {
|
|
318
|
-
type: "watch",
|
|
319
|
-
payload: {
|
|
320
|
-
workflowState: {
|
|
321
|
-
status: lastOutput.status,
|
|
322
|
-
steps: stepResults,
|
|
323
|
-
result: null,
|
|
324
|
-
error: base.error
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
eventTimestamp: Date.now()
|
|
328
|
-
});
|
|
329
751
|
} else if (lastOutput.status === "suspended") {
|
|
330
|
-
await emitter.emit("watch", {
|
|
331
|
-
type: "watch",
|
|
332
|
-
payload: {
|
|
333
|
-
workflowState: {
|
|
334
|
-
status: lastOutput.status,
|
|
335
|
-
steps: stepResults,
|
|
336
|
-
result: null,
|
|
337
|
-
error: null
|
|
338
|
-
}
|
|
339
|
-
},
|
|
340
|
-
eventTimestamp: Date.now()
|
|
341
|
-
});
|
|
342
752
|
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
343
753
|
if (stepResult?.status === "suspended") {
|
|
344
|
-
const nestedPath = stepResult?.
|
|
754
|
+
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
345
755
|
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
346
756
|
}
|
|
347
757
|
return [];
|
|
348
758
|
});
|
|
349
759
|
base.suspended = suspendedStepIds;
|
|
350
760
|
}
|
|
351
|
-
executionSpan?.end();
|
|
352
761
|
return base;
|
|
353
762
|
}
|
|
354
|
-
async
|
|
763
|
+
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
764
|
+
// await this.inngestStep.sleep(id, duration);
|
|
765
|
+
// }
|
|
766
|
+
async executeSleep({
|
|
355
767
|
workflowId,
|
|
356
768
|
runId,
|
|
357
|
-
|
|
769
|
+
entry,
|
|
770
|
+
prevOutput,
|
|
358
771
|
stepResults,
|
|
772
|
+
emitter,
|
|
773
|
+
abortController,
|
|
774
|
+
requestContext,
|
|
359
775
|
executionContext,
|
|
360
|
-
|
|
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,
|
|
361
858
|
prevOutput,
|
|
859
|
+
stepResults,
|
|
362
860
|
emitter,
|
|
363
|
-
|
|
861
|
+
abortController,
|
|
862
|
+
requestContext,
|
|
863
|
+
executionContext,
|
|
864
|
+
writableStream,
|
|
865
|
+
tracingContext
|
|
364
866
|
}) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
|
375
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;
|
|
376
960
|
}
|
|
377
961
|
async executeStep({
|
|
378
962
|
step,
|
|
@@ -381,91 +965,113 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
381
965
|
resume,
|
|
382
966
|
prevOutput,
|
|
383
967
|
emitter,
|
|
384
|
-
|
|
968
|
+
abortController,
|
|
969
|
+
requestContext,
|
|
970
|
+
tracingContext,
|
|
971
|
+
writableStream,
|
|
972
|
+
disableScorers
|
|
385
973
|
}) {
|
|
386
|
-
|
|
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(
|
|
387
989
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
388
990
|
async () => {
|
|
991
|
+
const startedAt2 = Date.now();
|
|
389
992
|
await emitter.emit("watch", {
|
|
390
|
-
type: "
|
|
993
|
+
type: "workflow-step-start",
|
|
391
994
|
payload: {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
status: "running",
|
|
398
|
-
steps: {
|
|
399
|
-
...stepResults,
|
|
400
|
-
[step.id]: {
|
|
401
|
-
status: "running"
|
|
402
|
-
}
|
|
403
|
-
},
|
|
404
|
-
result: null,
|
|
405
|
-
error: null
|
|
406
|
-
}
|
|
407
|
-
},
|
|
408
|
-
eventTimestamp: Date.now()
|
|
995
|
+
id: step.id,
|
|
996
|
+
status: "running",
|
|
997
|
+
payload: inputData,
|
|
998
|
+
startedAt: startedAt2
|
|
999
|
+
}
|
|
409
1000
|
});
|
|
1001
|
+
return startedAt2;
|
|
410
1002
|
}
|
|
411
1003
|
);
|
|
412
1004
|
if (step instanceof InngestWorkflow) {
|
|
413
1005
|
const isResume = !!resume?.steps?.length;
|
|
414
1006
|
let result;
|
|
415
1007
|
let runId;
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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 ?? {},
|
|
428
1020
|
runId,
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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 }
|
|
434
1030
|
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
+
}
|
|
448
1062
|
}
|
|
449
1063
|
const res = await this.inngestStep.run(
|
|
450
1064
|
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
451
1065
|
async () => {
|
|
452
1066
|
if (result.status === "failed") {
|
|
453
1067
|
await emitter.emit("watch", {
|
|
454
|
-
type: "
|
|
1068
|
+
type: "workflow-step-result",
|
|
455
1069
|
payload: {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
workflowState: {
|
|
462
|
-
status: "running",
|
|
463
|
-
steps: stepResults,
|
|
464
|
-
result: null,
|
|
465
|
-
error: null
|
|
466
|
-
}
|
|
467
|
-
},
|
|
468
|
-
eventTimestamp: Date.now()
|
|
1070
|
+
id: step.id,
|
|
1071
|
+
status: "failed",
|
|
1072
|
+
error: result?.error,
|
|
1073
|
+
payload: prevOutput
|
|
1074
|
+
}
|
|
469
1075
|
});
|
|
470
1076
|
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
471
1077
|
} else if (result.status === "suspended") {
|
|
@@ -474,50 +1080,27 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
474
1080
|
return stepRes2?.status === "suspended";
|
|
475
1081
|
});
|
|
476
1082
|
for (const [stepName, stepResult] of suspendedSteps) {
|
|
477
|
-
const suspendPath = [stepName, ...stepResult?.
|
|
1083
|
+
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
478
1084
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
479
1085
|
await emitter.emit("watch", {
|
|
480
|
-
type: "
|
|
1086
|
+
type: "workflow-step-suspended",
|
|
481
1087
|
payload: {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
payload: { ...stepResult?.payload, __workflow_meta: { runId, path: suspendPath } }
|
|
486
|
-
},
|
|
487
|
-
workflowState: {
|
|
488
|
-
status: "running",
|
|
489
|
-
steps: stepResults,
|
|
490
|
-
result: null,
|
|
491
|
-
error: null
|
|
492
|
-
}
|
|
493
|
-
},
|
|
494
|
-
eventTimestamp: Date.now()
|
|
1088
|
+
id: step.id,
|
|
1089
|
+
status: "suspended"
|
|
1090
|
+
}
|
|
495
1091
|
});
|
|
496
1092
|
return {
|
|
497
1093
|
executionContext,
|
|
498
1094
|
result: {
|
|
499
1095
|
status: "suspended",
|
|
500
|
-
payload:
|
|
1096
|
+
payload: stepResult.payload,
|
|
1097
|
+
suspendPayload: {
|
|
1098
|
+
...stepResult?.suspendPayload,
|
|
1099
|
+
__workflow_meta: { runId, path: suspendPath }
|
|
1100
|
+
}
|
|
501
1101
|
}
|
|
502
1102
|
};
|
|
503
1103
|
}
|
|
504
|
-
await emitter.emit("watch", {
|
|
505
|
-
type: "watch",
|
|
506
|
-
payload: {
|
|
507
|
-
currentStep: {
|
|
508
|
-
id: step.id,
|
|
509
|
-
status: "suspended",
|
|
510
|
-
payload: {}
|
|
511
|
-
},
|
|
512
|
-
workflowState: {
|
|
513
|
-
status: "running",
|
|
514
|
-
steps: stepResults,
|
|
515
|
-
result: null,
|
|
516
|
-
error: null
|
|
517
|
-
}
|
|
518
|
-
},
|
|
519
|
-
eventTimestamp: Date.now()
|
|
520
|
-
});
|
|
521
1104
|
return {
|
|
522
1105
|
executionContext,
|
|
523
1106
|
result: {
|
|
@@ -527,110 +1110,243 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
527
1110
|
};
|
|
528
1111
|
}
|
|
529
1112
|
await emitter.emit("watch", {
|
|
530
|
-
type: "
|
|
1113
|
+
type: "workflow-step-result",
|
|
531
1114
|
payload: {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
},
|
|
544
|
-
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
|
+
}
|
|
545
1126
|
});
|
|
546
1127
|
return { executionContext, result: { status: "success", output: result?.result } };
|
|
547
1128
|
}
|
|
548
1129
|
);
|
|
549
1130
|
Object.assign(executionContext, res.executionContext);
|
|
550
|
-
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
|
+
};
|
|
551
1139
|
}
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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
|
|
566
1256
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
execResults = { status: "failed", error: e instanceof Error ? e.message : String(e) };
|
|
584
|
-
}
|
|
585
|
-
if (suspended) {
|
|
586
|
-
execResults = { status: "suspended", payload: suspended.payload };
|
|
587
|
-
}
|
|
588
|
-
if (execResults.status === "failed") {
|
|
589
|
-
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
590
|
-
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
|
+
});
|
|
591
1273
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
type: "watch",
|
|
595
|
-
payload: {
|
|
596
|
-
currentStep: {
|
|
597
|
-
id: step.id,
|
|
598
|
-
status: execResults.status,
|
|
599
|
-
output: execResults.output
|
|
600
|
-
},
|
|
601
|
-
workflowState: {
|
|
602
|
-
status: "running",
|
|
603
|
-
steps: stepResults,
|
|
604
|
-
result: null,
|
|
605
|
-
error: null
|
|
606
|
-
}
|
|
607
|
-
},
|
|
608
|
-
eventTimestamp: Date.now()
|
|
1274
|
+
stepAISpan?.end({ output: execResults });
|
|
1275
|
+
return { result: execResults, executionContext, stepResults };
|
|
609
1276
|
});
|
|
610
|
-
|
|
611
|
-
|
|
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
|
+
}
|
|
612
1311
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
613
1312
|
Object.assign(stepResults, stepRes.stepResults);
|
|
1313
|
+
executionContext.state = stepRes.executionContext.state;
|
|
614
1314
|
return stepRes.result;
|
|
615
1315
|
}
|
|
616
1316
|
async persistStepUpdate({
|
|
617
1317
|
workflowId,
|
|
618
1318
|
runId,
|
|
619
1319
|
stepResults,
|
|
620
|
-
|
|
1320
|
+
resourceId,
|
|
1321
|
+
executionContext,
|
|
1322
|
+
serializedStepGraph,
|
|
1323
|
+
workflowStatus,
|
|
1324
|
+
result,
|
|
1325
|
+
error
|
|
621
1326
|
}) {
|
|
622
1327
|
await this.inngestStep.run(
|
|
623
1328
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
624
1329
|
async () => {
|
|
1330
|
+
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
|
|
1331
|
+
if (!shouldPersistSnapshot) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
625
1334
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
626
1335
|
workflowName: workflowId,
|
|
627
1336
|
runId,
|
|
1337
|
+
resourceId,
|
|
628
1338
|
snapshot: {
|
|
629
1339
|
runId,
|
|
630
|
-
value:
|
|
1340
|
+
value: executionContext.state,
|
|
631
1341
|
context: stepResults,
|
|
632
1342
|
activePaths: [],
|
|
633
1343
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1344
|
+
resumeLabels: executionContext.resumeLabels,
|
|
1345
|
+
waitingPaths: {},
|
|
1346
|
+
serializedStepGraph,
|
|
1347
|
+
status: workflowStatus,
|
|
1348
|
+
result,
|
|
1349
|
+
error,
|
|
634
1350
|
// @ts-ignore
|
|
635
1351
|
timestamp: Date.now()
|
|
636
1352
|
}
|
|
@@ -643,53 +1359,123 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
643
1359
|
runId,
|
|
644
1360
|
entry,
|
|
645
1361
|
prevOutput,
|
|
646
|
-
prevStep,
|
|
647
1362
|
stepResults,
|
|
648
1363
|
resume,
|
|
649
1364
|
executionContext,
|
|
650
1365
|
emitter,
|
|
651
|
-
|
|
1366
|
+
abortController,
|
|
1367
|
+
requestContext,
|
|
1368
|
+
writableStream,
|
|
1369
|
+
disableScorers,
|
|
1370
|
+
tracingContext
|
|
652
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
|
+
});
|
|
653
1381
|
let execResults;
|
|
654
1382
|
const truthyIndexes = (await Promise.all(
|
|
655
1383
|
entry.conditions.map(
|
|
656
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
|
+
});
|
|
657
1394
|
try {
|
|
658
|
-
const result = await cond(
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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
|
|
670
1441
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
1442
|
+
)
|
|
1443
|
+
);
|
|
1444
|
+
evalSpan?.end({
|
|
1445
|
+
output: result,
|
|
1446
|
+
attributes: {
|
|
1447
|
+
result: !!result
|
|
1448
|
+
}
|
|
677
1449
|
});
|
|
678
1450
|
return result ? index : null;
|
|
679
1451
|
} catch (e) {
|
|
1452
|
+
evalSpan?.error({
|
|
1453
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
1454
|
+
attributes: {
|
|
1455
|
+
result: false
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
680
1458
|
return null;
|
|
681
1459
|
}
|
|
682
1460
|
})
|
|
683
1461
|
)
|
|
684
1462
|
)).filter((index) => index !== null);
|
|
685
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
|
+
});
|
|
686
1470
|
const results = await Promise.all(
|
|
687
|
-
stepsToRun.map(
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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,
|
|
693
1479
|
stepResults,
|
|
694
1480
|
resume,
|
|
695
1481
|
executionContext: {
|
|
@@ -697,20 +1483,29 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
697
1483
|
runId,
|
|
698
1484
|
executionPath: [...executionContext.executionPath, index],
|
|
699
1485
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1486
|
+
resumeLabels: executionContext.resumeLabels,
|
|
700
1487
|
retryConfig: executionContext.retryConfig,
|
|
701
|
-
|
|
1488
|
+
state: executionContext.state
|
|
702
1489
|
},
|
|
703
1490
|
emitter,
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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
|
+
})
|
|
707
1502
|
);
|
|
708
1503
|
const hasFailed = results.find((result) => result.status === "failed");
|
|
709
1504
|
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
710
1505
|
if (hasFailed) {
|
|
711
1506
|
execResults = { status: "failed", error: hasFailed.error };
|
|
712
1507
|
} else if (hasSuspended) {
|
|
713
|
-
execResults = { status: "suspended",
|
|
1508
|
+
execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
|
|
714
1509
|
} else {
|
|
715
1510
|
execResults = {
|
|
716
1511
|
status: "success",
|
|
@@ -722,8 +1517,19 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
722
1517
|
}, {})
|
|
723
1518
|
};
|
|
724
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
|
+
}
|
|
725
1529
|
return execResults;
|
|
726
1530
|
}
|
|
727
1531
|
};
|
|
728
1532
|
|
|
729
|
-
export { InngestExecutionEngine, InngestRun, InngestWorkflow, init, serve };
|
|
1533
|
+
export { InngestExecutionEngine, InngestRun, InngestWorkflow, createStep, init, serve };
|
|
1534
|
+
//# sourceMappingURL=index.js.map
|
|
1535
|
+
//# sourceMappingURL=index.js.map
|