@mastra/inngest 0.0.0-new-scorer-api-20250801075530 → 0.0.0-partial-response-backport-20251204204441
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 +762 -3
- package/dist/index.cjs +904 -360
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +152 -63
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +906 -362
- package/dist/index.js.map +1 -1
- package/package.json +38 -17
- package/docker-compose.yaml +0 -10
- package/eslint.config.js +0 -6
- package/src/index.test.ts +0 -7815
- package/src/index.ts +0 -1784
- package/tsconfig.build.json +0 -9
- package/tsconfig.json +0 -5
- package/tsup.config.ts +0 -22
- package/vitest.config.ts +0 -14
package/dist/index.cjs
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var crypto = require('crypto');
|
|
4
|
+
var web = require('stream/web');
|
|
4
5
|
var realtime = require('@inngest/realtime');
|
|
6
|
+
var aiTracing = require('@mastra/core/ai-tracing');
|
|
5
7
|
var di = require('@mastra/core/di');
|
|
8
|
+
var stream = require('@mastra/core/stream');
|
|
6
9
|
var tools = require('@mastra/core/tools');
|
|
7
10
|
var workflows = require('@mastra/core/workflows');
|
|
8
11
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
12
|
+
var inngest = require('inngest');
|
|
9
13
|
var hono = require('inngest/hono');
|
|
10
14
|
var zod = require('zod');
|
|
11
15
|
|
|
12
16
|
// src/index.ts
|
|
13
|
-
function serve({
|
|
17
|
+
function serve({
|
|
18
|
+
mastra,
|
|
19
|
+
inngest,
|
|
20
|
+
functions: userFunctions = [],
|
|
21
|
+
registerOptions
|
|
22
|
+
}) {
|
|
14
23
|
const wfs = mastra.getWorkflows();
|
|
15
|
-
const
|
|
24
|
+
const workflowFunctions = Array.from(
|
|
16
25
|
new Set(
|
|
17
26
|
Object.values(wfs).flatMap((wf) => {
|
|
18
27
|
if (wf instanceof InngestWorkflow) {
|
|
@@ -24,8 +33,9 @@ function serve({ mastra, inngest }) {
|
|
|
24
33
|
)
|
|
25
34
|
);
|
|
26
35
|
return hono.serve({
|
|
36
|
+
...registerOptions,
|
|
27
37
|
client: inngest,
|
|
28
|
-
functions
|
|
38
|
+
functions: [...workflowFunctions, ...userFunctions]
|
|
29
39
|
});
|
|
30
40
|
}
|
|
31
41
|
var InngestRun = class extends workflows.Run {
|
|
@@ -53,9 +63,15 @@ var InngestRun = class extends workflows.Run {
|
|
|
53
63
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
54
64
|
runs = await this.getRuns(eventId);
|
|
55
65
|
if (runs?.[0]?.status === "Failed") {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
67
|
+
workflowName: this.workflowId,
|
|
68
|
+
runId: this.runId
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
output: { result: { steps: snapshot?.context, status: "failed", error: runs?.[0]?.output?.message } }
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (runs?.[0]?.status === "Cancelled") {
|
|
59
75
|
const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
60
76
|
workflowName: this.workflowId,
|
|
61
77
|
runId: this.runId
|
|
@@ -86,35 +102,46 @@ var InngestRun = class extends workflows.Run {
|
|
|
86
102
|
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
87
103
|
workflowName: this.workflowId,
|
|
88
104
|
runId: this.runId,
|
|
105
|
+
resourceId: this.resourceId,
|
|
89
106
|
snapshot: {
|
|
90
107
|
...snapshot,
|
|
91
|
-
status: "canceled"
|
|
108
|
+
status: "canceled",
|
|
109
|
+
value: snapshot.value
|
|
92
110
|
}
|
|
93
111
|
});
|
|
94
112
|
}
|
|
95
113
|
}
|
|
96
114
|
async start({
|
|
97
|
-
inputData
|
|
115
|
+
inputData,
|
|
116
|
+
initialState
|
|
98
117
|
}) {
|
|
99
118
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
100
119
|
workflowName: this.workflowId,
|
|
101
120
|
runId: this.runId,
|
|
121
|
+
resourceId: this.resourceId,
|
|
102
122
|
snapshot: {
|
|
103
123
|
runId: this.runId,
|
|
104
124
|
serializedStepGraph: this.serializedStepGraph,
|
|
125
|
+
status: "running",
|
|
105
126
|
value: {},
|
|
106
127
|
context: {},
|
|
107
128
|
activePaths: [],
|
|
108
129
|
suspendedPaths: {},
|
|
109
|
-
|
|
110
|
-
|
|
130
|
+
activeStepsPath: {},
|
|
131
|
+
resumeLabels: {},
|
|
132
|
+
waitingPaths: {},
|
|
133
|
+
timestamp: Date.now()
|
|
111
134
|
}
|
|
112
135
|
});
|
|
136
|
+
const inputDataToUse = await this._validateInput(inputData);
|
|
137
|
+
const initialStateToUse = await this._validateInitialState(initialState ?? {});
|
|
113
138
|
const eventOutput = await this.inngest.send({
|
|
114
139
|
name: `workflow.${this.workflowId}`,
|
|
115
140
|
data: {
|
|
116
|
-
inputData,
|
|
117
|
-
|
|
141
|
+
inputData: inputDataToUse,
|
|
142
|
+
initialState: initialStateToUse,
|
|
143
|
+
runId: this.runId,
|
|
144
|
+
resourceId: this.resourceId
|
|
118
145
|
}
|
|
119
146
|
});
|
|
120
147
|
const eventId = eventOutput.ids[0];
|
|
@@ -143,24 +170,33 @@ var InngestRun = class extends workflows.Run {
|
|
|
143
170
|
return p;
|
|
144
171
|
}
|
|
145
172
|
async _resume(params) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
)
|
|
149
|
-
|
|
173
|
+
const storage = this.#mastra?.getStorage();
|
|
174
|
+
let steps = [];
|
|
175
|
+
if (typeof params.step === "string") {
|
|
176
|
+
steps = params.step.split(".");
|
|
177
|
+
} else {
|
|
178
|
+
steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
179
|
+
(step) => typeof step === "string" ? step : step?.id
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
150
183
|
workflowName: this.workflowId,
|
|
151
184
|
runId: this.runId
|
|
152
185
|
});
|
|
186
|
+
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
187
|
+
const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
|
|
153
188
|
const eventOutput = await this.inngest.send({
|
|
154
189
|
name: `workflow.${this.workflowId}`,
|
|
155
190
|
data: {
|
|
156
|
-
inputData:
|
|
191
|
+
inputData: resumeDataToUse,
|
|
192
|
+
initialState: snapshot?.value ?? {},
|
|
157
193
|
runId: this.runId,
|
|
158
194
|
workflowId: this.workflowId,
|
|
159
195
|
stepResults: snapshot?.context,
|
|
160
196
|
resume: {
|
|
161
197
|
steps,
|
|
162
198
|
stepResults: snapshot?.context,
|
|
163
|
-
resumePayload:
|
|
199
|
+
resumePayload: resumeDataToUse,
|
|
164
200
|
// @ts-ignore
|
|
165
201
|
resumePath: snapshot?.suspendedPaths?.[steps?.[0]]
|
|
166
202
|
}
|
|
@@ -200,12 +236,107 @@ var InngestRun = class extends workflows.Run {
|
|
|
200
236
|
});
|
|
201
237
|
};
|
|
202
238
|
}
|
|
203
|
-
|
|
239
|
+
async timeTravel(params) {
|
|
240
|
+
const p = this._timeTravel(params).then((result) => {
|
|
241
|
+
if (result.status !== "suspended") {
|
|
242
|
+
this.closeStreamAction?.().catch(() => {
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return result;
|
|
246
|
+
});
|
|
247
|
+
this.executionResults = p;
|
|
248
|
+
return p;
|
|
249
|
+
}
|
|
250
|
+
async _timeTravel(params) {
|
|
251
|
+
if (!params.step || Array.isArray(params.step) && params.step?.length === 0) {
|
|
252
|
+
throw new Error("Step is required and must be a valid step or array of steps");
|
|
253
|
+
}
|
|
254
|
+
let steps = [];
|
|
255
|
+
if (typeof params.step === "string") {
|
|
256
|
+
steps = params.step.split(".");
|
|
257
|
+
} else {
|
|
258
|
+
steps = (Array.isArray(params.step) ? params.step : [params.step]).map(
|
|
259
|
+
(step) => typeof step === "string" ? step : step?.id
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
if (steps.length === 0) {
|
|
263
|
+
throw new Error("No steps provided to timeTravel");
|
|
264
|
+
}
|
|
265
|
+
const storage = this.#mastra?.getStorage();
|
|
266
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
267
|
+
workflowName: this.workflowId,
|
|
268
|
+
runId: this.runId
|
|
269
|
+
});
|
|
270
|
+
if (!snapshot) {
|
|
271
|
+
await storage?.persistWorkflowSnapshot({
|
|
272
|
+
workflowName: this.workflowId,
|
|
273
|
+
runId: this.runId,
|
|
274
|
+
resourceId: this.resourceId,
|
|
275
|
+
snapshot: {
|
|
276
|
+
runId: this.runId,
|
|
277
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
278
|
+
status: "pending",
|
|
279
|
+
value: {},
|
|
280
|
+
context: {},
|
|
281
|
+
activePaths: [],
|
|
282
|
+
suspendedPaths: {},
|
|
283
|
+
activeStepsPath: {},
|
|
284
|
+
resumeLabels: {},
|
|
285
|
+
waitingPaths: {},
|
|
286
|
+
timestamp: Date.now()
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
if (snapshot?.status === "running") {
|
|
291
|
+
throw new Error("This workflow run is still running, cannot time travel");
|
|
292
|
+
}
|
|
293
|
+
let inputDataToUse = params.inputData;
|
|
294
|
+
if (inputDataToUse && steps.length === 1) {
|
|
295
|
+
inputDataToUse = await this._validateTimetravelInputData(params.inputData, this.workflowSteps[steps[0]]);
|
|
296
|
+
}
|
|
297
|
+
const timeTravelData = workflows.createTimeTravelExecutionParams({
|
|
298
|
+
steps,
|
|
299
|
+
inputData: inputDataToUse,
|
|
300
|
+
resumeData: params.resumeData,
|
|
301
|
+
context: params.context,
|
|
302
|
+
nestedStepsContext: params.nestedStepsContext,
|
|
303
|
+
snapshot: snapshot ?? { context: {} },
|
|
304
|
+
graph: this.executionGraph,
|
|
305
|
+
initialState: params.initialState
|
|
306
|
+
});
|
|
307
|
+
const eventOutput = await this.inngest.send({
|
|
308
|
+
name: `workflow.${this.workflowId}`,
|
|
309
|
+
data: {
|
|
310
|
+
initialState: timeTravelData.state,
|
|
311
|
+
runId: this.runId,
|
|
312
|
+
workflowId: this.workflowId,
|
|
313
|
+
stepResults: timeTravelData.stepResults,
|
|
314
|
+
timeTravel: timeTravelData,
|
|
315
|
+
tracingOptions: params.tracingOptions,
|
|
316
|
+
outputOptions: params.outputOptions
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
const eventId = eventOutput.ids[0];
|
|
320
|
+
if (!eventId) {
|
|
321
|
+
throw new Error("Event ID is not set");
|
|
322
|
+
}
|
|
323
|
+
const runOutput = await this.getRunOutput(eventId);
|
|
324
|
+
const result = runOutput?.output?.result;
|
|
325
|
+
if (result.status === "failed") {
|
|
326
|
+
result.error = new Error(result.error);
|
|
327
|
+
}
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
streamLegacy({ inputData, runtimeContext } = {}) {
|
|
204
331
|
const { readable, writable } = new TransformStream();
|
|
205
332
|
const writer = writable.getWriter();
|
|
206
333
|
const unwatch = this.watch(async (event) => {
|
|
207
334
|
try {
|
|
208
|
-
|
|
335
|
+
const e = {
|
|
336
|
+
...event,
|
|
337
|
+
type: event.type.replace("workflow-", "")
|
|
338
|
+
};
|
|
339
|
+
await writer.write(e);
|
|
209
340
|
} catch {
|
|
210
341
|
}
|
|
211
342
|
}, "watch-v2");
|
|
@@ -231,13 +362,140 @@ var InngestRun = class extends workflows.Run {
|
|
|
231
362
|
getWorkflowState: () => this.executionResults
|
|
232
363
|
};
|
|
233
364
|
}
|
|
365
|
+
stream({
|
|
366
|
+
inputData,
|
|
367
|
+
runtimeContext,
|
|
368
|
+
closeOnSuspend = true
|
|
369
|
+
} = {}) {
|
|
370
|
+
const self = this;
|
|
371
|
+
let streamOutput;
|
|
372
|
+
const stream$1 = new web.ReadableStream({
|
|
373
|
+
async start(controller) {
|
|
374
|
+
const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
|
|
375
|
+
controller.enqueue({
|
|
376
|
+
type,
|
|
377
|
+
runId: self.runId,
|
|
378
|
+
from,
|
|
379
|
+
payload: {
|
|
380
|
+
stepName: payload.id,
|
|
381
|
+
...payload
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
}, "watch-v2");
|
|
385
|
+
self.closeStreamAction = async () => {
|
|
386
|
+
unwatch();
|
|
387
|
+
try {
|
|
388
|
+
await controller.close();
|
|
389
|
+
} catch (err) {
|
|
390
|
+
console.error("Error closing stream:", err);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const executionResultsPromise = self.start({
|
|
394
|
+
inputData,
|
|
395
|
+
runtimeContext
|
|
396
|
+
});
|
|
397
|
+
const executionResults = await executionResultsPromise;
|
|
398
|
+
if (closeOnSuspend) {
|
|
399
|
+
self.closeStreamAction?.().catch(() => {
|
|
400
|
+
});
|
|
401
|
+
} else if (executionResults.status !== "suspended") {
|
|
402
|
+
self.closeStreamAction?.().catch(() => {
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
if (streamOutput) {
|
|
406
|
+
streamOutput.updateResults(executionResults);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
streamOutput = new stream.WorkflowRunOutput({
|
|
411
|
+
runId: this.runId,
|
|
412
|
+
workflowId: this.workflowId,
|
|
413
|
+
stream: stream$1
|
|
414
|
+
});
|
|
415
|
+
return streamOutput;
|
|
416
|
+
}
|
|
417
|
+
timeTravelStream({
|
|
418
|
+
inputData,
|
|
419
|
+
resumeData,
|
|
420
|
+
initialState,
|
|
421
|
+
step,
|
|
422
|
+
context,
|
|
423
|
+
nestedStepsContext,
|
|
424
|
+
runtimeContext,
|
|
425
|
+
tracingOptions,
|
|
426
|
+
outputOptions
|
|
427
|
+
}) {
|
|
428
|
+
const self = this;
|
|
429
|
+
let streamOutput;
|
|
430
|
+
const stream$1 = new web.ReadableStream({
|
|
431
|
+
async start(controller) {
|
|
432
|
+
const unwatch = self.watch(async ({ type, from = stream.ChunkFrom.WORKFLOW, payload }) => {
|
|
433
|
+
controller.enqueue({
|
|
434
|
+
type,
|
|
435
|
+
runId: self.runId,
|
|
436
|
+
from,
|
|
437
|
+
payload: {
|
|
438
|
+
stepName: payload?.id,
|
|
439
|
+
...payload
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}, "watch-v2");
|
|
443
|
+
self.closeStreamAction = async () => {
|
|
444
|
+
unwatch();
|
|
445
|
+
try {
|
|
446
|
+
await controller.close();
|
|
447
|
+
} catch (err) {
|
|
448
|
+
console.error("Error closing stream:", err);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
const executionResultsPromise = self._timeTravel({
|
|
452
|
+
inputData,
|
|
453
|
+
step,
|
|
454
|
+
context,
|
|
455
|
+
nestedStepsContext,
|
|
456
|
+
resumeData,
|
|
457
|
+
initialState,
|
|
458
|
+
runtimeContext,
|
|
459
|
+
tracingOptions,
|
|
460
|
+
outputOptions
|
|
461
|
+
});
|
|
462
|
+
self.executionResults = executionResultsPromise;
|
|
463
|
+
let executionResults;
|
|
464
|
+
try {
|
|
465
|
+
executionResults = await executionResultsPromise;
|
|
466
|
+
self.closeStreamAction?.().catch(() => {
|
|
467
|
+
});
|
|
468
|
+
if (streamOutput) {
|
|
469
|
+
streamOutput.updateResults(executionResults);
|
|
470
|
+
}
|
|
471
|
+
} catch (err) {
|
|
472
|
+
streamOutput?.rejectResults(err);
|
|
473
|
+
self.closeStreamAction?.().catch(() => {
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
streamOutput = new stream.WorkflowRunOutput({
|
|
479
|
+
runId: this.runId,
|
|
480
|
+
workflowId: this.workflowId,
|
|
481
|
+
stream: stream$1
|
|
482
|
+
});
|
|
483
|
+
return streamOutput;
|
|
484
|
+
}
|
|
234
485
|
};
|
|
235
486
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
236
487
|
#mastra;
|
|
237
488
|
inngest;
|
|
238
489
|
function;
|
|
490
|
+
flowControlConfig;
|
|
239
491
|
constructor(params, inngest) {
|
|
240
|
-
|
|
492
|
+
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
493
|
+
super(workflowParams);
|
|
494
|
+
this.engineType = "inngest";
|
|
495
|
+
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
496
|
+
([_, value]) => value !== void 0
|
|
497
|
+
);
|
|
498
|
+
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
241
499
|
this.#mastra = params.mastra;
|
|
242
500
|
this.inngest = inngest;
|
|
243
501
|
}
|
|
@@ -258,27 +516,6 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
258
516
|
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
259
517
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
260
518
|
}
|
|
261
|
-
async getWorkflowRunExecutionResult(runId) {
|
|
262
|
-
const storage = this.#mastra?.getStorage();
|
|
263
|
-
if (!storage) {
|
|
264
|
-
this.logger.debug("Cannot get workflow run execution result. Mastra storage is not initialized");
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
const run = await storage.getWorkflowRunById({ runId, workflowName: this.id });
|
|
268
|
-
if (!run?.snapshot) {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
if (typeof run.snapshot === "string") {
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
return {
|
|
275
|
-
status: run.snapshot.status,
|
|
276
|
-
result: run.snapshot.result,
|
|
277
|
-
error: run.snapshot.error,
|
|
278
|
-
payload: run.snapshot.context?.input,
|
|
279
|
-
steps: run.snapshot.context
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
519
|
__registerMastra(mastra) {
|
|
283
520
|
this.#mastra = mastra;
|
|
284
521
|
this.executionEngine.__registerMastra(mastra);
|
|
@@ -297,23 +534,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
297
534
|
}
|
|
298
535
|
}
|
|
299
536
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
executionGraph: this.executionGraph,
|
|
308
|
-
serializedStepGraph: this.serializedStepGraph,
|
|
309
|
-
mastra: this.#mastra,
|
|
310
|
-
retryConfig: this.retryConfig,
|
|
311
|
-
cleanup: () => this.runs.delete(runIdToUse)
|
|
312
|
-
},
|
|
313
|
-
this.inngest
|
|
537
|
+
/**
|
|
538
|
+
* @deprecated Use createRunAsync() instead.
|
|
539
|
+
* @throws {Error} Always throws an error directing users to use createRunAsync()
|
|
540
|
+
*/
|
|
541
|
+
createRun(_options) {
|
|
542
|
+
throw new Error(
|
|
543
|
+
"createRun() has been deprecated. Please use createRunAsync() instead.\n\nMigration guide:\n Before: const run = workflow.createRun();\n After: const run = await workflow.createRunAsync();\n\nNote: createRunAsync() is an async method, so make sure your calling function is async."
|
|
314
544
|
);
|
|
315
|
-
this.runs.set(runIdToUse, run);
|
|
316
|
-
return run;
|
|
317
545
|
}
|
|
318
546
|
async createRunAsync(options) {
|
|
319
547
|
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
@@ -321,29 +549,41 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
321
549
|
{
|
|
322
550
|
workflowId: this.id,
|
|
323
551
|
runId: runIdToUse,
|
|
552
|
+
resourceId: options?.resourceId,
|
|
324
553
|
executionEngine: this.executionEngine,
|
|
325
554
|
executionGraph: this.executionGraph,
|
|
326
555
|
serializedStepGraph: this.serializedStepGraph,
|
|
327
556
|
mastra: this.#mastra,
|
|
328
557
|
retryConfig: this.retryConfig,
|
|
329
|
-
cleanup: () => this.runs.delete(runIdToUse)
|
|
558
|
+
cleanup: () => this.runs.delete(runIdToUse),
|
|
559
|
+
workflowSteps: this.steps,
|
|
560
|
+
workflowEngineType: this.engineType,
|
|
561
|
+
validateInputs: this.options.validateInputs
|
|
330
562
|
},
|
|
331
563
|
this.inngest
|
|
332
564
|
);
|
|
333
565
|
this.runs.set(runIdToUse, run);
|
|
334
|
-
const
|
|
335
|
-
|
|
566
|
+
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
|
|
567
|
+
workflowStatus: run.workflowRunStatus,
|
|
568
|
+
stepResults: {}
|
|
569
|
+
});
|
|
570
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, false);
|
|
571
|
+
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
336
572
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
337
573
|
workflowName: this.id,
|
|
338
574
|
runId: runIdToUse,
|
|
575
|
+
resourceId: options?.resourceId,
|
|
339
576
|
snapshot: {
|
|
340
577
|
runId: runIdToUse,
|
|
341
578
|
status: "pending",
|
|
342
579
|
value: {},
|
|
343
580
|
context: {},
|
|
344
581
|
activePaths: [],
|
|
582
|
+
activeStepsPath: {},
|
|
583
|
+
waitingPaths: {},
|
|
345
584
|
serializedStepGraph: this.serializedStepGraph,
|
|
346
585
|
suspendedPaths: {},
|
|
586
|
+
resumeLabels: {},
|
|
347
587
|
result: void 0,
|
|
348
588
|
error: void 0,
|
|
349
589
|
// @ts-ignore
|
|
@@ -362,11 +602,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
362
602
|
id: `workflow.${this.id}`,
|
|
363
603
|
// @ts-ignore
|
|
364
604
|
retries: this.retryConfig?.attempts ?? 0,
|
|
365
|
-
cancelOn: [{ event: `cancel.workflow.${this.id}` }]
|
|
605
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
606
|
+
// Spread flow control configuration
|
|
607
|
+
...this.flowControlConfig
|
|
366
608
|
},
|
|
367
609
|
{ event: `workflow.${this.id}` },
|
|
368
610
|
async ({ event, step, attempt, publish }) => {
|
|
369
|
-
let { inputData, runId, resume } = event.data;
|
|
611
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, timeTravel } = event.data;
|
|
370
612
|
if (!runId) {
|
|
371
613
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
372
614
|
return crypto.randomUUID();
|
|
@@ -394,19 +636,33 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
394
636
|
once: (_event, _callback) => {
|
|
395
637
|
}
|
|
396
638
|
};
|
|
397
|
-
const engine = new InngestExecutionEngine(this.#mastra, step, attempt);
|
|
639
|
+
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
398
640
|
const result = await engine.execute({
|
|
399
641
|
workflowId: this.id,
|
|
400
642
|
runId,
|
|
643
|
+
resourceId,
|
|
401
644
|
graph: this.executionGraph,
|
|
402
645
|
serializedStepGraph: this.serializedStepGraph,
|
|
403
646
|
input: inputData,
|
|
647
|
+
initialState,
|
|
404
648
|
emitter,
|
|
405
649
|
retryConfig: this.retryConfig,
|
|
406
650
|
runtimeContext: new di.RuntimeContext(),
|
|
407
651
|
// TODO
|
|
408
652
|
resume,
|
|
409
|
-
|
|
653
|
+
timeTravel,
|
|
654
|
+
abortController: new AbortController(),
|
|
655
|
+
currentSpan: void 0,
|
|
656
|
+
// TODO: Pass actual parent AI span from workflow execution context
|
|
657
|
+
outputOptions
|
|
658
|
+
});
|
|
659
|
+
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
660
|
+
if (result.status === "failed") {
|
|
661
|
+
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
662
|
+
cause: result
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return result;
|
|
410
666
|
});
|
|
411
667
|
return { result, runId };
|
|
412
668
|
}
|
|
@@ -440,17 +696,16 @@ function createStep(params) {
|
|
|
440
696
|
if (isAgent(params)) {
|
|
441
697
|
return {
|
|
442
698
|
id: params.name,
|
|
699
|
+
description: params.getDescription(),
|
|
443
700
|
// @ts-ignore
|
|
444
701
|
inputSchema: zod.z.object({
|
|
445
702
|
prompt: zod.z.string()
|
|
446
|
-
// resourceId: z.string().optional(),
|
|
447
|
-
// threadId: z.string().optional(),
|
|
448
703
|
}),
|
|
449
704
|
// @ts-ignore
|
|
450
705
|
outputSchema: zod.z.object({
|
|
451
706
|
text: zod.z.string()
|
|
452
707
|
}),
|
|
453
|
-
execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
|
|
708
|
+
execute: async ({ inputData, [_constants.EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort, tracingContext }) => {
|
|
454
709
|
let streamPromise = {};
|
|
455
710
|
streamPromise.promise = new Promise((resolve, reject) => {
|
|
456
711
|
streamPromise.resolve = resolve;
|
|
@@ -460,50 +715,66 @@ function createStep(params) {
|
|
|
460
715
|
name: params.name,
|
|
461
716
|
args: inputData
|
|
462
717
|
};
|
|
463
|
-
await
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
718
|
+
if ((await params.getLLM()).getModel().specificationVersion === `v2`) {
|
|
719
|
+
const { fullStream } = await params.stream(inputData.prompt, {
|
|
720
|
+
runtimeContext,
|
|
721
|
+
tracingContext,
|
|
722
|
+
onFinish: (result) => {
|
|
723
|
+
streamPromise.resolve(result.text);
|
|
724
|
+
},
|
|
725
|
+
abortSignal
|
|
726
|
+
});
|
|
727
|
+
if (abortSignal.aborted) {
|
|
728
|
+
return abort();
|
|
729
|
+
}
|
|
730
|
+
await emitter.emit("watch-v2", {
|
|
731
|
+
type: "tool-call-streaming-start",
|
|
732
|
+
...toolData ?? {}
|
|
733
|
+
});
|
|
734
|
+
for await (const chunk of fullStream) {
|
|
735
|
+
if (chunk.type === "text-delta") {
|
|
736
|
+
await emitter.emit("watch-v2", {
|
|
737
|
+
type: "tool-call-delta",
|
|
738
|
+
...toolData ?? {},
|
|
739
|
+
argsTextDelta: chunk.payload.text
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
} else {
|
|
744
|
+
const { fullStream } = await params.streamLegacy(inputData.prompt, {
|
|
745
|
+
runtimeContext,
|
|
746
|
+
tracingContext,
|
|
747
|
+
onFinish: (result) => {
|
|
748
|
+
streamPromise.resolve(result.text);
|
|
749
|
+
},
|
|
750
|
+
abortSignal
|
|
751
|
+
});
|
|
752
|
+
if (abortSignal.aborted) {
|
|
753
|
+
return abort();
|
|
754
|
+
}
|
|
755
|
+
await emitter.emit("watch-v2", {
|
|
756
|
+
type: "tool-call-streaming-start",
|
|
757
|
+
...toolData ?? {}
|
|
758
|
+
});
|
|
759
|
+
for await (const chunk of fullStream) {
|
|
760
|
+
if (chunk.type === "text-delta") {
|
|
482
761
|
await emitter.emit("watch-v2", {
|
|
483
762
|
type: "tool-call-delta",
|
|
484
|
-
...toolData,
|
|
763
|
+
...toolData ?? {},
|
|
485
764
|
argsTextDelta: chunk.textDelta
|
|
486
765
|
});
|
|
487
|
-
|
|
488
|
-
case "step-start":
|
|
489
|
-
case "step-finish":
|
|
490
|
-
case "finish":
|
|
491
|
-
break;
|
|
492
|
-
case "tool-call":
|
|
493
|
-
case "tool-result":
|
|
494
|
-
case "tool-call-streaming-start":
|
|
495
|
-
case "tool-call-delta":
|
|
496
|
-
case "source":
|
|
497
|
-
case "file":
|
|
498
|
-
default:
|
|
499
|
-
await emitter.emit("watch-v2", chunk);
|
|
500
|
-
break;
|
|
766
|
+
}
|
|
501
767
|
}
|
|
502
768
|
}
|
|
769
|
+
await emitter.emit("watch-v2", {
|
|
770
|
+
type: "tool-call-streaming-finish",
|
|
771
|
+
...toolData ?? {}
|
|
772
|
+
});
|
|
503
773
|
return {
|
|
504
774
|
text: await streamPromise.promise
|
|
505
775
|
};
|
|
506
|
-
}
|
|
776
|
+
},
|
|
777
|
+
component: params.component
|
|
507
778
|
};
|
|
508
779
|
}
|
|
509
780
|
if (isTool(params)) {
|
|
@@ -514,15 +785,20 @@ function createStep(params) {
|
|
|
514
785
|
// TODO: tool probably should have strong id type
|
|
515
786
|
// @ts-ignore
|
|
516
787
|
id: params.id,
|
|
788
|
+
description: params.description,
|
|
517
789
|
inputSchema: params.inputSchema,
|
|
518
790
|
outputSchema: params.outputSchema,
|
|
519
|
-
execute: async ({ inputData, mastra, runtimeContext }) => {
|
|
791
|
+
execute: async ({ inputData, mastra, runtimeContext, tracingContext, suspend, resumeData }) => {
|
|
520
792
|
return params.execute({
|
|
521
793
|
context: inputData,
|
|
522
|
-
mastra,
|
|
523
|
-
runtimeContext
|
|
794
|
+
mastra: aiTracing.wrapMastra(mastra, tracingContext),
|
|
795
|
+
runtimeContext,
|
|
796
|
+
tracingContext,
|
|
797
|
+
suspend,
|
|
798
|
+
resumeData
|
|
524
799
|
});
|
|
525
|
-
}
|
|
800
|
+
},
|
|
801
|
+
component: "TOOL"
|
|
526
802
|
};
|
|
527
803
|
}
|
|
528
804
|
return {
|
|
@@ -538,7 +814,10 @@ function createStep(params) {
|
|
|
538
814
|
function init(inngest) {
|
|
539
815
|
return {
|
|
540
816
|
createWorkflow(params) {
|
|
541
|
-
return new InngestWorkflow(
|
|
817
|
+
return new InngestWorkflow(
|
|
818
|
+
params,
|
|
819
|
+
inngest
|
|
820
|
+
);
|
|
542
821
|
},
|
|
543
822
|
createStep,
|
|
544
823
|
cloneStep(step, opts) {
|
|
@@ -547,7 +826,11 @@ function init(inngest) {
|
|
|
547
826
|
description: step.description,
|
|
548
827
|
inputSchema: step.inputSchema,
|
|
549
828
|
outputSchema: step.outputSchema,
|
|
550
|
-
|
|
829
|
+
resumeSchema: step.resumeSchema,
|
|
830
|
+
suspendSchema: step.suspendSchema,
|
|
831
|
+
stateSchema: step.stateSchema,
|
|
832
|
+
execute: step.execute,
|
|
833
|
+
component: step.component
|
|
551
834
|
};
|
|
552
835
|
},
|
|
553
836
|
cloneWorkflow(workflow, opts) {
|
|
@@ -567,19 +850,19 @@ function init(inngest) {
|
|
|
567
850
|
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
568
851
|
inngestStep;
|
|
569
852
|
inngestAttempts;
|
|
570
|
-
constructor(mastra, inngestStep, inngestAttempts = 0) {
|
|
571
|
-
super({ mastra });
|
|
853
|
+
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
854
|
+
super({ mastra, options });
|
|
572
855
|
this.inngestStep = inngestStep;
|
|
573
856
|
this.inngestAttempts = inngestAttempts;
|
|
574
857
|
}
|
|
575
858
|
async execute(params) {
|
|
576
859
|
await params.emitter.emit("watch-v2", {
|
|
577
|
-
type: "start",
|
|
860
|
+
type: "workflow-start",
|
|
578
861
|
payload: { runId: params.runId }
|
|
579
862
|
});
|
|
580
863
|
const result = await super.execute(params);
|
|
581
864
|
await params.emitter.emit("watch-v2", {
|
|
582
|
-
type: "finish",
|
|
865
|
+
type: "workflow-finish",
|
|
583
866
|
payload: { runId: params.runId }
|
|
584
867
|
});
|
|
585
868
|
return result;
|
|
@@ -631,7 +914,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
631
914
|
});
|
|
632
915
|
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
633
916
|
if (stepResult?.status === "suspended") {
|
|
634
|
-
const nestedPath = stepResult?.
|
|
917
|
+
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
635
918
|
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
636
919
|
}
|
|
637
920
|
return [];
|
|
@@ -641,33 +924,6 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
641
924
|
executionSpan?.end();
|
|
642
925
|
return base;
|
|
643
926
|
}
|
|
644
|
-
async superExecuteStep({
|
|
645
|
-
workflowId,
|
|
646
|
-
runId,
|
|
647
|
-
step,
|
|
648
|
-
stepResults,
|
|
649
|
-
executionContext,
|
|
650
|
-
resume,
|
|
651
|
-
prevOutput,
|
|
652
|
-
emitter,
|
|
653
|
-
abortController,
|
|
654
|
-
runtimeContext,
|
|
655
|
-
writableStream
|
|
656
|
-
}) {
|
|
657
|
-
return super.executeStep({
|
|
658
|
-
workflowId,
|
|
659
|
-
runId,
|
|
660
|
-
step,
|
|
661
|
-
stepResults,
|
|
662
|
-
executionContext,
|
|
663
|
-
resume,
|
|
664
|
-
prevOutput,
|
|
665
|
-
emitter,
|
|
666
|
-
abortController,
|
|
667
|
-
runtimeContext,
|
|
668
|
-
writableStream
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
927
|
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
672
928
|
// await this.inngestStep.sleep(id, duration);
|
|
673
929
|
// }
|
|
@@ -680,9 +936,20 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
680
936
|
emitter,
|
|
681
937
|
abortController,
|
|
682
938
|
runtimeContext,
|
|
683
|
-
|
|
939
|
+
executionContext,
|
|
940
|
+
writableStream,
|
|
941
|
+
tracingContext
|
|
684
942
|
}) {
|
|
685
943
|
let { duration, fn } = entry;
|
|
944
|
+
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
945
|
+
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
946
|
+
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
947
|
+
attributes: {
|
|
948
|
+
durationMs: duration,
|
|
949
|
+
sleepType: fn ? "dynamic" : "fixed"
|
|
950
|
+
},
|
|
951
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
952
|
+
});
|
|
686
953
|
if (fn) {
|
|
687
954
|
const stepCallId = crypto.randomUUID();
|
|
688
955
|
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
@@ -692,18 +959,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
692
959
|
mastra: this.mastra,
|
|
693
960
|
runtimeContext,
|
|
694
961
|
inputData: prevOutput,
|
|
962
|
+
state: executionContext.state,
|
|
963
|
+
setState: (state) => {
|
|
964
|
+
executionContext.state = state;
|
|
965
|
+
},
|
|
695
966
|
runCount: -1,
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
if (!step?.id) {
|
|
699
|
-
return null;
|
|
700
|
-
}
|
|
701
|
-
const result = stepResults[step.id];
|
|
702
|
-
if (result?.status === "success") {
|
|
703
|
-
return result.output;
|
|
704
|
-
}
|
|
705
|
-
return null;
|
|
967
|
+
tracingContext: {
|
|
968
|
+
currentSpan: sleepSpan
|
|
706
969
|
},
|
|
970
|
+
getInitData: () => stepResults?.input,
|
|
971
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
707
972
|
// TODO: this function shouldn't have suspend probably?
|
|
708
973
|
suspend: async (_suspendPayload) => {
|
|
709
974
|
},
|
|
@@ -713,11 +978,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
713
978
|
abortController?.abort();
|
|
714
979
|
},
|
|
715
980
|
[_constants.EMITTER_SYMBOL]: emitter,
|
|
981
|
+
// TODO: add streamVNext support
|
|
982
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
716
983
|
engine: { step: this.inngestStep },
|
|
717
984
|
abortSignal: abortController?.signal,
|
|
718
985
|
writer: new tools.ToolStream(
|
|
719
986
|
{
|
|
720
|
-
prefix: "step",
|
|
987
|
+
prefix: "workflow-step",
|
|
721
988
|
callId: stepCallId,
|
|
722
989
|
name: "sleep",
|
|
723
990
|
runId
|
|
@@ -726,8 +993,19 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
726
993
|
)
|
|
727
994
|
});
|
|
728
995
|
});
|
|
996
|
+
sleepSpan?.update({
|
|
997
|
+
attributes: {
|
|
998
|
+
durationMs: duration
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
try {
|
|
1003
|
+
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
1004
|
+
sleepSpan?.end();
|
|
1005
|
+
} catch (e) {
|
|
1006
|
+
sleepSpan?.error({ error: e });
|
|
1007
|
+
throw e;
|
|
729
1008
|
}
|
|
730
|
-
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
731
1009
|
}
|
|
732
1010
|
async executeSleepUntil({
|
|
733
1011
|
workflowId,
|
|
@@ -738,9 +1016,21 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
738
1016
|
emitter,
|
|
739
1017
|
abortController,
|
|
740
1018
|
runtimeContext,
|
|
741
|
-
|
|
1019
|
+
executionContext,
|
|
1020
|
+
writableStream,
|
|
1021
|
+
tracingContext
|
|
742
1022
|
}) {
|
|
743
1023
|
let { date, fn } = entry;
|
|
1024
|
+
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1025
|
+
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
1026
|
+
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
1027
|
+
attributes: {
|
|
1028
|
+
untilDate: date,
|
|
1029
|
+
durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
|
|
1030
|
+
sleepType: fn ? "dynamic" : "fixed"
|
|
1031
|
+
},
|
|
1032
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1033
|
+
});
|
|
744
1034
|
if (fn) {
|
|
745
1035
|
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
746
1036
|
const stepCallId = crypto.randomUUID();
|
|
@@ -750,18 +1040,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
750
1040
|
mastra: this.mastra,
|
|
751
1041
|
runtimeContext,
|
|
752
1042
|
inputData: prevOutput,
|
|
1043
|
+
state: executionContext.state,
|
|
1044
|
+
setState: (state) => {
|
|
1045
|
+
executionContext.state = state;
|
|
1046
|
+
},
|
|
753
1047
|
runCount: -1,
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
if (!step?.id) {
|
|
757
|
-
return null;
|
|
758
|
-
}
|
|
759
|
-
const result = stepResults[step.id];
|
|
760
|
-
if (result?.status === "success") {
|
|
761
|
-
return result.output;
|
|
762
|
-
}
|
|
763
|
-
return null;
|
|
1048
|
+
tracingContext: {
|
|
1049
|
+
currentSpan: sleepUntilSpan
|
|
764
1050
|
},
|
|
1051
|
+
getInitData: () => stepResults?.input,
|
|
1052
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
765
1053
|
// TODO: this function shouldn't have suspend probably?
|
|
766
1054
|
suspend: async (_suspendPayload) => {
|
|
767
1055
|
},
|
|
@@ -771,11 +1059,13 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
771
1059
|
abortController?.abort();
|
|
772
1060
|
},
|
|
773
1061
|
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1062
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1063
|
+
// TODO: add streamVNext support
|
|
774
1064
|
engine: { step: this.inngestStep },
|
|
775
1065
|
abortSignal: abortController?.signal,
|
|
776
1066
|
writer: new tools.ToolStream(
|
|
777
1067
|
{
|
|
778
|
-
prefix: "step",
|
|
1068
|
+
prefix: "workflow-step",
|
|
779
1069
|
callId: stepCallId,
|
|
780
1070
|
name: "sleep",
|
|
781
1071
|
runId
|
|
@@ -784,11 +1074,27 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
784
1074
|
)
|
|
785
1075
|
});
|
|
786
1076
|
});
|
|
1077
|
+
if (date && !(date instanceof Date)) {
|
|
1078
|
+
date = new Date(date);
|
|
1079
|
+
}
|
|
1080
|
+
const time = !date ? 0 : date.getTime() - Date.now();
|
|
1081
|
+
sleepUntilSpan?.update({
|
|
1082
|
+
attributes: {
|
|
1083
|
+
durationMs: Math.max(0, time)
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
787
1086
|
}
|
|
788
1087
|
if (!(date instanceof Date)) {
|
|
1088
|
+
sleepUntilSpan?.end();
|
|
789
1089
|
return;
|
|
790
1090
|
}
|
|
791
|
-
|
|
1091
|
+
try {
|
|
1092
|
+
await this.inngestStep.sleepUntil(entry.id, date);
|
|
1093
|
+
sleepUntilSpan?.end();
|
|
1094
|
+
} catch (e) {
|
|
1095
|
+
sleepUntilSpan?.error({ error: e });
|
|
1096
|
+
throw e;
|
|
1097
|
+
}
|
|
792
1098
|
}
|
|
793
1099
|
async executeWaitForEvent({ event, timeout }) {
|
|
794
1100
|
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
@@ -805,12 +1111,29 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
805
1111
|
stepResults,
|
|
806
1112
|
executionContext,
|
|
807
1113
|
resume,
|
|
1114
|
+
timeTravel,
|
|
808
1115
|
prevOutput,
|
|
809
1116
|
emitter,
|
|
810
1117
|
abortController,
|
|
811
1118
|
runtimeContext,
|
|
812
|
-
|
|
1119
|
+
tracingContext,
|
|
1120
|
+
writableStream,
|
|
1121
|
+
disableScorers
|
|
813
1122
|
}) {
|
|
1123
|
+
const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1124
|
+
name: `workflow step: '${step.id}'`,
|
|
1125
|
+
type: aiTracing.AISpanType.WORKFLOW_STEP,
|
|
1126
|
+
input: prevOutput,
|
|
1127
|
+
attributes: {
|
|
1128
|
+
stepId: step.id
|
|
1129
|
+
},
|
|
1130
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1131
|
+
});
|
|
1132
|
+
const { inputData, validationError } = await workflows.validateStepInput({
|
|
1133
|
+
prevOutput,
|
|
1134
|
+
step,
|
|
1135
|
+
validateInputs: this.options?.validateInputs ?? false
|
|
1136
|
+
});
|
|
814
1137
|
const startedAt = await this.inngestStep.run(
|
|
815
1138
|
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
816
1139
|
async () => {
|
|
@@ -837,11 +1160,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
837
1160
|
eventTimestamp: Date.now()
|
|
838
1161
|
});
|
|
839
1162
|
await emitter.emit("watch-v2", {
|
|
840
|
-
type: "step-start",
|
|
1163
|
+
type: "workflow-step-start",
|
|
841
1164
|
payload: {
|
|
842
1165
|
id: step.id,
|
|
843
1166
|
status: "running",
|
|
844
|
-
payload:
|
|
1167
|
+
payload: inputData,
|
|
845
1168
|
startedAt: startedAt2
|
|
846
1169
|
}
|
|
847
1170
|
});
|
|
@@ -852,38 +1175,87 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
852
1175
|
const isResume = !!resume?.steps?.length;
|
|
853
1176
|
let result;
|
|
854
1177
|
let runId;
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1178
|
+
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
1179
|
+
try {
|
|
1180
|
+
if (isResume) {
|
|
1181
|
+
runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
1182
|
+
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1183
|
+
workflowName: step.id,
|
|
1184
|
+
runId
|
|
1185
|
+
});
|
|
1186
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1187
|
+
function: step.getFunction(),
|
|
1188
|
+
data: {
|
|
1189
|
+
inputData,
|
|
1190
|
+
initialState: executionContext.state ?? snapshot?.value ?? {},
|
|
867
1191
|
runId,
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1192
|
+
resume: {
|
|
1193
|
+
runId,
|
|
1194
|
+
steps: resume.steps.slice(1),
|
|
1195
|
+
stepResults: snapshot?.context,
|
|
1196
|
+
resumePayload: resume.resumePayload,
|
|
1197
|
+
// @ts-ignore
|
|
1198
|
+
resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
|
|
1199
|
+
},
|
|
1200
|
+
outputOptions: { includeState: true }
|
|
873
1201
|
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1202
|
+
});
|
|
1203
|
+
result = invokeResp.result;
|
|
1204
|
+
runId = invokeResp.runId;
|
|
1205
|
+
executionContext.state = invokeResp.result.state;
|
|
1206
|
+
} else if (isTimeTravel) {
|
|
1207
|
+
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1208
|
+
workflowName: step.id,
|
|
1209
|
+
runId: executionContext.runId
|
|
1210
|
+
}) ?? { context: {} };
|
|
1211
|
+
const timeTravelParams = workflows.createTimeTravelExecutionParams({
|
|
1212
|
+
steps: timeTravel.steps.slice(1),
|
|
1213
|
+
inputData: timeTravel.inputData,
|
|
1214
|
+
resumeData: timeTravel.resumeData,
|
|
1215
|
+
context: timeTravel.nestedStepResults?.[step.id] ?? {},
|
|
1216
|
+
nestedStepsContext: timeTravel.nestedStepResults ?? {},
|
|
1217
|
+
snapshot,
|
|
1218
|
+
graph: step.buildExecutionGraph()
|
|
1219
|
+
});
|
|
1220
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1221
|
+
function: step.getFunction(),
|
|
1222
|
+
data: {
|
|
1223
|
+
timeTravel: timeTravelParams,
|
|
1224
|
+
initialState: executionContext.state ?? {},
|
|
1225
|
+
runId: executionContext.runId,
|
|
1226
|
+
outputOptions: { includeState: true }
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
result = invokeResp.result;
|
|
1230
|
+
runId = invokeResp.runId;
|
|
1231
|
+
executionContext.state = invokeResp.result.state;
|
|
1232
|
+
} else {
|
|
1233
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1234
|
+
function: step.getFunction(),
|
|
1235
|
+
data: {
|
|
1236
|
+
inputData,
|
|
1237
|
+
initialState: executionContext.state ?? {},
|
|
1238
|
+
outputOptions: { includeState: true }
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
result = invokeResp.result;
|
|
1242
|
+
runId = invokeResp.runId;
|
|
1243
|
+
executionContext.state = invokeResp.result.state;
|
|
1244
|
+
}
|
|
1245
|
+
} catch (e) {
|
|
1246
|
+
const errorCause = e?.cause;
|
|
1247
|
+
if (errorCause && typeof errorCause === "object") {
|
|
1248
|
+
result = errorCause;
|
|
1249
|
+
runId = errorCause.runId || crypto.randomUUID();
|
|
1250
|
+
} else {
|
|
1251
|
+
runId = crypto.randomUUID();
|
|
1252
|
+
result = {
|
|
1253
|
+
status: "failed",
|
|
1254
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
1255
|
+
steps: {},
|
|
1256
|
+
input: inputData
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
887
1259
|
}
|
|
888
1260
|
const res = await this.inngestStep.run(
|
|
889
1261
|
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
@@ -907,7 +1279,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
907
1279
|
eventTimestamp: Date.now()
|
|
908
1280
|
});
|
|
909
1281
|
await emitter.emit("watch-v2", {
|
|
910
|
-
type: "step-result",
|
|
1282
|
+
type: "workflow-step-result",
|
|
911
1283
|
payload: {
|
|
912
1284
|
id: step.id,
|
|
913
1285
|
status: "failed",
|
|
@@ -917,12 +1289,12 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
917
1289
|
});
|
|
918
1290
|
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
919
1291
|
} else if (result.status === "suspended") {
|
|
920
|
-
const suspendedSteps = Object.entries(result.steps).filter(([_stepName,
|
|
921
|
-
const stepRes2 =
|
|
1292
|
+
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult2]) => {
|
|
1293
|
+
const stepRes2 = stepResult2;
|
|
922
1294
|
return stepRes2?.status === "suspended";
|
|
923
1295
|
});
|
|
924
|
-
for (const [stepName,
|
|
925
|
-
const suspendPath = [stepName, ...
|
|
1296
|
+
for (const [stepName, stepResult2] of suspendedSteps) {
|
|
1297
|
+
const suspendPath = [stepName, ...stepResult2?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
926
1298
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
927
1299
|
await emitter.emit("watch", {
|
|
928
1300
|
type: "watch",
|
|
@@ -930,7 +1302,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
930
1302
|
currentStep: {
|
|
931
1303
|
id: step.id,
|
|
932
1304
|
status: "suspended",
|
|
933
|
-
payload:
|
|
1305
|
+
payload: stepResult2.payload,
|
|
1306
|
+
suspendPayload: {
|
|
1307
|
+
...stepResult2?.suspendPayload,
|
|
1308
|
+
__workflow_meta: { runId, path: suspendPath }
|
|
1309
|
+
}
|
|
934
1310
|
},
|
|
935
1311
|
workflowState: {
|
|
936
1312
|
status: "running",
|
|
@@ -942,7 +1318,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
942
1318
|
eventTimestamp: Date.now()
|
|
943
1319
|
});
|
|
944
1320
|
await emitter.emit("watch-v2", {
|
|
945
|
-
type: "step-suspended",
|
|
1321
|
+
type: "workflow-step-suspended",
|
|
946
1322
|
payload: {
|
|
947
1323
|
id: step.id,
|
|
948
1324
|
status: "suspended"
|
|
@@ -952,7 +1328,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
952
1328
|
executionContext,
|
|
953
1329
|
result: {
|
|
954
1330
|
status: "suspended",
|
|
955
|
-
payload:
|
|
1331
|
+
payload: stepResult2.payload,
|
|
1332
|
+
suspendPayload: {
|
|
1333
|
+
...stepResult2?.suspendPayload,
|
|
1334
|
+
__workflow_meta: { runId, path: suspendPath }
|
|
1335
|
+
}
|
|
956
1336
|
}
|
|
957
1337
|
};
|
|
958
1338
|
}
|
|
@@ -999,7 +1379,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
999
1379
|
eventTimestamp: Date.now()
|
|
1000
1380
|
});
|
|
1001
1381
|
await emitter.emit("watch-v2", {
|
|
1002
|
-
type: "step-result",
|
|
1382
|
+
type: "workflow-step-result",
|
|
1003
1383
|
payload: {
|
|
1004
1384
|
id: step.id,
|
|
1005
1385
|
status: "success",
|
|
@@ -1007,7 +1387,7 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1007
1387
|
}
|
|
1008
1388
|
});
|
|
1009
1389
|
await emitter.emit("watch-v2", {
|
|
1010
|
-
type: "step-finish",
|
|
1390
|
+
type: "workflow-step-finish",
|
|
1011
1391
|
payload: {
|
|
1012
1392
|
id: step.id,
|
|
1013
1393
|
metadata: {}
|
|
@@ -1017,136 +1397,234 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1017
1397
|
}
|
|
1018
1398
|
);
|
|
1019
1399
|
Object.assign(executionContext, res.executionContext);
|
|
1020
|
-
|
|
1400
|
+
const stepResult = {
|
|
1401
|
+
...res.result,
|
|
1402
|
+
startedAt,
|
|
1403
|
+
endedAt: Date.now(),
|
|
1404
|
+
payload: inputData,
|
|
1405
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1406
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1407
|
+
};
|
|
1408
|
+
return { result: stepResult, executionContextState: executionContext.state };
|
|
1021
1409
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1410
|
+
let stepRes;
|
|
1411
|
+
try {
|
|
1412
|
+
stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
1413
|
+
let execResults;
|
|
1414
|
+
let suspended;
|
|
1415
|
+
let bailed;
|
|
1416
|
+
const { resumeData: timeTravelResumeData, validationError: timeTravelResumeValidationError } = await workflows.validateStepResumeData({
|
|
1417
|
+
resumeData: timeTravel?.stepResults[step.id]?.status === "suspended" ? timeTravel?.resumeData : void 0,
|
|
1418
|
+
step
|
|
1419
|
+
});
|
|
1420
|
+
let resumeDataToUse;
|
|
1421
|
+
if (timeTravelResumeData && !timeTravelResumeValidationError) {
|
|
1422
|
+
resumeDataToUse = timeTravelResumeData;
|
|
1423
|
+
} else if (timeTravelResumeData && timeTravelResumeValidationError) {
|
|
1424
|
+
this.logger.warn("Time travel resume data validation failed", {
|
|
1425
|
+
stepId: step.id,
|
|
1426
|
+
error: timeTravelResumeValidationError.message
|
|
1427
|
+
});
|
|
1428
|
+
} else if (resume?.steps[0] === step.id) {
|
|
1429
|
+
resumeDataToUse = resume?.resumePayload;
|
|
1430
|
+
}
|
|
1431
|
+
try {
|
|
1432
|
+
if (validationError) {
|
|
1433
|
+
throw validationError;
|
|
1434
|
+
}
|
|
1435
|
+
const result = await step.execute({
|
|
1436
|
+
runId: executionContext.runId,
|
|
1437
|
+
mastra: this.mastra,
|
|
1438
|
+
runtimeContext,
|
|
1439
|
+
writableStream,
|
|
1440
|
+
state: executionContext?.state ?? {},
|
|
1441
|
+
setState: (state) => {
|
|
1442
|
+
executionContext.state = state;
|
|
1443
|
+
},
|
|
1444
|
+
inputData,
|
|
1445
|
+
resumeData: resumeDataToUse,
|
|
1446
|
+
tracingContext: {
|
|
1447
|
+
currentSpan: stepAISpan
|
|
1448
|
+
},
|
|
1449
|
+
getInitData: () => stepResults?.input,
|
|
1450
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1451
|
+
suspend: async (suspendPayload, suspendOptions) => {
|
|
1452
|
+
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1453
|
+
if (suspendOptions?.resumeLabel) {
|
|
1454
|
+
const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
|
|
1455
|
+
for (const label of resumeLabel) {
|
|
1456
|
+
executionContext.resumeLabels[label] = {
|
|
1457
|
+
stepId: step.id,
|
|
1458
|
+
foreachIndex: executionContext.foreachIndex
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
suspended = { payload: suspendPayload };
|
|
1463
|
+
},
|
|
1464
|
+
bail: (result2) => {
|
|
1465
|
+
bailed = { payload: result2 };
|
|
1466
|
+
},
|
|
1467
|
+
resume: {
|
|
1468
|
+
steps: resume?.steps?.slice(1) || [],
|
|
1469
|
+
resumePayload: resume?.resumePayload,
|
|
1470
|
+
// @ts-ignore
|
|
1471
|
+
runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
|
|
1472
|
+
},
|
|
1473
|
+
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1474
|
+
engine: {
|
|
1475
|
+
step: this.inngestStep
|
|
1476
|
+
},
|
|
1477
|
+
abortSignal: abortController.signal
|
|
1478
|
+
});
|
|
1479
|
+
const endedAt = Date.now();
|
|
1480
|
+
execResults = {
|
|
1481
|
+
status: "success",
|
|
1482
|
+
output: result,
|
|
1483
|
+
startedAt,
|
|
1484
|
+
endedAt,
|
|
1485
|
+
payload: inputData,
|
|
1486
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1487
|
+
resumePayload: resumeDataToUse
|
|
1488
|
+
};
|
|
1489
|
+
} catch (e) {
|
|
1490
|
+
const stepFailure = {
|
|
1491
|
+
status: "failed",
|
|
1492
|
+
payload: inputData,
|
|
1493
|
+
error: e instanceof Error ? e.stack ?? e.message : String(e),
|
|
1494
|
+
endedAt: Date.now(),
|
|
1495
|
+
startedAt,
|
|
1496
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1497
|
+
resumePayload: resumeDataToUse
|
|
1498
|
+
};
|
|
1499
|
+
execResults = stepFailure;
|
|
1500
|
+
const fallbackErrorMessage = `Step ${step.id} failed`;
|
|
1501
|
+
stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
|
|
1502
|
+
throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
|
|
1503
|
+
cause: execResults
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
if (suspended) {
|
|
1507
|
+
execResults = {
|
|
1508
|
+
status: "suspended",
|
|
1509
|
+
suspendPayload: suspended.payload,
|
|
1510
|
+
payload: inputData,
|
|
1511
|
+
suspendedAt: Date.now(),
|
|
1512
|
+
startedAt,
|
|
1513
|
+
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1514
|
+
resumePayload: resumeDataToUse
|
|
1515
|
+
};
|
|
1516
|
+
} else if (bailed) {
|
|
1517
|
+
execResults = {
|
|
1518
|
+
status: "bailed",
|
|
1519
|
+
output: bailed.payload,
|
|
1520
|
+
payload: inputData,
|
|
1521
|
+
endedAt: Date.now(),
|
|
1522
|
+
startedAt
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
await emitter.emit("watch", {
|
|
1526
|
+
type: "watch",
|
|
1527
|
+
payload: {
|
|
1528
|
+
currentStep: {
|
|
1529
|
+
id: step.id,
|
|
1530
|
+
...execResults
|
|
1531
|
+
},
|
|
1532
|
+
workflowState: {
|
|
1533
|
+
status: "running",
|
|
1534
|
+
steps: { ...stepResults, [step.id]: execResults },
|
|
1535
|
+
result: null,
|
|
1536
|
+
error: null
|
|
1039
1537
|
}
|
|
1040
|
-
return null;
|
|
1041
|
-
},
|
|
1042
|
-
suspend: async (suspendPayload) => {
|
|
1043
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1044
|
-
suspended = { payload: suspendPayload };
|
|
1045
1538
|
},
|
|
1046
|
-
|
|
1047
|
-
bailed = { payload: result2 };
|
|
1048
|
-
},
|
|
1049
|
-
resume: {
|
|
1050
|
-
steps: resume?.steps?.slice(1) || [],
|
|
1051
|
-
resumePayload: resume?.resumePayload,
|
|
1052
|
-
// @ts-ignore
|
|
1053
|
-
runId: stepResults[step.id]?.payload?.__workflow_meta?.runId
|
|
1054
|
-
},
|
|
1055
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1056
|
-
engine: {
|
|
1057
|
-
step: this.inngestStep
|
|
1058
|
-
},
|
|
1059
|
-
abortSignal: abortController.signal
|
|
1539
|
+
eventTimestamp: Date.now()
|
|
1060
1540
|
});
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
status: "suspended",
|
|
1085
|
-
suspendedPayload: suspended.payload,
|
|
1086
|
-
payload: prevOutput,
|
|
1087
|
-
suspendedAt: Date.now(),
|
|
1088
|
-
startedAt,
|
|
1089
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1090
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1091
|
-
};
|
|
1092
|
-
} else if (bailed) {
|
|
1093
|
-
execResults = { status: "bailed", output: bailed.payload, payload: prevOutput, endedAt: Date.now(), startedAt };
|
|
1094
|
-
}
|
|
1095
|
-
if (execResults.status === "failed") {
|
|
1096
|
-
if (executionContext.retryConfig.attempts > 0 && this.inngestAttempts < executionContext.retryConfig.attempts) {
|
|
1097
|
-
throw execResults.error;
|
|
1541
|
+
if (execResults.status === "suspended") {
|
|
1542
|
+
await emitter.emit("watch-v2", {
|
|
1543
|
+
type: "workflow-step-suspended",
|
|
1544
|
+
payload: {
|
|
1545
|
+
id: step.id,
|
|
1546
|
+
...execResults
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
} else {
|
|
1550
|
+
await emitter.emit("watch-v2", {
|
|
1551
|
+
type: "workflow-step-result",
|
|
1552
|
+
payload: {
|
|
1553
|
+
id: step.id,
|
|
1554
|
+
...execResults
|
|
1555
|
+
}
|
|
1556
|
+
});
|
|
1557
|
+
await emitter.emit("watch-v2", {
|
|
1558
|
+
type: "workflow-step-finish",
|
|
1559
|
+
payload: {
|
|
1560
|
+
id: step.id,
|
|
1561
|
+
metadata: {}
|
|
1562
|
+
}
|
|
1563
|
+
});
|
|
1098
1564
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1565
|
+
stepAISpan?.end({ output: execResults });
|
|
1566
|
+
return { result: execResults, executionContext, stepResults };
|
|
1567
|
+
});
|
|
1568
|
+
} catch (e) {
|
|
1569
|
+
const stepFailure = e instanceof Error ? e?.cause : {
|
|
1570
|
+
status: "failed",
|
|
1571
|
+
error: e instanceof Error ? e.stack ?? e.message : String(e),
|
|
1572
|
+
payload: inputData,
|
|
1573
|
+
startedAt,
|
|
1574
|
+
endedAt: Date.now()
|
|
1575
|
+
};
|
|
1576
|
+
await emitter.emit("watch-v2", {
|
|
1577
|
+
type: "workflow-step-result",
|
|
1102
1578
|
payload: {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
},
|
|
1107
|
-
workflowState: {
|
|
1108
|
-
status: "running",
|
|
1109
|
-
steps: { ...stepResults, [step.id]: execResults },
|
|
1110
|
-
result: null,
|
|
1111
|
-
error: null
|
|
1112
|
-
}
|
|
1113
|
-
},
|
|
1114
|
-
eventTimestamp: Date.now()
|
|
1579
|
+
id: step.id,
|
|
1580
|
+
...stepFailure
|
|
1581
|
+
}
|
|
1115
1582
|
});
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1583
|
+
await emitter.emit("watch-v2", {
|
|
1584
|
+
type: "workflow-step-finish",
|
|
1585
|
+
payload: {
|
|
1586
|
+
id: step.id,
|
|
1587
|
+
metadata: {}
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
stepRes = {
|
|
1591
|
+
result: stepFailure,
|
|
1592
|
+
executionContext,
|
|
1593
|
+
stepResults: {
|
|
1594
|
+
...stepResults,
|
|
1595
|
+
[step.id]: stepFailure
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
if (disableScorers !== false && stepRes.result.status === "success") {
|
|
1600
|
+
await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
|
|
1601
|
+
if (step.scorers) {
|
|
1602
|
+
await this.runScorers({
|
|
1603
|
+
scorers: step.scorers,
|
|
1604
|
+
runId: executionContext.runId,
|
|
1605
|
+
input: inputData,
|
|
1606
|
+
output: stepRes.result,
|
|
1607
|
+
workflowId: executionContext.workflowId,
|
|
1608
|
+
stepId: step.id,
|
|
1609
|
+
runtimeContext,
|
|
1610
|
+
disableScorers,
|
|
1611
|
+
tracingContext: { currentSpan: stepAISpan }
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
});
|
|
1615
|
+
}
|
|
1142
1616
|
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
1143
|
-
|
|
1144
|
-
return
|
|
1617
|
+
executionContext.state = stepRes.executionContext.state;
|
|
1618
|
+
return {
|
|
1619
|
+
result: stepRes.result,
|
|
1620
|
+
executionContextState: stepRes.executionContext.state
|
|
1621
|
+
};
|
|
1145
1622
|
}
|
|
1146
1623
|
async persistStepUpdate({
|
|
1147
1624
|
workflowId,
|
|
1148
1625
|
runId,
|
|
1149
1626
|
stepResults,
|
|
1627
|
+
resourceId,
|
|
1150
1628
|
executionContext,
|
|
1151
1629
|
serializedStepGraph,
|
|
1152
1630
|
workflowStatus,
|
|
@@ -1156,17 +1634,25 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1156
1634
|
await this.inngestStep.run(
|
|
1157
1635
|
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
1158
1636
|
async () => {
|
|
1637
|
+
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
|
|
1638
|
+
if (!shouldPersistSnapshot) {
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1159
1641
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
1160
1642
|
workflowName: workflowId,
|
|
1161
1643
|
runId,
|
|
1644
|
+
resourceId,
|
|
1162
1645
|
snapshot: {
|
|
1163
1646
|
runId,
|
|
1164
|
-
|
|
1647
|
+
status: workflowStatus,
|
|
1648
|
+
value: executionContext.state,
|
|
1165
1649
|
context: stepResults,
|
|
1166
|
-
activePaths:
|
|
1650
|
+
activePaths: executionContext.executionPath,
|
|
1651
|
+
activeStepsPath: executionContext.activeStepsPath,
|
|
1167
1652
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1653
|
+
resumeLabels: executionContext.resumeLabels,
|
|
1654
|
+
waitingPaths: {},
|
|
1168
1655
|
serializedStepGraph,
|
|
1169
|
-
status: workflowStatus,
|
|
1170
1656
|
result,
|
|
1171
1657
|
error,
|
|
1172
1658
|
// @ts-ignore
|
|
@@ -1181,20 +1667,39 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1181
1667
|
runId,
|
|
1182
1668
|
entry,
|
|
1183
1669
|
prevOutput,
|
|
1184
|
-
prevStep,
|
|
1185
1670
|
stepResults,
|
|
1186
|
-
|
|
1671
|
+
timeTravel,
|
|
1187
1672
|
resume,
|
|
1188
1673
|
executionContext,
|
|
1189
1674
|
emitter,
|
|
1190
1675
|
abortController,
|
|
1191
1676
|
runtimeContext,
|
|
1192
|
-
writableStream
|
|
1677
|
+
writableStream,
|
|
1678
|
+
disableScorers,
|
|
1679
|
+
tracingContext
|
|
1193
1680
|
}) {
|
|
1681
|
+
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1682
|
+
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
|
|
1683
|
+
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1684
|
+
input: prevOutput,
|
|
1685
|
+
attributes: {
|
|
1686
|
+
conditionCount: entry.conditions.length
|
|
1687
|
+
},
|
|
1688
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1689
|
+
});
|
|
1194
1690
|
let execResults;
|
|
1195
1691
|
const truthyIndexes = (await Promise.all(
|
|
1196
1692
|
entry.conditions.map(
|
|
1197
1693
|
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1694
|
+
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1695
|
+
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1696
|
+
name: `condition: '${index}'`,
|
|
1697
|
+
input: prevOutput,
|
|
1698
|
+
attributes: {
|
|
1699
|
+
conditionIndex: index
|
|
1700
|
+
},
|
|
1701
|
+
tracingPolicy: this.options?.tracingPolicy
|
|
1702
|
+
});
|
|
1198
1703
|
try {
|
|
1199
1704
|
const result = await cond({
|
|
1200
1705
|
runId,
|
|
@@ -1203,17 +1708,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1203
1708
|
runtimeContext,
|
|
1204
1709
|
runCount: -1,
|
|
1205
1710
|
inputData: prevOutput,
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
if (result2?.status === "success") {
|
|
1213
|
-
return result2.output;
|
|
1214
|
-
}
|
|
1215
|
-
return null;
|
|
1711
|
+
state: executionContext.state,
|
|
1712
|
+
setState: (state) => {
|
|
1713
|
+
executionContext.state = state;
|
|
1714
|
+
},
|
|
1715
|
+
tracingContext: {
|
|
1716
|
+
currentSpan: evalSpan
|
|
1216
1717
|
},
|
|
1718
|
+
getInitData: () => stepResults?.input,
|
|
1719
|
+
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1217
1720
|
// TODO: this function shouldn't have suspend probably?
|
|
1218
1721
|
suspend: async (_suspendPayload) => {
|
|
1219
1722
|
},
|
|
@@ -1223,13 +1726,15 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1223
1726
|
abortController.abort();
|
|
1224
1727
|
},
|
|
1225
1728
|
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1729
|
+
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1730
|
+
// TODO: add streamVNext support
|
|
1226
1731
|
engine: {
|
|
1227
1732
|
step: this.inngestStep
|
|
1228
1733
|
},
|
|
1229
1734
|
abortSignal: abortController.signal,
|
|
1230
1735
|
writer: new tools.ToolStream(
|
|
1231
1736
|
{
|
|
1232
|
-
prefix: "step",
|
|
1737
|
+
prefix: "workflow-step",
|
|
1233
1738
|
callId: crypto.randomUUID(),
|
|
1234
1739
|
name: "conditional",
|
|
1235
1740
|
runId
|
|
@@ -1237,56 +1742,95 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
1237
1742
|
writableStream
|
|
1238
1743
|
)
|
|
1239
1744
|
});
|
|
1745
|
+
evalSpan?.end({
|
|
1746
|
+
output: result,
|
|
1747
|
+
attributes: {
|
|
1748
|
+
result: !!result
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1240
1751
|
return result ? index : null;
|
|
1241
1752
|
} catch (e) {
|
|
1753
|
+
evalSpan?.error({
|
|
1754
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
1755
|
+
attributes: {
|
|
1756
|
+
result: false
|
|
1757
|
+
}
|
|
1758
|
+
});
|
|
1242
1759
|
return null;
|
|
1243
1760
|
}
|
|
1244
1761
|
})
|
|
1245
1762
|
)
|
|
1246
1763
|
)).filter((index) => index !== null);
|
|
1247
1764
|
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
1765
|
+
conditionalSpan?.update({
|
|
1766
|
+
attributes: {
|
|
1767
|
+
truthyIndexes,
|
|
1768
|
+
selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1248
1771
|
const results = await Promise.all(
|
|
1249
|
-
stepsToRun.map(
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1772
|
+
stepsToRun.map(async (step, index) => {
|
|
1773
|
+
const currStepResult = stepResults[step.step.id];
|
|
1774
|
+
if (currStepResult && currStepResult.status === "success") {
|
|
1775
|
+
return currStepResult;
|
|
1776
|
+
}
|
|
1777
|
+
const result = await this.executeStep({
|
|
1778
|
+
step: step.step,
|
|
1779
|
+
prevOutput,
|
|
1255
1780
|
stepResults,
|
|
1256
1781
|
resume,
|
|
1257
|
-
|
|
1782
|
+
timeTravel,
|
|
1258
1783
|
executionContext: {
|
|
1259
1784
|
workflowId,
|
|
1260
1785
|
runId,
|
|
1261
1786
|
executionPath: [...executionContext.executionPath, index],
|
|
1787
|
+
activeStepsPath: executionContext.activeStepsPath,
|
|
1262
1788
|
suspendedPaths: executionContext.suspendedPaths,
|
|
1789
|
+
resumeLabels: executionContext.resumeLabels,
|
|
1263
1790
|
retryConfig: executionContext.retryConfig,
|
|
1264
|
-
executionSpan: executionContext.executionSpan
|
|
1791
|
+
executionSpan: executionContext.executionSpan,
|
|
1792
|
+
state: executionContext.state
|
|
1265
1793
|
},
|
|
1266
1794
|
emitter,
|
|
1267
1795
|
abortController,
|
|
1268
1796
|
runtimeContext,
|
|
1269
|
-
writableStream
|
|
1270
|
-
|
|
1271
|
-
|
|
1797
|
+
writableStream,
|
|
1798
|
+
disableScorers,
|
|
1799
|
+
tracingContext: {
|
|
1800
|
+
currentSpan: conditionalSpan
|
|
1801
|
+
}
|
|
1802
|
+
});
|
|
1803
|
+
stepResults[step.step.id] = result.result;
|
|
1804
|
+
executionContext.state = result.executionContextState;
|
|
1805
|
+
return result.result;
|
|
1806
|
+
})
|
|
1272
1807
|
);
|
|
1273
|
-
const hasFailed = results.find((result) => result.
|
|
1274
|
-
const hasSuspended = results.find((result) => result.
|
|
1808
|
+
const hasFailed = results.find((result) => result.status === "failed");
|
|
1809
|
+
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
1275
1810
|
if (hasFailed) {
|
|
1276
|
-
execResults = { status: "failed", error: hasFailed.
|
|
1811
|
+
execResults = { status: "failed", error: hasFailed.error };
|
|
1277
1812
|
} else if (hasSuspended) {
|
|
1278
|
-
execResults = { status: "suspended",
|
|
1813
|
+
execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
|
|
1279
1814
|
} else {
|
|
1280
1815
|
execResults = {
|
|
1281
1816
|
status: "success",
|
|
1282
1817
|
output: results.reduce((acc, result, index) => {
|
|
1283
|
-
if (result.
|
|
1818
|
+
if (result.status === "success") {
|
|
1284
1819
|
acc[stepsToRun[index].step.id] = result.output;
|
|
1285
1820
|
}
|
|
1286
1821
|
return acc;
|
|
1287
1822
|
}, {})
|
|
1288
1823
|
};
|
|
1289
1824
|
}
|
|
1825
|
+
if (execResults.status === "failed") {
|
|
1826
|
+
conditionalSpan?.error({
|
|
1827
|
+
error: new Error(execResults.error)
|
|
1828
|
+
});
|
|
1829
|
+
} else {
|
|
1830
|
+
conditionalSpan?.end({
|
|
1831
|
+
output: execResults.output || execResults
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1290
1834
|
return execResults;
|
|
1291
1835
|
}
|
|
1292
1836
|
};
|