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