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