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