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