@mastra/inngest 0.0.0-bundle-recursion-20251030002519 → 0.0.0-bundle-studio-cloud-20251222034739
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 +874 -3
- package/dist/execution-engine.d.ts +109 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/index.cjs +924 -1112
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +20 -298
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +926 -1116
- 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 +18 -14
package/dist/index.cjs
CHANGED
|
@@ -1,43 +1,475 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var crypto = require('crypto');
|
|
4
|
-
var web = require('stream/web');
|
|
5
|
-
var realtime = require('@inngest/realtime');
|
|
6
|
-
var aiTracing = require('@mastra/core/ai-tracing');
|
|
7
|
-
var di = require('@mastra/core/di');
|
|
8
|
-
var stream = require('@mastra/core/stream');
|
|
9
3
|
var tools = require('@mastra/core/tools');
|
|
10
4
|
var workflows = require('@mastra/core/workflows');
|
|
11
5
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
6
|
+
var zod = require('zod');
|
|
7
|
+
var crypto$1 = require('crypto');
|
|
8
|
+
var di = require('@mastra/core/di');
|
|
12
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');
|
|
13
15
|
var hono = require('inngest/hono');
|
|
14
|
-
var zod = require('zod');
|
|
15
16
|
|
|
16
17
|
// src/index.ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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 });
|
|
30
75
|
}
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
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
|
+
};
|
|
41
473
|
var InngestRun = class extends workflows.Run {
|
|
42
474
|
inngest;
|
|
43
475
|
serializedStepGraph;
|
|
@@ -49,63 +481,111 @@ var InngestRun = class extends workflows.Run {
|
|
|
49
481
|
this.#mastra = params.mastra;
|
|
50
482
|
}
|
|
51
483
|
async getRuns(eventId) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
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
|
+
}
|
|
55
516
|
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return json.data;
|
|
517
|
+
}
|
|
518
|
+
throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
59
519
|
}
|
|
60
|
-
async getRunOutput(eventId) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
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
|
+
}
|
|
65
538
|
if (runs?.[0]?.status === "Failed") {
|
|
66
|
-
const snapshot = await
|
|
539
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
67
540
|
workflowName: this.workflowId,
|
|
68
541
|
runId: this.runId
|
|
69
542
|
});
|
|
543
|
+
if (snapshot?.context) {
|
|
544
|
+
snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
|
|
545
|
+
}
|
|
70
546
|
return {
|
|
71
|
-
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
|
+
}
|
|
72
555
|
};
|
|
73
556
|
}
|
|
74
557
|
if (runs?.[0]?.status === "Cancelled") {
|
|
75
|
-
const snapshot = await
|
|
558
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
76
559
|
workflowName: this.workflowId,
|
|
77
560
|
runId: this.runId
|
|
78
561
|
});
|
|
79
562
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
80
563
|
}
|
|
564
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
81
565
|
}
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
async sendEvent(event, data) {
|
|
85
|
-
await this.inngest.send({
|
|
86
|
-
name: `user-event-${event}`,
|
|
87
|
-
data
|
|
88
|
-
});
|
|
566
|
+
throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
89
567
|
}
|
|
90
568
|
async cancel() {
|
|
569
|
+
const storage = this.#mastra?.getStorage();
|
|
91
570
|
await this.inngest.send({
|
|
92
571
|
name: `cancel.workflow.${this.workflowId}`,
|
|
93
572
|
data: {
|
|
94
573
|
runId: this.runId
|
|
95
574
|
}
|
|
96
575
|
});
|
|
97
|
-
const snapshot = await
|
|
576
|
+
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
98
577
|
workflowName: this.workflowId,
|
|
99
578
|
runId: this.runId
|
|
100
579
|
});
|
|
101
580
|
if (snapshot) {
|
|
102
|
-
await
|
|
581
|
+
await storage?.persistWorkflowSnapshot({
|
|
103
582
|
workflowName: this.workflowId,
|
|
104
583
|
runId: this.runId,
|
|
105
584
|
resourceId: this.resourceId,
|
|
106
585
|
snapshot: {
|
|
107
586
|
...snapshot,
|
|
108
|
-
status: "canceled"
|
|
587
|
+
status: "canceled",
|
|
588
|
+
value: snapshot.value
|
|
109
589
|
}
|
|
110
590
|
});
|
|
111
591
|
}
|
|
@@ -113,12 +593,58 @@ var InngestRun = class extends workflows.Run {
|
|
|
113
593
|
async start(params) {
|
|
114
594
|
return this._start(params);
|
|
115
595
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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) {
|
|
603
|
+
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
604
|
+
workflowName: this.workflowId,
|
|
605
|
+
runId: this.runId,
|
|
606
|
+
resourceId: this.resourceId,
|
|
607
|
+
snapshot: {
|
|
608
|
+
runId: this.runId,
|
|
609
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
610
|
+
status: "running",
|
|
611
|
+
value: {},
|
|
612
|
+
context: {},
|
|
613
|
+
activePaths: [],
|
|
614
|
+
suspendedPaths: {},
|
|
615
|
+
activeStepsPath: {},
|
|
616
|
+
resumeLabels: {},
|
|
617
|
+
waitingPaths: {},
|
|
618
|
+
timestamp: Date.now()
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
const inputDataToUse = await this._validateInput(params.inputData);
|
|
622
|
+
const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
|
|
623
|
+
const eventOutput = await this.inngest.send({
|
|
624
|
+
name: `workflow.${this.workflowId}`,
|
|
625
|
+
data: {
|
|
626
|
+
inputData: inputDataToUse,
|
|
627
|
+
initialState: initialStateToUse,
|
|
628
|
+
runId: this.runId,
|
|
629
|
+
resourceId: this.resourceId,
|
|
630
|
+
outputOptions: params.outputOptions,
|
|
631
|
+
tracingOptions: params.tracingOptions,
|
|
632
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
const eventId = eventOutput.ids[0];
|
|
636
|
+
if (!eventId) {
|
|
637
|
+
throw new Error("Event ID is not set");
|
|
638
|
+
}
|
|
639
|
+
return { runId: this.runId };
|
|
640
|
+
}
|
|
641
|
+
async _start({
|
|
642
|
+
inputData,
|
|
643
|
+
initialState,
|
|
644
|
+
outputOptions,
|
|
120
645
|
tracingOptions,
|
|
121
|
-
format
|
|
646
|
+
format,
|
|
647
|
+
requestContext
|
|
122
648
|
}) {
|
|
123
649
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
124
650
|
workflowName: this.workflowId,
|
|
@@ -127,14 +653,15 @@ var InngestRun = class extends workflows.Run {
|
|
|
127
653
|
snapshot: {
|
|
128
654
|
runId: this.runId,
|
|
129
655
|
serializedStepGraph: this.serializedStepGraph,
|
|
656
|
+
status: "running",
|
|
130
657
|
value: {},
|
|
131
658
|
context: {},
|
|
132
659
|
activePaths: [],
|
|
133
660
|
suspendedPaths: {},
|
|
661
|
+
activeStepsPath: {},
|
|
134
662
|
resumeLabels: {},
|
|
135
663
|
waitingPaths: {},
|
|
136
|
-
timestamp: Date.now()
|
|
137
|
-
status: "running"
|
|
664
|
+
timestamp: Date.now()
|
|
138
665
|
}
|
|
139
666
|
});
|
|
140
667
|
const inputDataToUse = await this._validateInput(inputData);
|
|
@@ -148,7 +675,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
148
675
|
resourceId: this.resourceId,
|
|
149
676
|
outputOptions,
|
|
150
677
|
tracingOptions,
|
|
151
|
-
format
|
|
678
|
+
format,
|
|
679
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
152
680
|
}
|
|
153
681
|
});
|
|
154
682
|
const eventId = eventOutput.ids[0];
|
|
@@ -157,9 +685,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
157
685
|
}
|
|
158
686
|
const runOutput = await this.getRunOutput(eventId);
|
|
159
687
|
const result = runOutput?.output?.result;
|
|
160
|
-
|
|
161
|
-
result.error = new Error(result.error);
|
|
162
|
-
}
|
|
688
|
+
this.hydrateFailedResult(result);
|
|
163
689
|
if (result.status !== "suspended") {
|
|
164
690
|
this.cleanup?.();
|
|
165
691
|
}
|
|
@@ -177,15 +703,24 @@ var InngestRun = class extends workflows.Run {
|
|
|
177
703
|
return p;
|
|
178
704
|
}
|
|
179
705
|
async _resume(params) {
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
)
|
|
183
|
-
|
|
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({
|
|
184
716
|
workflowName: this.workflowId,
|
|
185
717
|
runId: this.runId
|
|
186
718
|
});
|
|
187
719
|
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
188
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 };
|
|
189
724
|
const eventOutput = await this.inngest.send({
|
|
190
725
|
name: `workflow.${this.workflowId}`,
|
|
191
726
|
data: {
|
|
@@ -198,9 +733,9 @@ var InngestRun = class extends workflows.Run {
|
|
|
198
733
|
steps,
|
|
199
734
|
stepResults: snapshot?.context,
|
|
200
735
|
resumePayload: resumeDataToUse,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
736
|
+
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
737
|
+
},
|
|
738
|
+
requestContext: mergedRequestContext
|
|
204
739
|
}
|
|
205
740
|
});
|
|
206
741
|
const eventId = eventOutput.ids[0];
|
|
@@ -209,17 +744,105 @@ var InngestRun = class extends workflows.Run {
|
|
|
209
744
|
}
|
|
210
745
|
const runOutput = await this.getRunOutput(eventId);
|
|
211
746
|
const result = runOutput?.output?.result;
|
|
212
|
-
|
|
213
|
-
|
|
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");
|
|
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");
|
|
214
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);
|
|
215
838
|
return result;
|
|
216
839
|
}
|
|
217
|
-
watch(cb
|
|
840
|
+
watch(cb) {
|
|
218
841
|
let active = true;
|
|
219
842
|
const streamPromise = realtime.subscribe(
|
|
220
843
|
{
|
|
221
844
|
channel: `workflow:${this.workflowId}:${this.runId}`,
|
|
222
|
-
topics: [
|
|
845
|
+
topics: ["watch"],
|
|
223
846
|
app: this.inngest
|
|
224
847
|
},
|
|
225
848
|
(message) => {
|
|
@@ -237,17 +860,17 @@ var InngestRun = class extends workflows.Run {
|
|
|
237
860
|
});
|
|
238
861
|
};
|
|
239
862
|
}
|
|
240
|
-
streamLegacy({ inputData,
|
|
863
|
+
streamLegacy({ inputData, requestContext } = {}) {
|
|
241
864
|
const { readable, writable } = new TransformStream();
|
|
242
865
|
const writer = writable.getWriter();
|
|
866
|
+
void writer.write({
|
|
867
|
+
// @ts-ignore
|
|
868
|
+
type: "start",
|
|
869
|
+
// @ts-ignore
|
|
870
|
+
payload: { runId: this.runId }
|
|
871
|
+
});
|
|
243
872
|
const unwatch = this.watch(async (event) => {
|
|
244
873
|
try {
|
|
245
|
-
await writer.write({
|
|
246
|
-
// @ts-ignore
|
|
247
|
-
type: "start",
|
|
248
|
-
// @ts-ignore
|
|
249
|
-
payload: { runId: this.runId }
|
|
250
|
-
});
|
|
251
874
|
const e = {
|
|
252
875
|
...event,
|
|
253
876
|
type: event.type.replace("workflow-", "")
|
|
@@ -259,7 +882,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
259
882
|
await writer.write(e);
|
|
260
883
|
} catch {
|
|
261
884
|
}
|
|
262
|
-
}
|
|
885
|
+
});
|
|
263
886
|
this.closeStreamAction = async () => {
|
|
264
887
|
await writer.write({
|
|
265
888
|
type: "finish",
|
|
@@ -275,7 +898,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
275
898
|
writer.releaseLock();
|
|
276
899
|
}
|
|
277
900
|
};
|
|
278
|
-
this.executionResults = this._start({ inputData,
|
|
901
|
+
this.executionResults = this._start({ inputData, requestContext, format: "legacy" }).then((result) => {
|
|
279
902
|
if (result.status !== "suspended") {
|
|
280
903
|
this.closeStreamAction?.().catch(() => {
|
|
281
904
|
});
|
|
@@ -289,7 +912,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
289
912
|
}
|
|
290
913
|
stream({
|
|
291
914
|
inputData,
|
|
292
|
-
|
|
915
|
+
requestContext,
|
|
293
916
|
tracingOptions,
|
|
294
917
|
closeOnSuspend = true,
|
|
295
918
|
initialState,
|
|
@@ -313,7 +936,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
313
936
|
...payload
|
|
314
937
|
}
|
|
315
938
|
});
|
|
316
|
-
}
|
|
939
|
+
});
|
|
317
940
|
self.closeStreamAction = async () => {
|
|
318
941
|
unwatch();
|
|
319
942
|
try {
|
|
@@ -324,7 +947,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
324
947
|
};
|
|
325
948
|
const executionResultsPromise = self._start({
|
|
326
949
|
inputData,
|
|
327
|
-
|
|
950
|
+
requestContext,
|
|
328
951
|
// tracingContext, // We are not able to pass a reference to a span here, what to do?
|
|
329
952
|
initialState,
|
|
330
953
|
tracingOptions,
|
|
@@ -363,7 +986,90 @@ var InngestRun = class extends workflows.Run {
|
|
|
363
986
|
streamVNext(args = {}) {
|
|
364
987
|
return this.stream(args);
|
|
365
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
|
+
}
|
|
366
1070
|
};
|
|
1071
|
+
|
|
1072
|
+
// src/workflow.ts
|
|
367
1073
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
368
1074
|
#mastra;
|
|
369
1075
|
inngest;
|
|
@@ -372,6 +1078,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
372
1078
|
constructor(params, inngest) {
|
|
373
1079
|
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
374
1080
|
super(workflowParams);
|
|
1081
|
+
this.engineType = "inngest";
|
|
375
1082
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
376
1083
|
([_, value]) => value !== void 0
|
|
377
1084
|
);
|
|
@@ -379,13 +1086,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
379
1086
|
this.#mastra = params.mastra;
|
|
380
1087
|
this.inngest = inngest;
|
|
381
1088
|
}
|
|
382
|
-
async
|
|
1089
|
+
async listWorkflowRuns(args) {
|
|
383
1090
|
const storage = this.#mastra?.getStorage();
|
|
384
1091
|
if (!storage) {
|
|
385
1092
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
386
1093
|
return { runs: [], total: 0 };
|
|
387
1094
|
}
|
|
388
|
-
return storage.
|
|
1095
|
+
return storage.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
389
1096
|
}
|
|
390
1097
|
async getWorkflowRunById(runId) {
|
|
391
1098
|
const storage = this.#mastra?.getStorage();
|
|
@@ -397,6 +1104,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
397
1104
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
398
1105
|
}
|
|
399
1106
|
__registerMastra(mastra) {
|
|
1107
|
+
super.__registerMastra(mastra);
|
|
400
1108
|
this.#mastra = mastra;
|
|
401
1109
|
this.executionEngine.__registerMastra(mastra);
|
|
402
1110
|
const updateNested = (step) => {
|
|
@@ -414,17 +1122,8 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
414
1122
|
}
|
|
415
1123
|
}
|
|
416
1124
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
* @throws {Error} Always throws an error directing users to use createRunAsync()
|
|
420
|
-
*/
|
|
421
|
-
createRun(_options) {
|
|
422
|
-
throw new Error(
|
|
423
|
-
"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."
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
async createRunAsync(options) {
|
|
427
|
-
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
1125
|
+
async createRun(options) {
|
|
1126
|
+
const runIdToUse = options?.runId || crypto$1.randomUUID();
|
|
428
1127
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
429
1128
|
{
|
|
430
1129
|
workflowId: this.id,
|
|
@@ -436,7 +1135,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
436
1135
|
mastra: this.#mastra,
|
|
437
1136
|
retryConfig: this.retryConfig,
|
|
438
1137
|
cleanup: () => this.runs.delete(runIdToUse),
|
|
439
|
-
workflowSteps: this.steps
|
|
1138
|
+
workflowSteps: this.steps,
|
|
1139
|
+
workflowEngineType: this.engineType,
|
|
1140
|
+
validateInputs: this.options.validateInputs
|
|
440
1141
|
},
|
|
441
1142
|
this.inngest
|
|
442
1143
|
);
|
|
@@ -445,7 +1146,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
445
1146
|
workflowStatus: run.workflowRunStatus,
|
|
446
1147
|
stepResults: {}
|
|
447
1148
|
});
|
|
448
|
-
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse,
|
|
1149
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
|
|
1150
|
+
withNestedWorkflows: false
|
|
1151
|
+
});
|
|
449
1152
|
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
450
1153
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
451
1154
|
workflowName: this.id,
|
|
@@ -457,13 +1160,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
457
1160
|
value: {},
|
|
458
1161
|
context: {},
|
|
459
1162
|
activePaths: [],
|
|
1163
|
+
activeStepsPath: {},
|
|
460
1164
|
waitingPaths: {},
|
|
461
1165
|
serializedStepGraph: this.serializedStepGraph,
|
|
462
1166
|
suspendedPaths: {},
|
|
463
1167
|
resumeLabels: {},
|
|
464
1168
|
result: void 0,
|
|
465
1169
|
error: void 0,
|
|
466
|
-
// @ts-ignore
|
|
467
1170
|
timestamp: Date.now()
|
|
468
1171
|
}
|
|
469
1172
|
});
|
|
@@ -477,42 +1180,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
477
1180
|
this.function = this.inngest.createFunction(
|
|
478
1181
|
{
|
|
479
1182
|
id: `workflow.${this.id}`,
|
|
480
|
-
|
|
481
|
-
retries: this.retryConfig?.attempts ?? 0,
|
|
1183
|
+
retries: Math.min(this.retryConfig?.attempts ?? 0, 20),
|
|
482
1184
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
483
1185
|
// Spread flow control configuration
|
|
484
1186
|
...this.flowControlConfig
|
|
485
1187
|
},
|
|
486
1188
|
{ event: `workflow.${this.id}` },
|
|
487
1189
|
async ({ event, step, attempt, publish }) => {
|
|
488
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format } = event.data;
|
|
1190
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
489
1191
|
if (!runId) {
|
|
490
1192
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
491
|
-
return crypto.randomUUID();
|
|
1193
|
+
return crypto$1.randomUUID();
|
|
492
1194
|
});
|
|
493
1195
|
}
|
|
494
|
-
const
|
|
495
|
-
emit: async (event2, data) => {
|
|
496
|
-
if (!publish) {
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
try {
|
|
500
|
-
await publish({
|
|
501
|
-
channel: `workflow:${this.id}:${runId}`,
|
|
502
|
-
topic: event2,
|
|
503
|
-
data
|
|
504
|
-
});
|
|
505
|
-
} catch (err) {
|
|
506
|
-
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
507
|
-
}
|
|
508
|
-
},
|
|
509
|
-
on: (_event, _callback) => {
|
|
510
|
-
},
|
|
511
|
-
off: (_event, _callback) => {
|
|
512
|
-
},
|
|
513
|
-
once: (_event, _callback) => {
|
|
514
|
-
}
|
|
515
|
-
};
|
|
1196
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
516
1197
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
517
1198
|
const result = await engine.execute({
|
|
518
1199
|
workflowId: this.id,
|
|
@@ -522,23 +1203,29 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
522
1203
|
serializedStepGraph: this.serializedStepGraph,
|
|
523
1204
|
input: inputData,
|
|
524
1205
|
initialState,
|
|
525
|
-
|
|
1206
|
+
pubsub,
|
|
526
1207
|
retryConfig: this.retryConfig,
|
|
527
|
-
|
|
528
|
-
// TODO
|
|
1208
|
+
requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
529
1209
|
resume,
|
|
1210
|
+
timeTravel,
|
|
530
1211
|
format,
|
|
531
1212
|
abortController: new AbortController(),
|
|
532
|
-
// currentSpan: undefined, // TODO: Pass actual parent
|
|
1213
|
+
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
533
1214
|
outputOptions,
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
1215
|
+
outputWriter: async (chunk) => {
|
|
1216
|
+
try {
|
|
1217
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1218
|
+
type: "watch",
|
|
1219
|
+
runId,
|
|
1220
|
+
data: chunk
|
|
537
1221
|
});
|
|
1222
|
+
} catch (err) {
|
|
1223
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
538
1224
|
}
|
|
539
|
-
}
|
|
1225
|
+
}
|
|
540
1226
|
});
|
|
541
1227
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1228
|
+
await engine.invokeLifecycleCallbacksInternal(result);
|
|
542
1229
|
if (result.status === "failed") {
|
|
543
1230
|
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
544
1231
|
cause: result
|
|
@@ -568,32 +1255,65 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
568
1255
|
return [this.getFunction(), ...this.getNestedFunctions(this.executionGraph.steps)];
|
|
569
1256
|
}
|
|
570
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
|
|
571
1287
|
function isAgent(params) {
|
|
572
1288
|
return params?.component === "AGENT";
|
|
573
1289
|
}
|
|
574
1290
|
function isTool(params) {
|
|
575
1291
|
return params instanceof tools.Tool;
|
|
576
1292
|
}
|
|
1293
|
+
function isInngestWorkflow(params) {
|
|
1294
|
+
return params instanceof InngestWorkflow;
|
|
1295
|
+
}
|
|
577
1296
|
function createStep(params, agentOptions) {
|
|
1297
|
+
if (isInngestWorkflow(params)) {
|
|
1298
|
+
return params;
|
|
1299
|
+
}
|
|
578
1300
|
if (isAgent(params)) {
|
|
1301
|
+
const outputSchema = agentOptions?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
|
|
579
1302
|
return {
|
|
580
1303
|
id: params.name,
|
|
581
1304
|
description: params.getDescription(),
|
|
582
|
-
// @ts-ignore
|
|
583
1305
|
inputSchema: zod.z.object({
|
|
584
1306
|
prompt: zod.z.string()
|
|
585
1307
|
// resourceId: z.string().optional(),
|
|
586
1308
|
// threadId: z.string().optional(),
|
|
587
1309
|
}),
|
|
588
|
-
|
|
589
|
-
outputSchema: zod.z.object({
|
|
590
|
-
text: zod.z.string()
|
|
591
|
-
}),
|
|
1310
|
+
outputSchema,
|
|
592
1311
|
execute: async ({
|
|
593
1312
|
inputData,
|
|
594
|
-
|
|
1313
|
+
runId,
|
|
1314
|
+
[_constants.PUBSUB_SYMBOL]: pubsub,
|
|
595
1315
|
[_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
596
|
-
|
|
1316
|
+
requestContext,
|
|
597
1317
|
tracingContext,
|
|
598
1318
|
abortSignal,
|
|
599
1319
|
abort,
|
|
@@ -604,6 +1324,7 @@ function createStep(params, agentOptions) {
|
|
|
604
1324
|
streamPromise.resolve = resolve;
|
|
605
1325
|
streamPromise.reject = reject;
|
|
606
1326
|
});
|
|
1327
|
+
let structuredResult = null;
|
|
607
1328
|
const toolData = {
|
|
608
1329
|
name: params.name,
|
|
609
1330
|
args: inputData
|
|
@@ -614,9 +1335,13 @@ function createStep(params, agentOptions) {
|
|
|
614
1335
|
...agentOptions ?? {},
|
|
615
1336
|
// resourceId: inputData.resourceId,
|
|
616
1337
|
// threadId: inputData.threadId,
|
|
617
|
-
|
|
1338
|
+
requestContext,
|
|
618
1339
|
tracingContext,
|
|
619
1340
|
onFinish: (result) => {
|
|
1341
|
+
const resultWithObject = result;
|
|
1342
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1343
|
+
structuredResult = resultWithObject.object;
|
|
1344
|
+
}
|
|
620
1345
|
streamPromise.resolve(result.text);
|
|
621
1346
|
void agentOptions?.onFinish?.(result);
|
|
622
1347
|
},
|
|
@@ -626,9 +1351,13 @@ function createStep(params, agentOptions) {
|
|
|
626
1351
|
} else {
|
|
627
1352
|
const modelOutput = await params.stream(inputData.prompt, {
|
|
628
1353
|
...agentOptions ?? {},
|
|
629
|
-
|
|
1354
|
+
requestContext,
|
|
630
1355
|
tracingContext,
|
|
631
1356
|
onFinish: (result) => {
|
|
1357
|
+
const resultWithObject = result;
|
|
1358
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1359
|
+
structuredResult = resultWithObject.object;
|
|
1360
|
+
}
|
|
632
1361
|
streamPromise.resolve(result.text);
|
|
633
1362
|
void agentOptions?.onFinish?.(result);
|
|
634
1363
|
},
|
|
@@ -637,22 +1366,24 @@ function createStep(params, agentOptions) {
|
|
|
637
1366
|
stream = modelOutput.fullStream;
|
|
638
1367
|
}
|
|
639
1368
|
if (streamFormat === "legacy") {
|
|
640
|
-
await
|
|
641
|
-
type: "
|
|
642
|
-
|
|
1369
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1370
|
+
type: "watch",
|
|
1371
|
+
runId,
|
|
1372
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
643
1373
|
});
|
|
644
1374
|
for await (const chunk of stream) {
|
|
645
1375
|
if (chunk.type === "text-delta") {
|
|
646
|
-
await
|
|
647
|
-
type: "
|
|
648
|
-
|
|
649
|
-
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 }
|
|
650
1380
|
});
|
|
651
1381
|
}
|
|
652
1382
|
}
|
|
653
|
-
await
|
|
654
|
-
type: "
|
|
655
|
-
|
|
1383
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1384
|
+
type: "watch",
|
|
1385
|
+
runId,
|
|
1386
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
656
1387
|
});
|
|
657
1388
|
} else {
|
|
658
1389
|
for await (const chunk of stream) {
|
|
@@ -662,6 +1393,9 @@ function createStep(params, agentOptions) {
|
|
|
662
1393
|
if (abortSignal.aborted) {
|
|
663
1394
|
return abort();
|
|
664
1395
|
}
|
|
1396
|
+
if (structuredResult !== null) {
|
|
1397
|
+
return structuredResult;
|
|
1398
|
+
}
|
|
665
1399
|
return {
|
|
666
1400
|
text: await streamPromise.promise
|
|
667
1401
|
};
|
|
@@ -675,20 +1409,38 @@ function createStep(params, agentOptions) {
|
|
|
675
1409
|
}
|
|
676
1410
|
return {
|
|
677
1411
|
// TODO: tool probably should have strong id type
|
|
678
|
-
// @ts-ignore
|
|
679
1412
|
id: params.id,
|
|
680
1413
|
description: params.description,
|
|
681
1414
|
inputSchema: params.inputSchema,
|
|
682
1415
|
outputSchema: params.outputSchema,
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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,
|
|
688
1433
|
tracingContext,
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
1434
|
+
workflow: {
|
|
1435
|
+
runId,
|
|
1436
|
+
resumeData,
|
|
1437
|
+
suspend,
|
|
1438
|
+
workflowId,
|
|
1439
|
+
state,
|
|
1440
|
+
setState
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
return params.execute(inputData, toolContext);
|
|
692
1444
|
},
|
|
693
1445
|
component: "TOOL"
|
|
694
1446
|
};
|
|
@@ -722,6 +1474,8 @@ function init(inngest) {
|
|
|
722
1474
|
suspendSchema: step.suspendSchema,
|
|
723
1475
|
stateSchema: step.stateSchema,
|
|
724
1476
|
execute: step.execute,
|
|
1477
|
+
retries: step.retries,
|
|
1478
|
+
scorers: step.scorers,
|
|
725
1479
|
component: step.component
|
|
726
1480
|
};
|
|
727
1481
|
},
|
|
@@ -731,7 +1485,8 @@ function init(inngest) {
|
|
|
731
1485
|
inputSchema: workflow.inputSchema,
|
|
732
1486
|
outputSchema: workflow.outputSchema,
|
|
733
1487
|
steps: workflow.stepDefs,
|
|
734
|
-
mastra: workflow.mastra
|
|
1488
|
+
mastra: workflow.mastra,
|
|
1489
|
+
options: workflow.options
|
|
735
1490
|
});
|
|
736
1491
|
wf.setStepFlow(workflow.stepGraph);
|
|
737
1492
|
wf.commit();
|
|
@@ -739,955 +1494,12 @@ function init(inngest) {
|
|
|
739
1494
|
}
|
|
740
1495
|
};
|
|
741
1496
|
}
|
|
742
|
-
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
743
|
-
inngestStep;
|
|
744
|
-
inngestAttempts;
|
|
745
|
-
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
746
|
-
super({ mastra, options });
|
|
747
|
-
this.inngestStep = inngestStep;
|
|
748
|
-
this.inngestAttempts = inngestAttempts;
|
|
749
|
-
}
|
|
750
|
-
async fmtReturnValue(emitter, stepResults, lastOutput, error) {
|
|
751
|
-
const base = {
|
|
752
|
-
status: lastOutput.status,
|
|
753
|
-
steps: stepResults
|
|
754
|
-
};
|
|
755
|
-
if (lastOutput.status === "success") {
|
|
756
|
-
await emitter.emit("watch", {
|
|
757
|
-
type: "watch",
|
|
758
|
-
payload: {
|
|
759
|
-
workflowState: {
|
|
760
|
-
status: lastOutput.status,
|
|
761
|
-
steps: stepResults,
|
|
762
|
-
result: lastOutput.output
|
|
763
|
-
}
|
|
764
|
-
},
|
|
765
|
-
eventTimestamp: Date.now()
|
|
766
|
-
});
|
|
767
|
-
base.result = lastOutput.output;
|
|
768
|
-
} else if (lastOutput.status === "failed") {
|
|
769
|
-
base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
|
|
770
|
-
await emitter.emit("watch", {
|
|
771
|
-
type: "watch",
|
|
772
|
-
payload: {
|
|
773
|
-
workflowState: {
|
|
774
|
-
status: lastOutput.status,
|
|
775
|
-
steps: stepResults,
|
|
776
|
-
result: null,
|
|
777
|
-
error: base.error
|
|
778
|
-
}
|
|
779
|
-
},
|
|
780
|
-
eventTimestamp: Date.now()
|
|
781
|
-
});
|
|
782
|
-
} else if (lastOutput.status === "suspended") {
|
|
783
|
-
await emitter.emit("watch", {
|
|
784
|
-
type: "watch",
|
|
785
|
-
payload: {
|
|
786
|
-
workflowState: {
|
|
787
|
-
status: lastOutput.status,
|
|
788
|
-
steps: stepResults,
|
|
789
|
-
result: null,
|
|
790
|
-
error: null
|
|
791
|
-
}
|
|
792
|
-
},
|
|
793
|
-
eventTimestamp: Date.now()
|
|
794
|
-
});
|
|
795
|
-
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
796
|
-
if (stepResult?.status === "suspended") {
|
|
797
|
-
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
798
|
-
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
799
|
-
}
|
|
800
|
-
return [];
|
|
801
|
-
});
|
|
802
|
-
base.suspended = suspendedStepIds;
|
|
803
|
-
}
|
|
804
|
-
return base;
|
|
805
|
-
}
|
|
806
|
-
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
807
|
-
// await this.inngestStep.sleep(id, duration);
|
|
808
|
-
// }
|
|
809
|
-
async executeSleep({
|
|
810
|
-
workflowId,
|
|
811
|
-
runId,
|
|
812
|
-
entry,
|
|
813
|
-
prevOutput,
|
|
814
|
-
stepResults,
|
|
815
|
-
emitter,
|
|
816
|
-
abortController,
|
|
817
|
-
runtimeContext,
|
|
818
|
-
executionContext,
|
|
819
|
-
writableStream,
|
|
820
|
-
tracingContext
|
|
821
|
-
}) {
|
|
822
|
-
let { duration, fn } = entry;
|
|
823
|
-
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
824
|
-
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
825
|
-
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
826
|
-
attributes: {
|
|
827
|
-
durationMs: duration,
|
|
828
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
829
|
-
},
|
|
830
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
831
|
-
});
|
|
832
|
-
if (fn) {
|
|
833
|
-
const stepCallId = crypto.randomUUID();
|
|
834
|
-
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
835
|
-
return await fn(
|
|
836
|
-
workflows.createDeprecationProxy(
|
|
837
|
-
{
|
|
838
|
-
runId,
|
|
839
|
-
workflowId,
|
|
840
|
-
mastra: this.mastra,
|
|
841
|
-
runtimeContext,
|
|
842
|
-
inputData: prevOutput,
|
|
843
|
-
state: executionContext.state,
|
|
844
|
-
setState: (state) => {
|
|
845
|
-
executionContext.state = state;
|
|
846
|
-
},
|
|
847
|
-
runCount: -1,
|
|
848
|
-
retryCount: -1,
|
|
849
|
-
tracingContext: {
|
|
850
|
-
currentSpan: sleepSpan
|
|
851
|
-
},
|
|
852
|
-
getInitData: () => stepResults?.input,
|
|
853
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
854
|
-
// TODO: this function shouldn't have suspend probably?
|
|
855
|
-
suspend: async (_suspendPayload) => {
|
|
856
|
-
},
|
|
857
|
-
bail: () => {
|
|
858
|
-
},
|
|
859
|
-
abort: () => {
|
|
860
|
-
abortController?.abort();
|
|
861
|
-
},
|
|
862
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
863
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
864
|
-
engine: { step: this.inngestStep },
|
|
865
|
-
abortSignal: abortController?.signal,
|
|
866
|
-
writer: new tools.ToolStream(
|
|
867
|
-
{
|
|
868
|
-
prefix: "workflow-step",
|
|
869
|
-
callId: stepCallId,
|
|
870
|
-
name: "sleep",
|
|
871
|
-
runId
|
|
872
|
-
},
|
|
873
|
-
writableStream
|
|
874
|
-
)
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
paramName: "runCount",
|
|
878
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
879
|
-
logger: this.logger
|
|
880
|
-
}
|
|
881
|
-
)
|
|
882
|
-
);
|
|
883
|
-
});
|
|
884
|
-
sleepSpan?.update({
|
|
885
|
-
attributes: {
|
|
886
|
-
durationMs: duration
|
|
887
|
-
}
|
|
888
|
-
});
|
|
889
|
-
}
|
|
890
|
-
try {
|
|
891
|
-
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
892
|
-
sleepSpan?.end();
|
|
893
|
-
} catch (e) {
|
|
894
|
-
sleepSpan?.error({ error: e });
|
|
895
|
-
throw e;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
async executeSleepUntil({
|
|
899
|
-
workflowId,
|
|
900
|
-
runId,
|
|
901
|
-
entry,
|
|
902
|
-
prevOutput,
|
|
903
|
-
stepResults,
|
|
904
|
-
emitter,
|
|
905
|
-
abortController,
|
|
906
|
-
runtimeContext,
|
|
907
|
-
executionContext,
|
|
908
|
-
writableStream,
|
|
909
|
-
tracingContext
|
|
910
|
-
}) {
|
|
911
|
-
let { date, fn } = entry;
|
|
912
|
-
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
913
|
-
type: aiTracing.AISpanType.WORKFLOW_SLEEP,
|
|
914
|
-
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
915
|
-
attributes: {
|
|
916
|
-
untilDate: date,
|
|
917
|
-
durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
|
|
918
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
919
|
-
},
|
|
920
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
921
|
-
});
|
|
922
|
-
if (fn) {
|
|
923
|
-
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
924
|
-
const stepCallId = crypto.randomUUID();
|
|
925
|
-
return await fn(
|
|
926
|
-
workflows.createDeprecationProxy(
|
|
927
|
-
{
|
|
928
|
-
runId,
|
|
929
|
-
workflowId,
|
|
930
|
-
mastra: this.mastra,
|
|
931
|
-
runtimeContext,
|
|
932
|
-
inputData: prevOutput,
|
|
933
|
-
state: executionContext.state,
|
|
934
|
-
setState: (state) => {
|
|
935
|
-
executionContext.state = state;
|
|
936
|
-
},
|
|
937
|
-
runCount: -1,
|
|
938
|
-
retryCount: -1,
|
|
939
|
-
tracingContext: {
|
|
940
|
-
currentSpan: sleepUntilSpan
|
|
941
|
-
},
|
|
942
|
-
getInitData: () => stepResults?.input,
|
|
943
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
944
|
-
// TODO: this function shouldn't have suspend probably?
|
|
945
|
-
suspend: async (_suspendPayload) => {
|
|
946
|
-
},
|
|
947
|
-
bail: () => {
|
|
948
|
-
},
|
|
949
|
-
abort: () => {
|
|
950
|
-
abortController?.abort();
|
|
951
|
-
},
|
|
952
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
953
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
954
|
-
engine: { step: this.inngestStep },
|
|
955
|
-
abortSignal: abortController?.signal,
|
|
956
|
-
writer: new tools.ToolStream(
|
|
957
|
-
{
|
|
958
|
-
prefix: "workflow-step",
|
|
959
|
-
callId: stepCallId,
|
|
960
|
-
name: "sleep",
|
|
961
|
-
runId
|
|
962
|
-
},
|
|
963
|
-
writableStream
|
|
964
|
-
)
|
|
965
|
-
},
|
|
966
|
-
{
|
|
967
|
-
paramName: "runCount",
|
|
968
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
969
|
-
logger: this.logger
|
|
970
|
-
}
|
|
971
|
-
)
|
|
972
|
-
);
|
|
973
|
-
});
|
|
974
|
-
if (date && !(date instanceof Date)) {
|
|
975
|
-
date = new Date(date);
|
|
976
|
-
}
|
|
977
|
-
const time = !date ? 0 : date.getTime() - Date.now();
|
|
978
|
-
sleepUntilSpan?.update({
|
|
979
|
-
attributes: {
|
|
980
|
-
durationMs: Math.max(0, time)
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
}
|
|
984
|
-
if (!(date instanceof Date)) {
|
|
985
|
-
sleepUntilSpan?.end();
|
|
986
|
-
return;
|
|
987
|
-
}
|
|
988
|
-
try {
|
|
989
|
-
await this.inngestStep.sleepUntil(entry.id, date);
|
|
990
|
-
sleepUntilSpan?.end();
|
|
991
|
-
} catch (e) {
|
|
992
|
-
sleepUntilSpan?.error({ error: e });
|
|
993
|
-
throw e;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
async executeWaitForEvent({ event, timeout }) {
|
|
997
|
-
const eventData = await this.inngestStep.waitForEvent(`user-event-${event}`, {
|
|
998
|
-
event: `user-event-${event}`,
|
|
999
|
-
timeout: timeout ?? 5e3
|
|
1000
|
-
});
|
|
1001
|
-
if (eventData === null) {
|
|
1002
|
-
throw "Timeout waiting for event";
|
|
1003
|
-
}
|
|
1004
|
-
return eventData?.data;
|
|
1005
|
-
}
|
|
1006
|
-
async executeStep({
|
|
1007
|
-
step,
|
|
1008
|
-
stepResults,
|
|
1009
|
-
executionContext,
|
|
1010
|
-
resume,
|
|
1011
|
-
prevOutput,
|
|
1012
|
-
emitter,
|
|
1013
|
-
abortController,
|
|
1014
|
-
runtimeContext,
|
|
1015
|
-
tracingContext,
|
|
1016
|
-
writableStream,
|
|
1017
|
-
disableScorers
|
|
1018
|
-
}) {
|
|
1019
|
-
const stepAISpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1020
|
-
name: `workflow step: '${step.id}'`,
|
|
1021
|
-
type: aiTracing.AISpanType.WORKFLOW_STEP,
|
|
1022
|
-
input: prevOutput,
|
|
1023
|
-
attributes: {
|
|
1024
|
-
stepId: step.id
|
|
1025
|
-
},
|
|
1026
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1027
|
-
});
|
|
1028
|
-
const { inputData, validationError } = await workflows.validateStepInput({
|
|
1029
|
-
prevOutput,
|
|
1030
|
-
step,
|
|
1031
|
-
validateInputs: this.options?.validateInputs ?? false
|
|
1032
|
-
});
|
|
1033
|
-
const startedAt = await this.inngestStep.run(
|
|
1034
|
-
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
1035
|
-
async () => {
|
|
1036
|
-
const startedAt2 = Date.now();
|
|
1037
|
-
await emitter.emit("watch", {
|
|
1038
|
-
type: "watch",
|
|
1039
|
-
payload: {
|
|
1040
|
-
currentStep: {
|
|
1041
|
-
id: step.id,
|
|
1042
|
-
status: "running"
|
|
1043
|
-
},
|
|
1044
|
-
workflowState: {
|
|
1045
|
-
status: "running",
|
|
1046
|
-
steps: {
|
|
1047
|
-
...stepResults,
|
|
1048
|
-
[step.id]: {
|
|
1049
|
-
status: "running"
|
|
1050
|
-
}
|
|
1051
|
-
},
|
|
1052
|
-
result: null,
|
|
1053
|
-
error: null
|
|
1054
|
-
}
|
|
1055
|
-
},
|
|
1056
|
-
eventTimestamp: Date.now()
|
|
1057
|
-
});
|
|
1058
|
-
await emitter.emit("watch-v2", {
|
|
1059
|
-
type: "workflow-step-start",
|
|
1060
|
-
payload: {
|
|
1061
|
-
id: step.id,
|
|
1062
|
-
status: "running",
|
|
1063
|
-
payload: inputData,
|
|
1064
|
-
startedAt: startedAt2
|
|
1065
|
-
}
|
|
1066
|
-
});
|
|
1067
|
-
return startedAt2;
|
|
1068
|
-
}
|
|
1069
|
-
);
|
|
1070
|
-
if (step instanceof InngestWorkflow) {
|
|
1071
|
-
const isResume = !!resume?.steps?.length;
|
|
1072
|
-
let result;
|
|
1073
|
-
let runId;
|
|
1074
|
-
try {
|
|
1075
|
-
if (isResume) {
|
|
1076
|
-
runId = stepResults[resume?.steps?.[0]]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
1077
|
-
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1078
|
-
workflowName: step.id,
|
|
1079
|
-
runId
|
|
1080
|
-
});
|
|
1081
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1082
|
-
function: step.getFunction(),
|
|
1083
|
-
data: {
|
|
1084
|
-
inputData,
|
|
1085
|
-
initialState: executionContext.state ?? snapshot?.value ?? {},
|
|
1086
|
-
runId,
|
|
1087
|
-
resume: {
|
|
1088
|
-
runId,
|
|
1089
|
-
steps: resume.steps.slice(1),
|
|
1090
|
-
stepResults: snapshot?.context,
|
|
1091
|
-
resumePayload: resume.resumePayload,
|
|
1092
|
-
// @ts-ignore
|
|
1093
|
-
resumePath: snapshot?.suspendedPaths?.[resume.steps?.[1]]
|
|
1094
|
-
},
|
|
1095
|
-
outputOptions: { includeState: true }
|
|
1096
|
-
}
|
|
1097
|
-
});
|
|
1098
|
-
result = invokeResp.result;
|
|
1099
|
-
runId = invokeResp.runId;
|
|
1100
|
-
executionContext.state = invokeResp.result.state;
|
|
1101
|
-
} else {
|
|
1102
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1103
|
-
function: step.getFunction(),
|
|
1104
|
-
data: {
|
|
1105
|
-
inputData,
|
|
1106
|
-
initialState: executionContext.state ?? {},
|
|
1107
|
-
outputOptions: { includeState: true }
|
|
1108
|
-
}
|
|
1109
|
-
});
|
|
1110
|
-
result = invokeResp.result;
|
|
1111
|
-
runId = invokeResp.runId;
|
|
1112
|
-
executionContext.state = invokeResp.result.state;
|
|
1113
|
-
}
|
|
1114
|
-
} catch (e) {
|
|
1115
|
-
const errorCause = e?.cause;
|
|
1116
|
-
if (errorCause && typeof errorCause === "object") {
|
|
1117
|
-
result = errorCause;
|
|
1118
|
-
runId = errorCause.runId || crypto.randomUUID();
|
|
1119
|
-
} else {
|
|
1120
|
-
runId = crypto.randomUUID();
|
|
1121
|
-
result = {
|
|
1122
|
-
status: "failed",
|
|
1123
|
-
error: e instanceof Error ? e : new Error(String(e)),
|
|
1124
|
-
steps: {},
|
|
1125
|
-
input: inputData
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
const res = await this.inngestStep.run(
|
|
1130
|
-
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
1131
|
-
async () => {
|
|
1132
|
-
if (result.status === "failed") {
|
|
1133
|
-
await emitter.emit("watch", {
|
|
1134
|
-
type: "watch",
|
|
1135
|
-
payload: {
|
|
1136
|
-
currentStep: {
|
|
1137
|
-
id: step.id,
|
|
1138
|
-
status: "failed",
|
|
1139
|
-
error: result?.error
|
|
1140
|
-
},
|
|
1141
|
-
workflowState: {
|
|
1142
|
-
status: "running",
|
|
1143
|
-
steps: stepResults,
|
|
1144
|
-
result: null,
|
|
1145
|
-
error: null
|
|
1146
|
-
}
|
|
1147
|
-
},
|
|
1148
|
-
eventTimestamp: Date.now()
|
|
1149
|
-
});
|
|
1150
|
-
await emitter.emit("watch-v2", {
|
|
1151
|
-
type: "workflow-step-result",
|
|
1152
|
-
payload: {
|
|
1153
|
-
id: step.id,
|
|
1154
|
-
status: "failed",
|
|
1155
|
-
error: result?.error,
|
|
1156
|
-
payload: prevOutput
|
|
1157
|
-
}
|
|
1158
|
-
});
|
|
1159
|
-
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
1160
|
-
} else if (result.status === "suspended") {
|
|
1161
|
-
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
1162
|
-
const stepRes2 = stepResult;
|
|
1163
|
-
return stepRes2?.status === "suspended";
|
|
1164
|
-
});
|
|
1165
|
-
for (const [stepName, stepResult] of suspendedSteps) {
|
|
1166
|
-
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
1167
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1168
|
-
await emitter.emit("watch", {
|
|
1169
|
-
type: "watch",
|
|
1170
|
-
payload: {
|
|
1171
|
-
currentStep: {
|
|
1172
|
-
id: step.id,
|
|
1173
|
-
status: "suspended",
|
|
1174
|
-
payload: stepResult.payload,
|
|
1175
|
-
suspendPayload: {
|
|
1176
|
-
...stepResult?.suspendPayload,
|
|
1177
|
-
__workflow_meta: { runId, path: suspendPath }
|
|
1178
|
-
}
|
|
1179
|
-
},
|
|
1180
|
-
workflowState: {
|
|
1181
|
-
status: "running",
|
|
1182
|
-
steps: stepResults,
|
|
1183
|
-
result: null,
|
|
1184
|
-
error: null
|
|
1185
|
-
}
|
|
1186
|
-
},
|
|
1187
|
-
eventTimestamp: Date.now()
|
|
1188
|
-
});
|
|
1189
|
-
await emitter.emit("watch-v2", {
|
|
1190
|
-
type: "workflow-step-suspended",
|
|
1191
|
-
payload: {
|
|
1192
|
-
id: step.id,
|
|
1193
|
-
status: "suspended"
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
return {
|
|
1197
|
-
executionContext,
|
|
1198
|
-
result: {
|
|
1199
|
-
status: "suspended",
|
|
1200
|
-
payload: stepResult.payload,
|
|
1201
|
-
suspendPayload: {
|
|
1202
|
-
...stepResult?.suspendPayload,
|
|
1203
|
-
__workflow_meta: { runId, path: suspendPath }
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
await emitter.emit("watch", {
|
|
1209
|
-
type: "watch",
|
|
1210
|
-
payload: {
|
|
1211
|
-
currentStep: {
|
|
1212
|
-
id: step.id,
|
|
1213
|
-
status: "suspended",
|
|
1214
|
-
payload: {}
|
|
1215
|
-
},
|
|
1216
|
-
workflowState: {
|
|
1217
|
-
status: "running",
|
|
1218
|
-
steps: stepResults,
|
|
1219
|
-
result: null,
|
|
1220
|
-
error: null
|
|
1221
|
-
}
|
|
1222
|
-
},
|
|
1223
|
-
eventTimestamp: Date.now()
|
|
1224
|
-
});
|
|
1225
|
-
return {
|
|
1226
|
-
executionContext,
|
|
1227
|
-
result: {
|
|
1228
|
-
status: "suspended",
|
|
1229
|
-
payload: {}
|
|
1230
|
-
}
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
await emitter.emit("watch", {
|
|
1234
|
-
type: "watch",
|
|
1235
|
-
payload: {
|
|
1236
|
-
currentStep: {
|
|
1237
|
-
id: step.id,
|
|
1238
|
-
status: "success",
|
|
1239
|
-
output: result?.result
|
|
1240
|
-
},
|
|
1241
|
-
workflowState: {
|
|
1242
|
-
status: "running",
|
|
1243
|
-
steps: stepResults,
|
|
1244
|
-
result: null,
|
|
1245
|
-
error: null
|
|
1246
|
-
}
|
|
1247
|
-
},
|
|
1248
|
-
eventTimestamp: Date.now()
|
|
1249
|
-
});
|
|
1250
|
-
await emitter.emit("watch-v2", {
|
|
1251
|
-
type: "workflow-step-result",
|
|
1252
|
-
payload: {
|
|
1253
|
-
id: step.id,
|
|
1254
|
-
status: "success",
|
|
1255
|
-
output: result?.result
|
|
1256
|
-
}
|
|
1257
|
-
});
|
|
1258
|
-
await emitter.emit("watch-v2", {
|
|
1259
|
-
type: "workflow-step-finish",
|
|
1260
|
-
payload: {
|
|
1261
|
-
id: step.id,
|
|
1262
|
-
metadata: {}
|
|
1263
|
-
}
|
|
1264
|
-
});
|
|
1265
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
1266
|
-
}
|
|
1267
|
-
);
|
|
1268
|
-
Object.assign(executionContext, res.executionContext);
|
|
1269
|
-
return {
|
|
1270
|
-
...res.result,
|
|
1271
|
-
startedAt,
|
|
1272
|
-
endedAt: Date.now(),
|
|
1273
|
-
payload: inputData,
|
|
1274
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1275
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1276
|
-
};
|
|
1277
|
-
}
|
|
1278
|
-
const stepCallId = crypto.randomUUID();
|
|
1279
|
-
let stepRes;
|
|
1280
|
-
try {
|
|
1281
|
-
stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
1282
|
-
let execResults;
|
|
1283
|
-
let suspended;
|
|
1284
|
-
let bailed;
|
|
1285
|
-
try {
|
|
1286
|
-
if (validationError) {
|
|
1287
|
-
throw validationError;
|
|
1288
|
-
}
|
|
1289
|
-
const result = await step.execute({
|
|
1290
|
-
runId: executionContext.runId,
|
|
1291
|
-
mastra: this.mastra,
|
|
1292
|
-
runtimeContext,
|
|
1293
|
-
writer: new tools.ToolStream(
|
|
1294
|
-
{
|
|
1295
|
-
prefix: "workflow-step",
|
|
1296
|
-
callId: stepCallId,
|
|
1297
|
-
name: step.id,
|
|
1298
|
-
runId: executionContext.runId
|
|
1299
|
-
},
|
|
1300
|
-
writableStream
|
|
1301
|
-
),
|
|
1302
|
-
state: executionContext?.state ?? {},
|
|
1303
|
-
setState: (state) => {
|
|
1304
|
-
executionContext.state = state;
|
|
1305
|
-
},
|
|
1306
|
-
inputData,
|
|
1307
|
-
resumeData: resume?.steps[0] === step.id ? resume?.resumePayload : void 0,
|
|
1308
|
-
tracingContext: {
|
|
1309
|
-
currentSpan: stepAISpan
|
|
1310
|
-
},
|
|
1311
|
-
getInitData: () => stepResults?.input,
|
|
1312
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1313
|
-
suspend: async (suspendPayload, suspendOptions) => {
|
|
1314
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1315
|
-
if (suspendOptions?.resumeLabel) {
|
|
1316
|
-
const resumeLabel = Array.isArray(suspendOptions.resumeLabel) ? suspendOptions.resumeLabel : [suspendOptions.resumeLabel];
|
|
1317
|
-
for (const label of resumeLabel) {
|
|
1318
|
-
executionContext.resumeLabels[label] = {
|
|
1319
|
-
stepId: step.id,
|
|
1320
|
-
foreachIndex: executionContext.foreachIndex
|
|
1321
|
-
};
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
suspended = { payload: suspendPayload };
|
|
1325
|
-
},
|
|
1326
|
-
bail: (result2) => {
|
|
1327
|
-
bailed = { payload: result2 };
|
|
1328
|
-
},
|
|
1329
|
-
resume: {
|
|
1330
|
-
steps: resume?.steps?.slice(1) || [],
|
|
1331
|
-
resumePayload: resume?.resumePayload,
|
|
1332
|
-
// @ts-ignore
|
|
1333
|
-
runId: stepResults[step.id]?.suspendPayload?.__workflow_meta?.runId
|
|
1334
|
-
},
|
|
1335
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1336
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1337
|
-
engine: {
|
|
1338
|
-
step: this.inngestStep
|
|
1339
|
-
},
|
|
1340
|
-
abortSignal: abortController.signal
|
|
1341
|
-
});
|
|
1342
|
-
const endedAt = Date.now();
|
|
1343
|
-
execResults = {
|
|
1344
|
-
status: "success",
|
|
1345
|
-
output: result,
|
|
1346
|
-
startedAt,
|
|
1347
|
-
endedAt,
|
|
1348
|
-
payload: inputData,
|
|
1349
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1350
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1351
|
-
};
|
|
1352
|
-
} catch (e) {
|
|
1353
|
-
const stepFailure = {
|
|
1354
|
-
status: "failed",
|
|
1355
|
-
payload: inputData,
|
|
1356
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1357
|
-
endedAt: Date.now(),
|
|
1358
|
-
startedAt,
|
|
1359
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1360
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1361
|
-
};
|
|
1362
|
-
execResults = stepFailure;
|
|
1363
|
-
const fallbackErrorMessage = `Step ${step.id} failed`;
|
|
1364
|
-
stepAISpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
|
|
1365
|
-
throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
|
|
1366
|
-
cause: execResults
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
|
-
if (suspended) {
|
|
1370
|
-
execResults = {
|
|
1371
|
-
status: "suspended",
|
|
1372
|
-
suspendPayload: suspended.payload,
|
|
1373
|
-
payload: inputData,
|
|
1374
|
-
suspendedAt: Date.now(),
|
|
1375
|
-
startedAt,
|
|
1376
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1377
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1378
|
-
};
|
|
1379
|
-
} else if (bailed) {
|
|
1380
|
-
execResults = {
|
|
1381
|
-
status: "bailed",
|
|
1382
|
-
output: bailed.payload,
|
|
1383
|
-
payload: inputData,
|
|
1384
|
-
endedAt: Date.now(),
|
|
1385
|
-
startedAt
|
|
1386
|
-
};
|
|
1387
|
-
}
|
|
1388
|
-
await emitter.emit("watch", {
|
|
1389
|
-
type: "watch",
|
|
1390
|
-
payload: {
|
|
1391
|
-
currentStep: {
|
|
1392
|
-
id: step.id,
|
|
1393
|
-
...execResults
|
|
1394
|
-
},
|
|
1395
|
-
workflowState: {
|
|
1396
|
-
status: "running",
|
|
1397
|
-
steps: { ...stepResults, [step.id]: execResults },
|
|
1398
|
-
result: null,
|
|
1399
|
-
error: null
|
|
1400
|
-
}
|
|
1401
|
-
},
|
|
1402
|
-
eventTimestamp: Date.now()
|
|
1403
|
-
});
|
|
1404
|
-
if (execResults.status === "suspended") {
|
|
1405
|
-
await emitter.emit("watch-v2", {
|
|
1406
|
-
type: "workflow-step-suspended",
|
|
1407
|
-
payload: {
|
|
1408
|
-
id: step.id,
|
|
1409
|
-
...execResults
|
|
1410
|
-
}
|
|
1411
|
-
});
|
|
1412
|
-
} else {
|
|
1413
|
-
await emitter.emit("watch-v2", {
|
|
1414
|
-
type: "workflow-step-result",
|
|
1415
|
-
payload: {
|
|
1416
|
-
id: step.id,
|
|
1417
|
-
...execResults
|
|
1418
|
-
}
|
|
1419
|
-
});
|
|
1420
|
-
await emitter.emit("watch-v2", {
|
|
1421
|
-
type: "workflow-step-finish",
|
|
1422
|
-
payload: {
|
|
1423
|
-
id: step.id,
|
|
1424
|
-
metadata: {}
|
|
1425
|
-
}
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
stepAISpan?.end({ output: execResults });
|
|
1429
|
-
return { result: execResults, executionContext, stepResults };
|
|
1430
|
-
});
|
|
1431
|
-
} catch (e) {
|
|
1432
|
-
const stepFailure = e instanceof Error ? e?.cause : {
|
|
1433
|
-
status: "failed",
|
|
1434
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1435
|
-
payload: inputData,
|
|
1436
|
-
startedAt,
|
|
1437
|
-
endedAt: Date.now()
|
|
1438
|
-
};
|
|
1439
|
-
stepRes = {
|
|
1440
|
-
result: stepFailure,
|
|
1441
|
-
executionContext,
|
|
1442
|
-
stepResults: {
|
|
1443
|
-
...stepResults,
|
|
1444
|
-
[step.id]: stepFailure
|
|
1445
|
-
}
|
|
1446
|
-
};
|
|
1447
|
-
}
|
|
1448
|
-
if (disableScorers !== false && stepRes.result.status === "success") {
|
|
1449
|
-
await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
|
|
1450
|
-
if (step.scorers) {
|
|
1451
|
-
await this.runScorers({
|
|
1452
|
-
scorers: step.scorers,
|
|
1453
|
-
runId: executionContext.runId,
|
|
1454
|
-
input: inputData,
|
|
1455
|
-
output: stepRes.result,
|
|
1456
|
-
workflowId: executionContext.workflowId,
|
|
1457
|
-
stepId: step.id,
|
|
1458
|
-
runtimeContext,
|
|
1459
|
-
disableScorers,
|
|
1460
|
-
tracingContext: { currentSpan: stepAISpan }
|
|
1461
|
-
});
|
|
1462
|
-
}
|
|
1463
|
-
});
|
|
1464
|
-
}
|
|
1465
|
-
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
1466
|
-
Object.assign(stepResults, stepRes.stepResults);
|
|
1467
|
-
executionContext.state = stepRes.executionContext.state;
|
|
1468
|
-
return stepRes.result;
|
|
1469
|
-
}
|
|
1470
|
-
async persistStepUpdate({
|
|
1471
|
-
workflowId,
|
|
1472
|
-
runId,
|
|
1473
|
-
stepResults,
|
|
1474
|
-
resourceId,
|
|
1475
|
-
executionContext,
|
|
1476
|
-
serializedStepGraph,
|
|
1477
|
-
workflowStatus,
|
|
1478
|
-
result,
|
|
1479
|
-
error
|
|
1480
|
-
}) {
|
|
1481
|
-
await this.inngestStep.run(
|
|
1482
|
-
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
1483
|
-
async () => {
|
|
1484
|
-
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
|
|
1485
|
-
if (!shouldPersistSnapshot) {
|
|
1486
|
-
return;
|
|
1487
|
-
}
|
|
1488
|
-
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
1489
|
-
workflowName: workflowId,
|
|
1490
|
-
runId,
|
|
1491
|
-
resourceId,
|
|
1492
|
-
snapshot: {
|
|
1493
|
-
runId,
|
|
1494
|
-
value: executionContext.state,
|
|
1495
|
-
context: stepResults,
|
|
1496
|
-
activePaths: [],
|
|
1497
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1498
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1499
|
-
waitingPaths: {},
|
|
1500
|
-
serializedStepGraph,
|
|
1501
|
-
status: workflowStatus,
|
|
1502
|
-
result,
|
|
1503
|
-
error,
|
|
1504
|
-
// @ts-ignore
|
|
1505
|
-
timestamp: Date.now()
|
|
1506
|
-
}
|
|
1507
|
-
});
|
|
1508
|
-
}
|
|
1509
|
-
);
|
|
1510
|
-
}
|
|
1511
|
-
async executeConditional({
|
|
1512
|
-
workflowId,
|
|
1513
|
-
runId,
|
|
1514
|
-
entry,
|
|
1515
|
-
prevOutput,
|
|
1516
|
-
stepResults,
|
|
1517
|
-
resume,
|
|
1518
|
-
executionContext,
|
|
1519
|
-
emitter,
|
|
1520
|
-
abortController,
|
|
1521
|
-
runtimeContext,
|
|
1522
|
-
writableStream,
|
|
1523
|
-
disableScorers,
|
|
1524
|
-
tracingContext
|
|
1525
|
-
}) {
|
|
1526
|
-
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1527
|
-
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL,
|
|
1528
|
-
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1529
|
-
input: prevOutput,
|
|
1530
|
-
attributes: {
|
|
1531
|
-
conditionCount: entry.conditions.length
|
|
1532
|
-
},
|
|
1533
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1534
|
-
});
|
|
1535
|
-
let execResults;
|
|
1536
|
-
const truthyIndexes = (await Promise.all(
|
|
1537
|
-
entry.conditions.map(
|
|
1538
|
-
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1539
|
-
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1540
|
-
type: aiTracing.AISpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1541
|
-
name: `condition: '${index}'`,
|
|
1542
|
-
input: prevOutput,
|
|
1543
|
-
attributes: {
|
|
1544
|
-
conditionIndex: index
|
|
1545
|
-
},
|
|
1546
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1547
|
-
});
|
|
1548
|
-
try {
|
|
1549
|
-
const result = await cond(
|
|
1550
|
-
workflows.createDeprecationProxy(
|
|
1551
|
-
{
|
|
1552
|
-
runId,
|
|
1553
|
-
workflowId,
|
|
1554
|
-
mastra: this.mastra,
|
|
1555
|
-
runtimeContext,
|
|
1556
|
-
runCount: -1,
|
|
1557
|
-
retryCount: -1,
|
|
1558
|
-
inputData: prevOutput,
|
|
1559
|
-
state: executionContext.state,
|
|
1560
|
-
setState: (state) => {
|
|
1561
|
-
executionContext.state = state;
|
|
1562
|
-
},
|
|
1563
|
-
tracingContext: {
|
|
1564
|
-
currentSpan: evalSpan
|
|
1565
|
-
},
|
|
1566
|
-
getInitData: () => stepResults?.input,
|
|
1567
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1568
|
-
// TODO: this function shouldn't have suspend probably?
|
|
1569
|
-
suspend: async (_suspendPayload) => {
|
|
1570
|
-
},
|
|
1571
|
-
bail: () => {
|
|
1572
|
-
},
|
|
1573
|
-
abort: () => {
|
|
1574
|
-
abortController.abort();
|
|
1575
|
-
},
|
|
1576
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1577
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1578
|
-
engine: {
|
|
1579
|
-
step: this.inngestStep
|
|
1580
|
-
},
|
|
1581
|
-
abortSignal: abortController.signal,
|
|
1582
|
-
writer: new tools.ToolStream(
|
|
1583
|
-
{
|
|
1584
|
-
prefix: "workflow-step",
|
|
1585
|
-
callId: crypto.randomUUID(),
|
|
1586
|
-
name: "conditional",
|
|
1587
|
-
runId
|
|
1588
|
-
},
|
|
1589
|
-
writableStream
|
|
1590
|
-
)
|
|
1591
|
-
},
|
|
1592
|
-
{
|
|
1593
|
-
paramName: "runCount",
|
|
1594
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1595
|
-
logger: this.logger
|
|
1596
|
-
}
|
|
1597
|
-
)
|
|
1598
|
-
);
|
|
1599
|
-
evalSpan?.end({
|
|
1600
|
-
output: result,
|
|
1601
|
-
attributes: {
|
|
1602
|
-
result: !!result
|
|
1603
|
-
}
|
|
1604
|
-
});
|
|
1605
|
-
return result ? index : null;
|
|
1606
|
-
} catch (e) {
|
|
1607
|
-
evalSpan?.error({
|
|
1608
|
-
error: e instanceof Error ? e : new Error(String(e)),
|
|
1609
|
-
attributes: {
|
|
1610
|
-
result: false
|
|
1611
|
-
}
|
|
1612
|
-
});
|
|
1613
|
-
return null;
|
|
1614
|
-
}
|
|
1615
|
-
})
|
|
1616
|
-
)
|
|
1617
|
-
)).filter((index) => index !== null);
|
|
1618
|
-
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
1619
|
-
conditionalSpan?.update({
|
|
1620
|
-
attributes: {
|
|
1621
|
-
truthyIndexes,
|
|
1622
|
-
selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1625
|
-
const results = await Promise.all(
|
|
1626
|
-
stepsToRun.map(async (step, index) => {
|
|
1627
|
-
const currStepResult = stepResults[step.step.id];
|
|
1628
|
-
if (currStepResult && currStepResult.status === "success") {
|
|
1629
|
-
return currStepResult;
|
|
1630
|
-
}
|
|
1631
|
-
const result = await this.executeStep({
|
|
1632
|
-
step: step.step,
|
|
1633
|
-
prevOutput,
|
|
1634
|
-
stepResults,
|
|
1635
|
-
resume,
|
|
1636
|
-
executionContext: {
|
|
1637
|
-
workflowId,
|
|
1638
|
-
runId,
|
|
1639
|
-
executionPath: [...executionContext.executionPath, index],
|
|
1640
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1641
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1642
|
-
retryConfig: executionContext.retryConfig,
|
|
1643
|
-
state: executionContext.state
|
|
1644
|
-
},
|
|
1645
|
-
emitter,
|
|
1646
|
-
abortController,
|
|
1647
|
-
runtimeContext,
|
|
1648
|
-
writableStream,
|
|
1649
|
-
disableScorers,
|
|
1650
|
-
tracingContext: {
|
|
1651
|
-
currentSpan: conditionalSpan
|
|
1652
|
-
}
|
|
1653
|
-
});
|
|
1654
|
-
stepResults[step.step.id] = result;
|
|
1655
|
-
return result;
|
|
1656
|
-
})
|
|
1657
|
-
);
|
|
1658
|
-
const hasFailed = results.find((result) => result.status === "failed");
|
|
1659
|
-
const hasSuspended = results.find((result) => result.status === "suspended");
|
|
1660
|
-
if (hasFailed) {
|
|
1661
|
-
execResults = { status: "failed", error: hasFailed.error };
|
|
1662
|
-
} else if (hasSuspended) {
|
|
1663
|
-
execResults = { status: "suspended", suspendPayload: hasSuspended.suspendPayload };
|
|
1664
|
-
} else {
|
|
1665
|
-
execResults = {
|
|
1666
|
-
status: "success",
|
|
1667
|
-
output: results.reduce((acc, result, index) => {
|
|
1668
|
-
if (result.status === "success") {
|
|
1669
|
-
acc[stepsToRun[index].step.id] = result.output;
|
|
1670
|
-
}
|
|
1671
|
-
return acc;
|
|
1672
|
-
}, {})
|
|
1673
|
-
};
|
|
1674
|
-
}
|
|
1675
|
-
if (execResults.status === "failed") {
|
|
1676
|
-
conditionalSpan?.error({
|
|
1677
|
-
error: new Error(execResults.error)
|
|
1678
|
-
});
|
|
1679
|
-
} else {
|
|
1680
|
-
conditionalSpan?.end({
|
|
1681
|
-
output: execResults.output || execResults
|
|
1682
|
-
});
|
|
1683
|
-
}
|
|
1684
|
-
return execResults;
|
|
1685
|
-
}
|
|
1686
|
-
};
|
|
1687
1497
|
|
|
1688
1498
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
1499
|
+
exports.InngestPubSub = InngestPubSub;
|
|
1689
1500
|
exports.InngestRun = InngestRun;
|
|
1690
1501
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1502
|
+
exports._compatibilityCheck = _compatibilityCheck;
|
|
1691
1503
|
exports.createStep = createStep;
|
|
1692
1504
|
exports.init = init;
|
|
1693
1505
|
exports.serve = serve;
|