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