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