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