@mastra/inngest 1.0.0-beta.3 → 1.0.0-beta.4
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 +23 -0
- package/dist/execution-engine.d.ts +85 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/index.cjs +348 -890
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -319
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +348 -891
- 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 +5 -5
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 di = require('@mastra/core/di');
|
|
7
|
-
var observability = require('@mastra/core/observability');
|
|
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;
|
|
@@ -115,7 +374,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
115
374
|
initialState,
|
|
116
375
|
outputOptions,
|
|
117
376
|
tracingOptions,
|
|
118
|
-
format
|
|
377
|
+
format,
|
|
378
|
+
requestContext
|
|
119
379
|
}) {
|
|
120
380
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
121
381
|
workflowName: this.workflowId,
|
|
@@ -146,7 +406,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
146
406
|
resourceId: this.resourceId,
|
|
147
407
|
outputOptions,
|
|
148
408
|
tracingOptions,
|
|
149
|
-
format
|
|
409
|
+
format,
|
|
410
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
150
411
|
}
|
|
151
412
|
});
|
|
152
413
|
const eventId = eventOutput.ids[0];
|
|
@@ -190,6 +451,9 @@ var InngestRun = class extends workflows.Run {
|
|
|
190
451
|
});
|
|
191
452
|
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
192
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 };
|
|
193
457
|
const eventOutput = await this.inngest.send({
|
|
194
458
|
name: `workflow.${this.workflowId}`,
|
|
195
459
|
data: {
|
|
@@ -203,7 +467,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
203
467
|
stepResults: snapshot?.context,
|
|
204
468
|
resumePayload: resumeDataToUse,
|
|
205
469
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
206
|
-
}
|
|
470
|
+
},
|
|
471
|
+
requestContext: mergedRequestContext
|
|
207
472
|
}
|
|
208
473
|
});
|
|
209
474
|
const eventId = eventOutput.ids[0];
|
|
@@ -294,7 +559,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
294
559
|
stepResults: timeTravelData.stepResults,
|
|
295
560
|
timeTravel: timeTravelData,
|
|
296
561
|
tracingOptions: params.tracingOptions,
|
|
297
|
-
outputOptions: params.outputOptions
|
|
562
|
+
outputOptions: params.outputOptions,
|
|
563
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
298
564
|
}
|
|
299
565
|
});
|
|
300
566
|
const eventId = eventOutput.ids[0];
|
|
@@ -334,14 +600,14 @@ var InngestRun = class extends workflows.Run {
|
|
|
334
600
|
streamLegacy({ inputData, requestContext } = {}) {
|
|
335
601
|
const { readable, writable } = new TransformStream();
|
|
336
602
|
const writer = writable.getWriter();
|
|
603
|
+
void writer.write({
|
|
604
|
+
// @ts-ignore
|
|
605
|
+
type: "start",
|
|
606
|
+
// @ts-ignore
|
|
607
|
+
payload: { runId: this.runId }
|
|
608
|
+
});
|
|
337
609
|
const unwatch = this.watch(async (event) => {
|
|
338
610
|
try {
|
|
339
|
-
await writer.write({
|
|
340
|
-
// @ts-ignore
|
|
341
|
-
type: "start",
|
|
342
|
-
// @ts-ignore
|
|
343
|
-
payload: { runId: this.runId }
|
|
344
|
-
});
|
|
345
611
|
const e = {
|
|
346
612
|
...event,
|
|
347
613
|
type: event.type.replace("workflow-", "")
|
|
@@ -487,7 +753,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
487
753
|
self.closeStreamAction = async () => {
|
|
488
754
|
unwatch();
|
|
489
755
|
try {
|
|
490
|
-
|
|
756
|
+
controller.close();
|
|
491
757
|
} catch (err) {
|
|
492
758
|
console.error("Error closing stream:", err);
|
|
493
759
|
}
|
|
@@ -527,6 +793,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
527
793
|
return this.streamOutput;
|
|
528
794
|
}
|
|
529
795
|
};
|
|
796
|
+
|
|
797
|
+
// src/workflow.ts
|
|
530
798
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
531
799
|
#mastra;
|
|
532
800
|
inngest;
|
|
@@ -680,8 +948,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
680
948
|
initialState,
|
|
681
949
|
emitter,
|
|
682
950
|
retryConfig: this.retryConfig,
|
|
683
|
-
requestContext: new di.RequestContext(),
|
|
684
|
-
// TODO
|
|
951
|
+
requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
685
952
|
resume,
|
|
686
953
|
timeTravel,
|
|
687
954
|
format,
|
|
@@ -725,13 +992,48 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
725
992
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
726
993
|
}
|
|
727
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
|
|
728
1024
|
function isAgent(params) {
|
|
729
1025
|
return params?.component === "AGENT";
|
|
730
1026
|
}
|
|
731
1027
|
function isTool(params) {
|
|
732
1028
|
return params instanceof tools.Tool;
|
|
733
1029
|
}
|
|
1030
|
+
function isInngestWorkflow(params) {
|
|
1031
|
+
return params instanceof InngestWorkflow;
|
|
1032
|
+
}
|
|
734
1033
|
function createStep(params, agentOptions) {
|
|
1034
|
+
if (isInngestWorkflow(params)) {
|
|
1035
|
+
return params;
|
|
1036
|
+
}
|
|
735
1037
|
if (isAgent(params)) {
|
|
736
1038
|
return {
|
|
737
1039
|
id: params.name,
|
|
@@ -906,7 +1208,8 @@ function init(inngest) {
|
|
|
906
1208
|
inputSchema: workflow.inputSchema,
|
|
907
1209
|
outputSchema: workflow.outputSchema,
|
|
908
1210
|
steps: workflow.stepDefs,
|
|
909
|
-
mastra: workflow.mastra
|
|
1211
|
+
mastra: workflow.mastra,
|
|
1212
|
+
options: workflow.options
|
|
910
1213
|
});
|
|
911
1214
|
wf.setStepFlow(workflow.stepGraph);
|
|
912
1215
|
wf.commit();
|
|
@@ -914,856 +1217,11 @@ function init(inngest) {
|
|
|
914
1217
|
}
|
|
915
1218
|
};
|
|
916
1219
|
}
|
|
917
|
-
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
918
|
-
inngestStep;
|
|
919
|
-
inngestAttempts;
|
|
920
|
-
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
921
|
-
super({ mastra, options });
|
|
922
|
-
this.inngestStep = inngestStep;
|
|
923
|
-
this.inngestAttempts = inngestAttempts;
|
|
924
|
-
}
|
|
925
|
-
async fmtReturnValue(emitter, stepResults, lastOutput, error) {
|
|
926
|
-
const base = {
|
|
927
|
-
status: lastOutput.status,
|
|
928
|
-
steps: stepResults
|
|
929
|
-
};
|
|
930
|
-
if (lastOutput.status === "success") {
|
|
931
|
-
base.result = lastOutput.output;
|
|
932
|
-
} else if (lastOutput.status === "failed") {
|
|
933
|
-
base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
|
|
934
|
-
} else if (lastOutput.status === "suspended") {
|
|
935
|
-
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
936
|
-
if (stepResult?.status === "suspended") {
|
|
937
|
-
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
938
|
-
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
939
|
-
}
|
|
940
|
-
return [];
|
|
941
|
-
});
|
|
942
|
-
base.suspended = suspendedStepIds;
|
|
943
|
-
}
|
|
944
|
-
return base;
|
|
945
|
-
}
|
|
946
|
-
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
947
|
-
// await this.inngestStep.sleep(id, duration);
|
|
948
|
-
// }
|
|
949
|
-
async executeSleep({
|
|
950
|
-
workflowId,
|
|
951
|
-
runId,
|
|
952
|
-
entry,
|
|
953
|
-
prevOutput,
|
|
954
|
-
stepResults,
|
|
955
|
-
emitter,
|
|
956
|
-
abortController,
|
|
957
|
-
requestContext,
|
|
958
|
-
executionContext,
|
|
959
|
-
writableStream,
|
|
960
|
-
tracingContext
|
|
961
|
-
}) {
|
|
962
|
-
let { duration, fn } = entry;
|
|
963
|
-
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
964
|
-
type: observability.SpanType.WORKFLOW_SLEEP,
|
|
965
|
-
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
966
|
-
attributes: {
|
|
967
|
-
durationMs: duration,
|
|
968
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
969
|
-
},
|
|
970
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
971
|
-
});
|
|
972
|
-
if (fn) {
|
|
973
|
-
const stepCallId = crypto.randomUUID();
|
|
974
|
-
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
975
|
-
return await fn(
|
|
976
|
-
workflows.createDeprecationProxy(
|
|
977
|
-
{
|
|
978
|
-
runId,
|
|
979
|
-
workflowId,
|
|
980
|
-
mastra: this.mastra,
|
|
981
|
-
requestContext,
|
|
982
|
-
inputData: prevOutput,
|
|
983
|
-
state: executionContext.state,
|
|
984
|
-
setState: (state) => {
|
|
985
|
-
executionContext.state = state;
|
|
986
|
-
},
|
|
987
|
-
retryCount: -1,
|
|
988
|
-
tracingContext: {
|
|
989
|
-
currentSpan: sleepSpan
|
|
990
|
-
},
|
|
991
|
-
getInitData: () => stepResults?.input,
|
|
992
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
993
|
-
// TODO: this function shouldn't have suspend probably?
|
|
994
|
-
suspend: async (_suspendPayload) => {
|
|
995
|
-
},
|
|
996
|
-
bail: () => {
|
|
997
|
-
},
|
|
998
|
-
abort: () => {
|
|
999
|
-
abortController?.abort();
|
|
1000
|
-
},
|
|
1001
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1002
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1003
|
-
engine: { step: this.inngestStep },
|
|
1004
|
-
abortSignal: abortController?.signal,
|
|
1005
|
-
writer: new tools.ToolStream(
|
|
1006
|
-
{
|
|
1007
|
-
prefix: "workflow-step",
|
|
1008
|
-
callId: stepCallId,
|
|
1009
|
-
name: "sleep",
|
|
1010
|
-
runId
|
|
1011
|
-
},
|
|
1012
|
-
writableStream
|
|
1013
|
-
)
|
|
1014
|
-
},
|
|
1015
|
-
{
|
|
1016
|
-
paramName: "runCount",
|
|
1017
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1018
|
-
logger: this.logger
|
|
1019
|
-
}
|
|
1020
|
-
)
|
|
1021
|
-
);
|
|
1022
|
-
});
|
|
1023
|
-
sleepSpan?.update({
|
|
1024
|
-
attributes: {
|
|
1025
|
-
durationMs: duration
|
|
1026
|
-
}
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
try {
|
|
1030
|
-
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
1031
|
-
sleepSpan?.end();
|
|
1032
|
-
} catch (e) {
|
|
1033
|
-
sleepSpan?.error({ error: e });
|
|
1034
|
-
throw e;
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
async executeSleepUntil({
|
|
1038
|
-
workflowId,
|
|
1039
|
-
runId,
|
|
1040
|
-
entry,
|
|
1041
|
-
prevOutput,
|
|
1042
|
-
stepResults,
|
|
1043
|
-
emitter,
|
|
1044
|
-
abortController,
|
|
1045
|
-
requestContext,
|
|
1046
|
-
executionContext,
|
|
1047
|
-
writableStream,
|
|
1048
|
-
tracingContext
|
|
1049
|
-
}) {
|
|
1050
|
-
let { date, fn } = entry;
|
|
1051
|
-
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1052
|
-
type: observability.SpanType.WORKFLOW_SLEEP,
|
|
1053
|
-
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
1054
|
-
attributes: {
|
|
1055
|
-
untilDate: date,
|
|
1056
|
-
durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
|
|
1057
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
1058
|
-
},
|
|
1059
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1060
|
-
});
|
|
1061
|
-
if (fn) {
|
|
1062
|
-
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
1063
|
-
const stepCallId = crypto.randomUUID();
|
|
1064
|
-
return await fn(
|
|
1065
|
-
workflows.createDeprecationProxy(
|
|
1066
|
-
{
|
|
1067
|
-
runId,
|
|
1068
|
-
workflowId,
|
|
1069
|
-
mastra: this.mastra,
|
|
1070
|
-
requestContext,
|
|
1071
|
-
inputData: prevOutput,
|
|
1072
|
-
state: executionContext.state,
|
|
1073
|
-
setState: (state) => {
|
|
1074
|
-
executionContext.state = state;
|
|
1075
|
-
},
|
|
1076
|
-
retryCount: -1,
|
|
1077
|
-
tracingContext: {
|
|
1078
|
-
currentSpan: sleepUntilSpan
|
|
1079
|
-
},
|
|
1080
|
-
getInitData: () => stepResults?.input,
|
|
1081
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1082
|
-
// TODO: this function shouldn't have suspend probably?
|
|
1083
|
-
suspend: async (_suspendPayload) => {
|
|
1084
|
-
},
|
|
1085
|
-
bail: () => {
|
|
1086
|
-
},
|
|
1087
|
-
abort: () => {
|
|
1088
|
-
abortController?.abort();
|
|
1089
|
-
},
|
|
1090
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1091
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1092
|
-
engine: { step: this.inngestStep },
|
|
1093
|
-
abortSignal: abortController?.signal,
|
|
1094
|
-
writer: new tools.ToolStream(
|
|
1095
|
-
{
|
|
1096
|
-
prefix: "workflow-step",
|
|
1097
|
-
callId: stepCallId,
|
|
1098
|
-
name: "sleep",
|
|
1099
|
-
runId
|
|
1100
|
-
},
|
|
1101
|
-
writableStream
|
|
1102
|
-
)
|
|
1103
|
-
},
|
|
1104
|
-
{
|
|
1105
|
-
paramName: "runCount",
|
|
1106
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1107
|
-
logger: this.logger
|
|
1108
|
-
}
|
|
1109
|
-
)
|
|
1110
|
-
);
|
|
1111
|
-
});
|
|
1112
|
-
if (date && !(date instanceof Date)) {
|
|
1113
|
-
date = new Date(date);
|
|
1114
|
-
}
|
|
1115
|
-
const time = !date ? 0 : date.getTime() - Date.now();
|
|
1116
|
-
sleepUntilSpan?.update({
|
|
1117
|
-
attributes: {
|
|
1118
|
-
durationMs: Math.max(0, time)
|
|
1119
|
-
}
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
if (!(date instanceof Date)) {
|
|
1123
|
-
sleepUntilSpan?.end();
|
|
1124
|
-
return;
|
|
1125
|
-
}
|
|
1126
|
-
try {
|
|
1127
|
-
await this.inngestStep.sleepUntil(entry.id, date);
|
|
1128
|
-
sleepUntilSpan?.end();
|
|
1129
|
-
} catch (e) {
|
|
1130
|
-
sleepUntilSpan?.error({ error: e });
|
|
1131
|
-
throw e;
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
async executeStep({
|
|
1135
|
-
step,
|
|
1136
|
-
stepResults,
|
|
1137
|
-
executionContext,
|
|
1138
|
-
resume,
|
|
1139
|
-
timeTravel,
|
|
1140
|
-
prevOutput,
|
|
1141
|
-
emitter,
|
|
1142
|
-
abortController,
|
|
1143
|
-
requestContext,
|
|
1144
|
-
tracingContext,
|
|
1145
|
-
writableStream,
|
|
1146
|
-
disableScorers
|
|
1147
|
-
}) {
|
|
1148
|
-
const stepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1149
|
-
name: `workflow step: '${step.id}'`,
|
|
1150
|
-
type: observability.SpanType.WORKFLOW_STEP,
|
|
1151
|
-
input: prevOutput,
|
|
1152
|
-
attributes: {
|
|
1153
|
-
stepId: step.id
|
|
1154
|
-
},
|
|
1155
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1156
|
-
});
|
|
1157
|
-
const { inputData, validationError } = await workflows.validateStepInput({
|
|
1158
|
-
prevOutput,
|
|
1159
|
-
step,
|
|
1160
|
-
validateInputs: this.options?.validateInputs ?? true
|
|
1161
|
-
});
|
|
1162
|
-
const startedAt = await this.inngestStep.run(
|
|
1163
|
-
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
1164
|
-
async () => {
|
|
1165
|
-
const startedAt2 = Date.now();
|
|
1166
|
-
await emitter.emit("watch", {
|
|
1167
|
-
type: "workflow-step-start",
|
|
1168
|
-
payload: {
|
|
1169
|
-
id: step.id,
|
|
1170
|
-
status: "running",
|
|
1171
|
-
payload: inputData,
|
|
1172
|
-
startedAt: startedAt2
|
|
1173
|
-
}
|
|
1174
|
-
});
|
|
1175
|
-
return startedAt2;
|
|
1176
|
-
}
|
|
1177
|
-
);
|
|
1178
|
-
if (step instanceof InngestWorkflow) {
|
|
1179
|
-
const isResume = !!resume?.steps?.length;
|
|
1180
|
-
let result;
|
|
1181
|
-
let runId;
|
|
1182
|
-
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
1183
|
-
try {
|
|
1184
|
-
if (isResume) {
|
|
1185
|
-
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
1186
|
-
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1187
|
-
workflowName: step.id,
|
|
1188
|
-
runId
|
|
1189
|
-
});
|
|
1190
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1191
|
-
function: step.getFunction(),
|
|
1192
|
-
data: {
|
|
1193
|
-
inputData,
|
|
1194
|
-
initialState: executionContext.state ?? snapshot?.value ?? {},
|
|
1195
|
-
runId,
|
|
1196
|
-
resume: {
|
|
1197
|
-
runId,
|
|
1198
|
-
steps: resume.steps.slice(1),
|
|
1199
|
-
stepResults: snapshot?.context,
|
|
1200
|
-
resumePayload: resume.resumePayload,
|
|
1201
|
-
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
1202
|
-
},
|
|
1203
|
-
outputOptions: { includeState: true }
|
|
1204
|
-
}
|
|
1205
|
-
});
|
|
1206
|
-
result = invokeResp.result;
|
|
1207
|
-
runId = invokeResp.runId;
|
|
1208
|
-
executionContext.state = invokeResp.result.state;
|
|
1209
|
-
} else if (isTimeTravel) {
|
|
1210
|
-
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1211
|
-
workflowName: step.id,
|
|
1212
|
-
runId: executionContext.runId
|
|
1213
|
-
}) ?? { context: {} };
|
|
1214
|
-
const timeTravelParams = workflows.createTimeTravelExecutionParams({
|
|
1215
|
-
steps: timeTravel.steps.slice(1),
|
|
1216
|
-
inputData: timeTravel.inputData,
|
|
1217
|
-
resumeData: timeTravel.resumeData,
|
|
1218
|
-
context: timeTravel.nestedStepResults?.[step.id] ?? {},
|
|
1219
|
-
nestedStepsContext: timeTravel.nestedStepResults ?? {},
|
|
1220
|
-
snapshot,
|
|
1221
|
-
graph: step.buildExecutionGraph()
|
|
1222
|
-
});
|
|
1223
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1224
|
-
function: step.getFunction(),
|
|
1225
|
-
data: {
|
|
1226
|
-
timeTravel: timeTravelParams,
|
|
1227
|
-
initialState: executionContext.state ?? {},
|
|
1228
|
-
runId: executionContext.runId,
|
|
1229
|
-
outputOptions: { includeState: true }
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
result = invokeResp.result;
|
|
1233
|
-
runId = invokeResp.runId;
|
|
1234
|
-
executionContext.state = invokeResp.result.state;
|
|
1235
|
-
} else {
|
|
1236
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1237
|
-
function: step.getFunction(),
|
|
1238
|
-
data: {
|
|
1239
|
-
inputData,
|
|
1240
|
-
initialState: executionContext.state ?? {},
|
|
1241
|
-
outputOptions: { includeState: true }
|
|
1242
|
-
}
|
|
1243
|
-
});
|
|
1244
|
-
result = invokeResp.result;
|
|
1245
|
-
runId = invokeResp.runId;
|
|
1246
|
-
executionContext.state = invokeResp.result.state;
|
|
1247
|
-
}
|
|
1248
|
-
} catch (e) {
|
|
1249
|
-
const errorCause = e?.cause;
|
|
1250
|
-
if (errorCause && typeof errorCause === "object") {
|
|
1251
|
-
result = errorCause;
|
|
1252
|
-
runId = errorCause.runId || crypto.randomUUID();
|
|
1253
|
-
} else {
|
|
1254
|
-
runId = crypto.randomUUID();
|
|
1255
|
-
result = {
|
|
1256
|
-
status: "failed",
|
|
1257
|
-
error: e instanceof Error ? e : new Error(String(e)),
|
|
1258
|
-
steps: {},
|
|
1259
|
-
input: inputData
|
|
1260
|
-
};
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
const res = await this.inngestStep.run(
|
|
1264
|
-
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
1265
|
-
async () => {
|
|
1266
|
-
if (result.status === "failed") {
|
|
1267
|
-
await emitter.emit("watch", {
|
|
1268
|
-
type: "workflow-step-result",
|
|
1269
|
-
payload: {
|
|
1270
|
-
id: step.id,
|
|
1271
|
-
status: "failed",
|
|
1272
|
-
error: result?.error,
|
|
1273
|
-
payload: prevOutput
|
|
1274
|
-
}
|
|
1275
|
-
});
|
|
1276
|
-
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
1277
|
-
} else if (result.status === "suspended") {
|
|
1278
|
-
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
1279
|
-
const stepRes2 = stepResult;
|
|
1280
|
-
return stepRes2?.status === "suspended";
|
|
1281
|
-
});
|
|
1282
|
-
for (const [stepName, stepResult] of suspendedSteps) {
|
|
1283
|
-
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
1284
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1285
|
-
await emitter.emit("watch", {
|
|
1286
|
-
type: "workflow-step-suspended",
|
|
1287
|
-
payload: {
|
|
1288
|
-
id: step.id,
|
|
1289
|
-
status: "suspended"
|
|
1290
|
-
}
|
|
1291
|
-
});
|
|
1292
|
-
return {
|
|
1293
|
-
executionContext,
|
|
1294
|
-
result: {
|
|
1295
|
-
status: "suspended",
|
|
1296
|
-
payload: stepResult.payload,
|
|
1297
|
-
suspendPayload: {
|
|
1298
|
-
...stepResult?.suspendPayload,
|
|
1299
|
-
__workflow_meta: { runId, path: suspendPath }
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
};
|
|
1303
|
-
}
|
|
1304
|
-
return {
|
|
1305
|
-
executionContext,
|
|
1306
|
-
result: {
|
|
1307
|
-
status: "suspended",
|
|
1308
|
-
payload: {}
|
|
1309
|
-
}
|
|
1310
|
-
};
|
|
1311
|
-
}
|
|
1312
|
-
await emitter.emit("watch", {
|
|
1313
|
-
type: "workflow-step-result",
|
|
1314
|
-
payload: {
|
|
1315
|
-
id: step.id,
|
|
1316
|
-
status: "success",
|
|
1317
|
-
output: result?.result
|
|
1318
|
-
}
|
|
1319
|
-
});
|
|
1320
|
-
await emitter.emit("watch", {
|
|
1321
|
-
type: "workflow-step-finish",
|
|
1322
|
-
payload: {
|
|
1323
|
-
id: step.id,
|
|
1324
|
-
metadata: {}
|
|
1325
|
-
}
|
|
1326
|
-
});
|
|
1327
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
1328
|
-
}
|
|
1329
|
-
);
|
|
1330
|
-
Object.assign(executionContext, res.executionContext);
|
|
1331
|
-
return {
|
|
1332
|
-
...res.result,
|
|
1333
|
-
startedAt,
|
|
1334
|
-
endedAt: Date.now(),
|
|
1335
|
-
payload: inputData,
|
|
1336
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1337
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1338
|
-
};
|
|
1339
|
-
}
|
|
1340
|
-
const stepCallId = crypto.randomUUID();
|
|
1341
|
-
let stepRes;
|
|
1342
|
-
try {
|
|
1343
|
-
stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
1344
|
-
let execResults;
|
|
1345
|
-
let suspended;
|
|
1346
|
-
let bailed;
|
|
1347
|
-
const { resumeData: timeTravelResumeData, validationError: timeTravelResumeValidationError } = await workflows.validateStepResumeData({
|
|
1348
|
-
resumeData: timeTravel?.stepResults[step.id]?.status === "suspended" ? timeTravel?.resumeData : void 0,
|
|
1349
|
-
step
|
|
1350
|
-
});
|
|
1351
|
-
let resumeDataToUse;
|
|
1352
|
-
if (timeTravelResumeData && !timeTravelResumeValidationError) {
|
|
1353
|
-
resumeDataToUse = timeTravelResumeData;
|
|
1354
|
-
} else if (timeTravelResumeData && timeTravelResumeValidationError) {
|
|
1355
|
-
this.logger.warn("Time travel resume data validation failed", {
|
|
1356
|
-
stepId: step.id,
|
|
1357
|
-
error: timeTravelResumeValidationError.message
|
|
1358
|
-
});
|
|
1359
|
-
} else if (resume?.steps[0] === step.id) {
|
|
1360
|
-
resumeDataToUse = resume?.resumePayload;
|
|
1361
|
-
}
|
|
1362
|
-
try {
|
|
1363
|
-
if (validationError) {
|
|
1364
|
-
throw validationError;
|
|
1365
|
-
}
|
|
1366
|
-
const retryCount = this.getOrGenerateRetryCount(step.id);
|
|
1367
|
-
const result = await step.execute({
|
|
1368
|
-
runId: executionContext.runId,
|
|
1369
|
-
workflowId: executionContext.workflowId,
|
|
1370
|
-
mastra: this.mastra,
|
|
1371
|
-
requestContext,
|
|
1372
|
-
retryCount,
|
|
1373
|
-
writer: new tools.ToolStream(
|
|
1374
|
-
{
|
|
1375
|
-
prefix: "workflow-step",
|
|
1376
|
-
callId: stepCallId,
|
|
1377
|
-
name: step.id,
|
|
1378
|
-
runId: executionContext.runId
|
|
1379
|
-
},
|
|
1380
|
-
writableStream
|
|
1381
|
-
),
|
|
1382
|
-
state: executionContext?.state ?? {},
|
|
1383
|
-
setState: (state) => {
|
|
1384
|
-
executionContext.state = state;
|
|
1385
|
-
},
|
|
1386
|
-
inputData,
|
|
1387
|
-
resumeData: resumeDataToUse,
|
|
1388
|
-
tracingContext: {
|
|
1389
|
-
currentSpan: stepSpan
|
|
1390
|
-
},
|
|
1391
|
-
getInitData: () => stepResults?.input,
|
|
1392
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1393
|
-
suspend: async (suspendPayload, suspendOptions) => {
|
|
1394
|
-
const { suspendData, validationError: validationError2 } = await workflows.validateStepSuspendData({
|
|
1395
|
-
suspendData: suspendPayload,
|
|
1396
|
-
step
|
|
1397
|
-
});
|
|
1398
|
-
if (validationError2) {
|
|
1399
|
-
throw validationError2;
|
|
1400
|
-
}
|
|
1401
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1402
|
-
if (suspendOptions?.resumeLabel) {
|
|
1403
|
-
const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
|
|
1404
|
-
for (const label of resumeLabel) {
|
|
1405
|
-
executionContext.resumeLabels[label] = {
|
|
1406
|
-
stepId: step.id,
|
|
1407
|
-
foreachIndex: executionContext.foreachIndex
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
suspended = { payload: suspendData };
|
|
1412
|
-
},
|
|
1413
|
-
bail: (result2) => {
|
|
1414
|
-
bailed = { payload: result2 };
|
|
1415
|
-
},
|
|
1416
|
-
abort: () => {
|
|
1417
|
-
abortController?.abort();
|
|
1418
|
-
},
|
|
1419
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1420
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1421
|
-
engine: {
|
|
1422
|
-
step: this.inngestStep
|
|
1423
|
-
},
|
|
1424
|
-
abortSignal: abortController.signal
|
|
1425
|
-
});
|
|
1426
|
-
const endedAt = Date.now();
|
|
1427
|
-
execResults = {
|
|
1428
|
-
status: "success",
|
|
1429
|
-
output: result,
|
|
1430
|
-
startedAt,
|
|
1431
|
-
endedAt,
|
|
1432
|
-
payload: inputData,
|
|
1433
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1434
|
-
resumePayload: resumeDataToUse
|
|
1435
|
-
};
|
|
1436
|
-
} catch (e) {
|
|
1437
|
-
const stepFailure = {
|
|
1438
|
-
status: "failed",
|
|
1439
|
-
payload: inputData,
|
|
1440
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1441
|
-
endedAt: Date.now(),
|
|
1442
|
-
startedAt,
|
|
1443
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1444
|
-
resumePayload: resumeDataToUse
|
|
1445
|
-
};
|
|
1446
|
-
execResults = stepFailure;
|
|
1447
|
-
const fallbackErrorMessage = `Step ${step.id} failed`;
|
|
1448
|
-
stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
|
|
1449
|
-
throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
|
|
1450
|
-
cause: execResults
|
|
1451
|
-
});
|
|
1452
|
-
}
|
|
1453
|
-
if (suspended) {
|
|
1454
|
-
execResults = {
|
|
1455
|
-
status: "suspended",
|
|
1456
|
-
suspendPayload: suspended.payload,
|
|
1457
|
-
...execResults.output ? { suspendOutput: execResults.output } : {},
|
|
1458
|
-
payload: inputData,
|
|
1459
|
-
suspendedAt: Date.now(),
|
|
1460
|
-
startedAt,
|
|
1461
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1462
|
-
resumePayload: resumeDataToUse
|
|
1463
|
-
};
|
|
1464
|
-
} else if (bailed) {
|
|
1465
|
-
execResults = {
|
|
1466
|
-
status: "bailed",
|
|
1467
|
-
output: bailed.payload,
|
|
1468
|
-
payload: inputData,
|
|
1469
|
-
endedAt: Date.now(),
|
|
1470
|
-
startedAt
|
|
1471
|
-
};
|
|
1472
|
-
}
|
|
1473
|
-
if (execResults.status === "suspended") {
|
|
1474
|
-
await emitter.emit("watch", {
|
|
1475
|
-
type: "workflow-step-suspended",
|
|
1476
|
-
payload: {
|
|
1477
|
-
id: step.id,
|
|
1478
|
-
...execResults
|
|
1479
|
-
}
|
|
1480
|
-
});
|
|
1481
|
-
} else {
|
|
1482
|
-
await emitter.emit("watch", {
|
|
1483
|
-
type: "workflow-step-result",
|
|
1484
|
-
payload: {
|
|
1485
|
-
id: step.id,
|
|
1486
|
-
...execResults
|
|
1487
|
-
}
|
|
1488
|
-
});
|
|
1489
|
-
await emitter.emit("watch", {
|
|
1490
|
-
type: "workflow-step-finish",
|
|
1491
|
-
payload: {
|
|
1492
|
-
id: step.id,
|
|
1493
|
-
metadata: {}
|
|
1494
|
-
}
|
|
1495
|
-
});
|
|
1496
|
-
}
|
|
1497
|
-
stepSpan?.end({ output: execResults });
|
|
1498
|
-
return { result: execResults, executionContext, stepResults };
|
|
1499
|
-
});
|
|
1500
|
-
} catch (e) {
|
|
1501
|
-
const stepFailure = e instanceof Error ? e?.cause : {
|
|
1502
|
-
status: "failed",
|
|
1503
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1504
|
-
payload: inputData,
|
|
1505
|
-
startedAt,
|
|
1506
|
-
endedAt: Date.now()
|
|
1507
|
-
};
|
|
1508
|
-
stepRes = {
|
|
1509
|
-
result: stepFailure,
|
|
1510
|
-
executionContext,
|
|
1511
|
-
stepResults: {
|
|
1512
|
-
...stepResults,
|
|
1513
|
-
[step.id]: stepFailure
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
}
|
|
1517
|
-
if (disableScorers !== false && stepRes.result.status === "success") {
|
|
1518
|
-
await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
|
|
1519
|
-
if (step.scorers) {
|
|
1520
|
-
await this.runScorers({
|
|
1521
|
-
scorers: step.scorers,
|
|
1522
|
-
runId: executionContext.runId,
|
|
1523
|
-
input: inputData,
|
|
1524
|
-
output: stepRes.result,
|
|
1525
|
-
workflowId: executionContext.workflowId,
|
|
1526
|
-
stepId: step.id,
|
|
1527
|
-
requestContext,
|
|
1528
|
-
disableScorers,
|
|
1529
|
-
tracingContext: { currentSpan: stepSpan }
|
|
1530
|
-
});
|
|
1531
|
-
}
|
|
1532
|
-
});
|
|
1533
|
-
}
|
|
1534
|
-
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
1535
|
-
executionContext.state = stepRes.executionContext.state;
|
|
1536
|
-
return stepRes.result;
|
|
1537
|
-
}
|
|
1538
|
-
async persistStepUpdate({
|
|
1539
|
-
workflowId,
|
|
1540
|
-
runId,
|
|
1541
|
-
stepResults,
|
|
1542
|
-
resourceId,
|
|
1543
|
-
executionContext,
|
|
1544
|
-
serializedStepGraph,
|
|
1545
|
-
workflowStatus,
|
|
1546
|
-
result,
|
|
1547
|
-
error
|
|
1548
|
-
}) {
|
|
1549
|
-
await this.inngestStep.run(
|
|
1550
|
-
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
1551
|
-
async () => {
|
|
1552
|
-
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
|
|
1553
|
-
if (!shouldPersistSnapshot) {
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
1557
|
-
workflowName: workflowId,
|
|
1558
|
-
runId,
|
|
1559
|
-
resourceId,
|
|
1560
|
-
snapshot: {
|
|
1561
|
-
runId,
|
|
1562
|
-
status: workflowStatus,
|
|
1563
|
-
value: executionContext.state,
|
|
1564
|
-
context: stepResults,
|
|
1565
|
-
activePaths: executionContext.executionPath,
|
|
1566
|
-
activeStepsPath: executionContext.activeStepsPath,
|
|
1567
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1568
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1569
|
-
waitingPaths: {},
|
|
1570
|
-
serializedStepGraph,
|
|
1571
|
-
result,
|
|
1572
|
-
error,
|
|
1573
|
-
timestamp: Date.now()
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1576
|
-
}
|
|
1577
|
-
);
|
|
1578
|
-
}
|
|
1579
|
-
async executeConditional({
|
|
1580
|
-
workflowId,
|
|
1581
|
-
runId,
|
|
1582
|
-
entry,
|
|
1583
|
-
prevOutput,
|
|
1584
|
-
stepResults,
|
|
1585
|
-
timeTravel,
|
|
1586
|
-
resume,
|
|
1587
|
-
executionContext,
|
|
1588
|
-
emitter,
|
|
1589
|
-
abortController,
|
|
1590
|
-
requestContext,
|
|
1591
|
-
writableStream,
|
|
1592
|
-
disableScorers,
|
|
1593
|
-
tracingContext
|
|
1594
|
-
}) {
|
|
1595
|
-
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1596
|
-
type: observability.SpanType.WORKFLOW_CONDITIONAL,
|
|
1597
|
-
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1598
|
-
input: prevOutput,
|
|
1599
|
-
attributes: {
|
|
1600
|
-
conditionCount: entry.conditions.length
|
|
1601
|
-
},
|
|
1602
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1603
|
-
});
|
|
1604
|
-
let execResults;
|
|
1605
|
-
const truthyIndexes = (await Promise.all(
|
|
1606
|
-
entry.conditions.map(
|
|
1607
|
-
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1608
|
-
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1609
|
-
type: observability.SpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1610
|
-
name: `condition: '${index}'`,
|
|
1611
|
-
input: prevOutput,
|
|
1612
|
-
attributes: {
|
|
1613
|
-
conditionIndex: index
|
|
1614
|
-
},
|
|
1615
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1616
|
-
});
|
|
1617
|
-
try {
|
|
1618
|
-
const result = await cond(
|
|
1619
|
-
workflows.createDeprecationProxy(
|
|
1620
|
-
{
|
|
1621
|
-
runId,
|
|
1622
|
-
workflowId,
|
|
1623
|
-
mastra: this.mastra,
|
|
1624
|
-
requestContext,
|
|
1625
|
-
retryCount: -1,
|
|
1626
|
-
inputData: prevOutput,
|
|
1627
|
-
state: executionContext.state,
|
|
1628
|
-
setState: (state) => {
|
|
1629
|
-
executionContext.state = state;
|
|
1630
|
-
},
|
|
1631
|
-
tracingContext: {
|
|
1632
|
-
currentSpan: evalSpan
|
|
1633
|
-
},
|
|
1634
|
-
getInitData: () => stepResults?.input,
|
|
1635
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1636
|
-
// TODO: this function shouldn't have suspend probably?
|
|
1637
|
-
suspend: async (_suspendPayload) => {
|
|
1638
|
-
},
|
|
1639
|
-
bail: () => {
|
|
1640
|
-
},
|
|
1641
|
-
abort: () => {
|
|
1642
|
-
abortController.abort();
|
|
1643
|
-
},
|
|
1644
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1645
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1646
|
-
engine: {
|
|
1647
|
-
step: this.inngestStep
|
|
1648
|
-
},
|
|
1649
|
-
abortSignal: abortController.signal,
|
|
1650
|
-
writer: new tools.ToolStream(
|
|
1651
|
-
{
|
|
1652
|
-
prefix: "workflow-step",
|
|
1653
|
-
callId: crypto.randomUUID(),
|
|
1654
|
-
name: "conditional",
|
|
1655
|
-
runId
|
|
1656
|
-
},
|
|
1657
|
-
writableStream
|
|
1658
|
-
)
|
|
1659
|
-
},
|
|
1660
|
-
{
|
|
1661
|
-
paramName: "runCount",
|
|
1662
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1663
|
-
logger: this.logger
|
|
1664
|
-
}
|
|
1665
|
-
)
|
|
1666
|
-
);
|
|
1667
|
-
evalSpan?.end({
|
|
1668
|
-
output: result,
|
|
1669
|
-
attributes: {
|
|
1670
|
-
result: !!result
|
|
1671
|
-
}
|
|
1672
|
-
});
|
|
1673
|
-
return result ? index : null;
|
|
1674
|
-
} catch (e) {
|
|
1675
|
-
evalSpan?.error({
|
|
1676
|
-
error: e instanceof Error ? e : new Error(String(e)),
|
|
1677
|
-
attributes: {
|
|
1678
|
-
result: false
|
|
1679
|
-
}
|
|
1680
|
-
});
|
|
1681
|
-
return null;
|
|
1682
|
-
}
|
|
1683
|
-
})
|
|
1684
|
-
)
|
|
1685
|
-
)).filter((index) => index !== null);
|
|
1686
|
-
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
1687
|
-
conditionalSpan?.update({
|
|
1688
|
-
attributes: {
|
|
1689
|
-
truthyIndexes,
|
|
1690
|
-
selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
|
|
1691
|
-
}
|
|
1692
|
-
});
|
|
1693
|
-
const results = await Promise.all(
|
|
1694
|
-
stepsToRun.map(async (step, index) => {
|
|
1695
|
-
const currStepResult = stepResults[step.step.id];
|
|
1696
|
-
if (currStepResult && currStepResult.status === "success") {
|
|
1697
|
-
return currStepResult;
|
|
1698
|
-
}
|
|
1699
|
-
const result = await this.executeStep({
|
|
1700
|
-
step: step.step,
|
|
1701
|
-
prevOutput,
|
|
1702
|
-
stepResults,
|
|
1703
|
-
resume,
|
|
1704
|
-
timeTravel,
|
|
1705
|
-
executionContext: {
|
|
1706
|
-
workflowId,
|
|
1707
|
-
runId,
|
|
1708
|
-
executionPath: [...executionContext.executionPath, index],
|
|
1709
|
-
activeStepsPath: executionContext.activeStepsPath,
|
|
1710
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1711
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1712
|
-
retryConfig: executionContext.retryConfig,
|
|
1713
|
-
state: executionContext.state
|
|
1714
|
-
},
|
|
1715
|
-
emitter,
|
|
1716
|
-
abortController,
|
|
1717
|
-
requestContext,
|
|
1718
|
-
writableStream,
|
|
1719
|
-
disableScorers,
|
|
1720
|
-
tracingContext: {
|
|
1721
|
-
currentSpan: conditionalSpan
|
|
1722
|
-
}
|
|
1723
|
-
});
|
|
1724
|
-
stepResults[step.step.id] = result;
|
|
1725
|
-
return result;
|
|
1726
|
-
})
|
|
1727
|
-
);
|
|
1728
|
-
const hasFailed = results.find((result) => result.status === "failed");
|
|
1729
|
-
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
1730
|
-
if (hasFailed) {
|
|
1731
|
-
execResults = { status: "failed", error: hasFailed.error };
|
|
1732
|
-
} else if (hasSuspended) {
|
|
1733
|
-
execResults = {
|
|
1734
|
-
status: "suspended",
|
|
1735
|
-
suspendPayload: hasSuspended.suspendPayload,
|
|
1736
|
-
...hasSuspended.suspendOutput ? { suspendOutput: hasSuspended.suspendOutput } : {}
|
|
1737
|
-
};
|
|
1738
|
-
} else {
|
|
1739
|
-
execResults = {
|
|
1740
|
-
status: "success",
|
|
1741
|
-
output: results.reduce((acc, result, index) => {
|
|
1742
|
-
if (result.status === "success") {
|
|
1743
|
-
if ("step" in stepsToRun[index]) {
|
|
1744
|
-
acc[stepsToRun[index].step.id] = result.output;
|
|
1745
|
-
}
|
|
1746
|
-
}
|
|
1747
|
-
return acc;
|
|
1748
|
-
}, {})
|
|
1749
|
-
};
|
|
1750
|
-
}
|
|
1751
|
-
if (execResults.status === "failed") {
|
|
1752
|
-
conditionalSpan?.error({
|
|
1753
|
-
error: new Error(execResults.error)
|
|
1754
|
-
});
|
|
1755
|
-
} else {
|
|
1756
|
-
conditionalSpan?.end({
|
|
1757
|
-
output: execResults.output || execResults
|
|
1758
|
-
});
|
|
1759
|
-
}
|
|
1760
|
-
return execResults;
|
|
1761
|
-
}
|
|
1762
|
-
};
|
|
1763
1220
|
|
|
1764
1221
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
1765
1222
|
exports.InngestRun = InngestRun;
|
|
1766
1223
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1224
|
+
exports._compatibilityCheck = _compatibilityCheck;
|
|
1767
1225
|
exports.createStep = createStep;
|
|
1768
1226
|
exports.init = init;
|
|
1769
1227
|
exports.serve = serve;
|