@mastra/inngest 0.0.0-feat-improve-processors-20251205191721 → 0.0.0-feat-mcp-embedded-docs-tools-clean-20260102135536
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 +796 -12
- package/dist/execution-engine.d.ts +31 -8
- package/dist/execution-engine.d.ts.map +1 -1
- package/dist/index.cjs +551 -197
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +21 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +547 -194
- 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 +36 -16
- package/dist/run.d.ts.map +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow.d.ts +3 -0
- package/dist/workflow.d.ts.map +1 -1
- package/package.json +7 -8
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var agent = require('@mastra/core/agent');
|
|
3
4
|
var tools = require('@mastra/core/tools');
|
|
4
5
|
var workflows = require('@mastra/core/workflows');
|
|
5
6
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
6
7
|
var zod = require('zod');
|
|
7
|
-
var crypto = require('crypto');
|
|
8
|
-
var web = require('stream/web');
|
|
8
|
+
var crypto$1 = require('crypto');
|
|
9
9
|
var di = require('@mastra/core/di');
|
|
10
10
|
var inngest = require('inngest');
|
|
11
|
+
var error = require('@mastra/core/error');
|
|
11
12
|
var realtime = require('@inngest/realtime');
|
|
13
|
+
var events = require('@mastra/core/events');
|
|
14
|
+
var web = require('stream/web');
|
|
12
15
|
var stream = require('@mastra/core/stream');
|
|
13
16
|
var hono = require('inngest/hono');
|
|
14
17
|
|
|
@@ -25,17 +28,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
25
28
|
// Hook Overrides
|
|
26
29
|
// =============================================================================
|
|
27
30
|
/**
|
|
28
|
-
* Format errors
|
|
31
|
+
* Format errors while preserving Error instances and their custom properties.
|
|
32
|
+
* Uses getErrorFromUnknown to ensure all error properties are preserved.
|
|
29
33
|
*/
|
|
30
|
-
formatResultError(error, lastOutput) {
|
|
31
|
-
if (error instanceof Error) {
|
|
32
|
-
return error.stack ?? error.message;
|
|
33
|
-
}
|
|
34
|
+
formatResultError(error$1, lastOutput) {
|
|
34
35
|
const outputError = lastOutput?.error;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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();
|
|
39
43
|
}
|
|
40
44
|
/**
|
|
41
45
|
* Detect InngestWorkflow instances for special nested workflow handling
|
|
@@ -57,32 +61,46 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
57
61
|
* After retries exhausted, error propagates here and we return a failed result.
|
|
58
62
|
*/
|
|
59
63
|
async executeStepWithRetry(stepId, runStep, params) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
} catch (e) {
|
|
64
|
-
const cause = e?.cause;
|
|
65
|
-
if (cause?.status === "failed") {
|
|
66
|
-
params.stepSpan?.error({
|
|
67
|
-
error: e,
|
|
68
|
-
attributes: { status: "failed" }
|
|
69
|
-
});
|
|
70
|
-
return { ok: false, error: cause };
|
|
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));
|
|
71
67
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
+
};
|
|
83
100
|
}
|
|
84
|
-
}
|
|
101
|
+
}
|
|
85
102
|
}
|
|
103
|
+
return { ok: false, error: { status: "failed", error: new Error("Unknown error"), endedAt: Date.now() } };
|
|
86
104
|
}
|
|
87
105
|
/**
|
|
88
106
|
* Use Inngest's sleep primitive for durability
|
|
@@ -101,21 +119,11 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
101
119
|
* If retryConfig is provided, throws RetryAfterError INSIDE step.run() to trigger
|
|
102
120
|
* Inngest's step-level retry mechanism (not function-level retry).
|
|
103
121
|
*/
|
|
104
|
-
async wrapDurableOperation(operationId, operationFn
|
|
122
|
+
async wrapDurableOperation(operationId, operationFn) {
|
|
105
123
|
return this.inngestStep.run(operationId, async () => {
|
|
106
124
|
try {
|
|
107
125
|
return await operationFn();
|
|
108
126
|
} catch (e) {
|
|
109
|
-
if (retryConfig) {
|
|
110
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
111
|
-
throw new inngest.RetryAfterError(errorMessage, retryConfig.delay, {
|
|
112
|
-
cause: {
|
|
113
|
-
status: "failed",
|
|
114
|
-
error: `Error: ${errorMessage}`,
|
|
115
|
-
endedAt: Date.now()
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
127
|
throw e;
|
|
120
128
|
}
|
|
121
129
|
});
|
|
@@ -126,6 +134,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
126
134
|
getEngineContext() {
|
|
127
135
|
return { step: this.inngestStep };
|
|
128
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
|
+
}
|
|
129
149
|
/**
|
|
130
150
|
* Execute nested InngestWorkflow using inngestStep.invoke() for durability.
|
|
131
151
|
* This MUST be called directly (not inside step.run()) due to Inngest constraints.
|
|
@@ -134,15 +154,27 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
134
154
|
if (!(params.step instanceof InngestWorkflow)) {
|
|
135
155
|
return null;
|
|
136
156
|
}
|
|
137
|
-
const {
|
|
157
|
+
const {
|
|
158
|
+
step,
|
|
159
|
+
stepResults,
|
|
160
|
+
executionContext,
|
|
161
|
+
resume,
|
|
162
|
+
timeTravel,
|
|
163
|
+
prevOutput,
|
|
164
|
+
inputData,
|
|
165
|
+
pubsub,
|
|
166
|
+
startedAt,
|
|
167
|
+
perStep
|
|
168
|
+
} = params;
|
|
138
169
|
const isResume = !!resume?.steps?.length;
|
|
139
170
|
let result;
|
|
140
171
|
let runId;
|
|
141
172
|
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
142
173
|
try {
|
|
143
174
|
if (isResume) {
|
|
144
|
-
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
145
|
-
const
|
|
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({
|
|
146
178
|
workflowName: step.id,
|
|
147
179
|
runId
|
|
148
180
|
});
|
|
@@ -159,14 +191,16 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
159
191
|
resumePayload: resume.resumePayload,
|
|
160
192
|
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
161
193
|
},
|
|
162
|
-
outputOptions: { includeState: true }
|
|
194
|
+
outputOptions: { includeState: true },
|
|
195
|
+
perStep
|
|
163
196
|
}
|
|
164
197
|
});
|
|
165
198
|
result = invokeResp.result;
|
|
166
199
|
runId = invokeResp.runId;
|
|
167
200
|
executionContext.state = invokeResp.result.state;
|
|
168
201
|
} else if (isTimeTravel) {
|
|
169
|
-
const
|
|
202
|
+
const workflowsStoreForTimeTravel = await this.mastra?.getStorage()?.getStore("workflows");
|
|
203
|
+
const snapshot = await workflowsStoreForTimeTravel?.loadWorkflowSnapshot({
|
|
170
204
|
workflowName: step.id,
|
|
171
205
|
runId: executionContext.runId
|
|
172
206
|
}) ?? { context: {} };
|
|
@@ -185,7 +219,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
185
219
|
timeTravel: timeTravelParams,
|
|
186
220
|
initialState: executionContext.state ?? {},
|
|
187
221
|
runId: executionContext.runId,
|
|
188
|
-
outputOptions: { includeState: true }
|
|
222
|
+
outputOptions: { includeState: true },
|
|
223
|
+
perStep
|
|
189
224
|
}
|
|
190
225
|
});
|
|
191
226
|
result = invokeResp.result;
|
|
@@ -197,7 +232,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
197
232
|
data: {
|
|
198
233
|
inputData,
|
|
199
234
|
initialState: executionContext.state ?? {},
|
|
200
|
-
outputOptions: { includeState: true }
|
|
235
|
+
outputOptions: { includeState: true },
|
|
236
|
+
perStep
|
|
201
237
|
}
|
|
202
238
|
});
|
|
203
239
|
result = invokeResp.result;
|
|
@@ -208,9 +244,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
208
244
|
const errorCause = e?.cause;
|
|
209
245
|
if (errorCause && typeof errorCause === "object") {
|
|
210
246
|
result = errorCause;
|
|
211
|
-
runId = errorCause.runId || crypto.randomUUID();
|
|
247
|
+
runId = errorCause.runId || crypto$1.randomUUID();
|
|
212
248
|
} else {
|
|
213
|
-
runId = crypto.randomUUID();
|
|
249
|
+
runId = crypto$1.randomUUID();
|
|
214
250
|
result = {
|
|
215
251
|
status: "failed",
|
|
216
252
|
error: e instanceof Error ? e : new Error(String(e)),
|
|
@@ -223,16 +259,20 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
223
259
|
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
224
260
|
async () => {
|
|
225
261
|
if (result.status === "failed") {
|
|
226
|
-
await
|
|
227
|
-
type: "
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
+
}
|
|
233
273
|
}
|
|
234
274
|
});
|
|
235
|
-
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
275
|
+
return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
|
|
236
276
|
} else if (result.status === "suspended") {
|
|
237
277
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
238
278
|
const stepRes = stepResult;
|
|
@@ -241,17 +281,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
241
281
|
for (const [stepName, stepResult] of suspendedSteps) {
|
|
242
282
|
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
243
283
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
244
|
-
await
|
|
245
|
-
type: "
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
+
}
|
|
249
293
|
}
|
|
250
294
|
});
|
|
251
295
|
return {
|
|
252
296
|
executionContext,
|
|
253
297
|
result: {
|
|
254
298
|
status: "suspended",
|
|
299
|
+
suspendedAt: Date.now(),
|
|
255
300
|
payload: stepResult.payload,
|
|
256
301
|
suspendPayload: {
|
|
257
302
|
...stepResult?.suspendPayload,
|
|
@@ -264,59 +309,205 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
264
309
|
executionContext,
|
|
265
310
|
result: {
|
|
266
311
|
status: "suspended",
|
|
312
|
+
suspendedAt: Date.now(),
|
|
267
313
|
payload: {}
|
|
268
314
|
}
|
|
269
315
|
};
|
|
270
316
|
} else if (result.status === "tripwire") {
|
|
271
|
-
await
|
|
272
|
-
type: "
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
+
}
|
|
278
328
|
}
|
|
279
329
|
});
|
|
280
330
|
return {
|
|
281
331
|
executionContext,
|
|
282
332
|
result: {
|
|
283
333
|
status: "tripwire",
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
metadata: result?.metadata,
|
|
287
|
-
processorId: result?.processorId
|
|
334
|
+
tripwire: result?.tripwire,
|
|
335
|
+
endedAt: Date.now()
|
|
288
336
|
}
|
|
289
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" } };
|
|
290
362
|
}
|
|
291
|
-
await
|
|
292
|
-
type: "
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
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
|
+
}
|
|
297
373
|
}
|
|
298
374
|
});
|
|
299
|
-
await
|
|
300
|
-
type: "
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
+
}
|
|
304
384
|
}
|
|
305
385
|
});
|
|
306
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
386
|
+
return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
|
|
307
387
|
}
|
|
308
388
|
);
|
|
309
389
|
Object.assign(executionContext, res.executionContext);
|
|
310
390
|
return {
|
|
311
391
|
...res.result,
|
|
312
392
|
startedAt,
|
|
313
|
-
endedAt: Date.now(),
|
|
314
393
|
payload: inputData,
|
|
315
394
|
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
316
395
|
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
317
396
|
};
|
|
318
397
|
}
|
|
319
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
|
+
};
|
|
320
511
|
var InngestRun = class extends workflows.Run {
|
|
321
512
|
inngest;
|
|
322
513
|
serializedStepGraph;
|
|
@@ -328,38 +519,90 @@ var InngestRun = class extends workflows.Run {
|
|
|
328
519
|
this.#mastra = params.mastra;
|
|
329
520
|
}
|
|
330
521
|
async getRuns(eventId) {
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
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
|
+
}
|
|
334
554
|
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return json.data;
|
|
555
|
+
}
|
|
556
|
+
throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
338
557
|
}
|
|
339
|
-
async getRunOutput(eventId) {
|
|
340
|
-
|
|
558
|
+
async getRunOutput(eventId, maxWaitMs = 3e5) {
|
|
559
|
+
const startTime = Date.now();
|
|
341
560
|
const storage = this.#mastra?.getStorage();
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
runs
|
|
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
|
+
}
|
|
345
577
|
if (runs?.[0]?.status === "Failed") {
|
|
346
|
-
const snapshot = await
|
|
578
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
347
579
|
workflowName: this.workflowId,
|
|
348
580
|
runId: this.runId
|
|
349
581
|
});
|
|
582
|
+
if (snapshot?.context) {
|
|
583
|
+
snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
|
|
584
|
+
}
|
|
350
585
|
return {
|
|
351
|
-
output: {
|
|
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
|
+
}
|
|
352
594
|
};
|
|
353
595
|
}
|
|
354
596
|
if (runs?.[0]?.status === "Cancelled") {
|
|
355
|
-
const snapshot = await
|
|
597
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
356
598
|
workflowName: this.workflowId,
|
|
357
599
|
runId: this.runId
|
|
358
600
|
});
|
|
359
601
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
360
602
|
}
|
|
603
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
361
604
|
}
|
|
362
|
-
|
|
605
|
+
throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
363
606
|
}
|
|
364
607
|
async cancel() {
|
|
365
608
|
const storage = this.#mastra?.getStorage();
|
|
@@ -369,12 +612,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
369
612
|
runId: this.runId
|
|
370
613
|
}
|
|
371
614
|
});
|
|
372
|
-
const
|
|
615
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
616
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
373
617
|
workflowName: this.workflowId,
|
|
374
618
|
runId: this.runId
|
|
375
619
|
});
|
|
376
620
|
if (snapshot) {
|
|
377
|
-
await
|
|
621
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
378
622
|
workflowName: this.workflowId,
|
|
379
623
|
runId: this.runId,
|
|
380
624
|
resourceId: this.resourceId,
|
|
@@ -389,15 +633,64 @@ var InngestRun = class extends workflows.Run {
|
|
|
389
633
|
async start(params) {
|
|
390
634
|
return this._start(params);
|
|
391
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
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
const eventId = eventOutput.ids[0];
|
|
678
|
+
if (!eventId) {
|
|
679
|
+
throw new Error("Event ID is not set");
|
|
680
|
+
}
|
|
681
|
+
return { runId: this.runId };
|
|
682
|
+
}
|
|
392
683
|
async _start({
|
|
393
684
|
inputData,
|
|
394
685
|
initialState,
|
|
395
686
|
outputOptions,
|
|
396
687
|
tracingOptions,
|
|
397
688
|
format,
|
|
398
|
-
requestContext
|
|
689
|
+
requestContext,
|
|
690
|
+
perStep
|
|
399
691
|
}) {
|
|
400
|
-
await this.#mastra.getStorage()?.
|
|
692
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
693
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
401
694
|
workflowName: this.workflowId,
|
|
402
695
|
runId: this.runId,
|
|
403
696
|
resourceId: this.resourceId,
|
|
@@ -427,7 +720,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
427
720
|
outputOptions,
|
|
428
721
|
tracingOptions,
|
|
429
722
|
format,
|
|
430
|
-
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
723
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
|
|
724
|
+
perStep
|
|
431
725
|
}
|
|
432
726
|
});
|
|
433
727
|
const eventId = eventOutput.ids[0];
|
|
@@ -436,9 +730,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
436
730
|
}
|
|
437
731
|
const runOutput = await this.getRunOutput(eventId);
|
|
438
732
|
const result = runOutput?.output?.result;
|
|
439
|
-
|
|
440
|
-
result.error = new Error(result.error);
|
|
441
|
-
}
|
|
733
|
+
this.hydrateFailedResult(result);
|
|
442
734
|
if (result.status !== "suspended") {
|
|
443
735
|
this.cleanup?.();
|
|
444
736
|
}
|
|
@@ -465,7 +757,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
465
757
|
(step) => typeof step === "string" ? step : step?.id
|
|
466
758
|
);
|
|
467
759
|
}
|
|
468
|
-
const
|
|
760
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
761
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
469
762
|
workflowName: this.workflowId,
|
|
470
763
|
runId: this.runId
|
|
471
764
|
});
|
|
@@ -488,7 +781,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
488
781
|
resumePayload: resumeDataToUse,
|
|
489
782
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
490
783
|
},
|
|
491
|
-
requestContext: mergedRequestContext
|
|
784
|
+
requestContext: mergedRequestContext,
|
|
785
|
+
perStep: params.perStep
|
|
492
786
|
}
|
|
493
787
|
});
|
|
494
788
|
const eventId = eventOutput.ids[0];
|
|
@@ -497,9 +791,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
497
791
|
}
|
|
498
792
|
const runOutput = await this.getRunOutput(eventId);
|
|
499
793
|
const result = runOutput?.output?.result;
|
|
500
|
-
|
|
501
|
-
result.error = new Error(result.error);
|
|
502
|
-
}
|
|
794
|
+
this.hydrateFailedResult(result);
|
|
503
795
|
return result;
|
|
504
796
|
}
|
|
505
797
|
async timeTravel(params) {
|
|
@@ -529,12 +821,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
529
821
|
throw new Error("No steps provided to timeTravel");
|
|
530
822
|
}
|
|
531
823
|
const storage = this.#mastra?.getStorage();
|
|
532
|
-
const
|
|
824
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
825
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
533
826
|
workflowName: this.workflowId,
|
|
534
827
|
runId: this.runId
|
|
535
828
|
});
|
|
536
829
|
if (!snapshot) {
|
|
537
|
-
await
|
|
830
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
538
831
|
workflowName: this.workflowId,
|
|
539
832
|
runId: this.runId,
|
|
540
833
|
resourceId: this.resourceId,
|
|
@@ -568,7 +861,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
568
861
|
nestedStepsContext: params.nestedStepsContext,
|
|
569
862
|
snapshot: snapshot ?? { context: {} },
|
|
570
863
|
graph: this.executionGraph,
|
|
571
|
-
initialState: params.initialState
|
|
864
|
+
initialState: params.initialState,
|
|
865
|
+
perStep: params.perStep
|
|
572
866
|
});
|
|
573
867
|
const eventOutput = await this.inngest.send({
|
|
574
868
|
name: `workflow.${this.workflowId}`,
|
|
@@ -580,7 +874,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
580
874
|
timeTravel: timeTravelData,
|
|
581
875
|
tracingOptions: params.tracingOptions,
|
|
582
876
|
outputOptions: params.outputOptions,
|
|
583
|
-
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
877
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
878
|
+
perStep: params.perStep
|
|
584
879
|
}
|
|
585
880
|
});
|
|
586
881
|
const eventId = eventOutput.ids[0];
|
|
@@ -589,9 +884,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
589
884
|
}
|
|
590
885
|
const runOutput = await this.getRunOutput(eventId);
|
|
591
886
|
const result = runOutput?.output?.result;
|
|
592
|
-
|
|
593
|
-
result.error = new Error(result.error);
|
|
594
|
-
}
|
|
887
|
+
this.hydrateFailedResult(result);
|
|
595
888
|
return result;
|
|
596
889
|
}
|
|
597
890
|
watch(cb) {
|
|
@@ -673,7 +966,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
673
966
|
tracingOptions,
|
|
674
967
|
closeOnSuspend = true,
|
|
675
968
|
initialState,
|
|
676
|
-
outputOptions
|
|
969
|
+
outputOptions,
|
|
970
|
+
perStep
|
|
677
971
|
} = {}) {
|
|
678
972
|
if (this.closeStreamAction && this.streamOutput) {
|
|
679
973
|
return this.streamOutput;
|
|
@@ -709,7 +1003,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
709
1003
|
initialState,
|
|
710
1004
|
tracingOptions,
|
|
711
1005
|
outputOptions,
|
|
712
|
-
format: "vnext"
|
|
1006
|
+
format: "vnext",
|
|
1007
|
+
perStep
|
|
713
1008
|
});
|
|
714
1009
|
let executionResults;
|
|
715
1010
|
try {
|
|
@@ -740,9 +1035,6 @@ var InngestRun = class extends workflows.Run {
|
|
|
740
1035
|
});
|
|
741
1036
|
return this.streamOutput;
|
|
742
1037
|
}
|
|
743
|
-
streamVNext(args = {}) {
|
|
744
|
-
return this.stream(args);
|
|
745
|
-
}
|
|
746
1038
|
timeTravelStream({
|
|
747
1039
|
inputData,
|
|
748
1040
|
resumeData,
|
|
@@ -752,7 +1044,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
752
1044
|
nestedStepsContext,
|
|
753
1045
|
requestContext,
|
|
754
1046
|
tracingOptions,
|
|
755
|
-
outputOptions
|
|
1047
|
+
outputOptions,
|
|
1048
|
+
perStep
|
|
756
1049
|
}) {
|
|
757
1050
|
this.closeStreamAction = async () => {
|
|
758
1051
|
};
|
|
@@ -787,7 +1080,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
787
1080
|
initialState,
|
|
788
1081
|
requestContext,
|
|
789
1082
|
tracingOptions,
|
|
790
|
-
outputOptions
|
|
1083
|
+
outputOptions,
|
|
1084
|
+
perStep
|
|
791
1085
|
});
|
|
792
1086
|
self.executionResults = executionResultsPromise;
|
|
793
1087
|
let executionResults;
|
|
@@ -812,6 +1106,18 @@ var InngestRun = class extends workflows.Run {
|
|
|
812
1106
|
});
|
|
813
1107
|
return this.streamOutput;
|
|
814
1108
|
}
|
|
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);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
815
1121
|
};
|
|
816
1122
|
|
|
817
1123
|
// src/workflow.ts
|
|
@@ -819,9 +1125,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
819
1125
|
#mastra;
|
|
820
1126
|
inngest;
|
|
821
1127
|
function;
|
|
1128
|
+
cronFunction;
|
|
822
1129
|
flowControlConfig;
|
|
1130
|
+
cronConfig;
|
|
823
1131
|
constructor(params, inngest) {
|
|
824
|
-
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
1132
|
+
const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
|
|
825
1133
|
super(workflowParams);
|
|
826
1134
|
this.engineType = "inngest";
|
|
827
1135
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
@@ -830,6 +1138,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
830
1138
|
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
831
1139
|
this.#mastra = params.mastra;
|
|
832
1140
|
this.inngest = inngest;
|
|
1141
|
+
if (cron) {
|
|
1142
|
+
this.cronConfig = { cron, inputData, initialState };
|
|
1143
|
+
}
|
|
833
1144
|
}
|
|
834
1145
|
async listWorkflowRuns(args) {
|
|
835
1146
|
const storage = this.#mastra?.getStorage();
|
|
@@ -837,7 +1148,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
837
1148
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
838
1149
|
return { runs: [], total: 0 };
|
|
839
1150
|
}
|
|
840
|
-
|
|
1151
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1152
|
+
if (!workflowsStore) {
|
|
1153
|
+
return { runs: [], total: 0 };
|
|
1154
|
+
}
|
|
1155
|
+
return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
841
1156
|
}
|
|
842
1157
|
async getWorkflowRunById(runId) {
|
|
843
1158
|
const storage = this.#mastra?.getStorage();
|
|
@@ -845,10 +1160,15 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
845
1160
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
846
1161
|
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
847
1162
|
}
|
|
848
|
-
const
|
|
1163
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1164
|
+
if (!workflowsStore) {
|
|
1165
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
1166
|
+
}
|
|
1167
|
+
const run = await workflowsStore.getWorkflowRunById({ runId, workflowName: this.id });
|
|
849
1168
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
850
1169
|
}
|
|
851
1170
|
__registerMastra(mastra) {
|
|
1171
|
+
super.__registerMastra(mastra);
|
|
852
1172
|
this.#mastra = mastra;
|
|
853
1173
|
this.executionEngine.__registerMastra(mastra);
|
|
854
1174
|
const updateNested = (step) => {
|
|
@@ -867,7 +1187,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
867
1187
|
}
|
|
868
1188
|
}
|
|
869
1189
|
async createRun(options) {
|
|
870
|
-
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
1190
|
+
const runIdToUse = options?.runId || crypto$1.randomUUID();
|
|
871
1191
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
872
1192
|
{
|
|
873
1193
|
workflowId: this.id,
|
|
@@ -890,9 +1210,12 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
890
1210
|
workflowStatus: run.workflowRunStatus,
|
|
891
1211
|
stepResults: {}
|
|
892
1212
|
});
|
|
893
|
-
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse,
|
|
1213
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
|
|
1214
|
+
withNestedWorkflows: false
|
|
1215
|
+
});
|
|
894
1216
|
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
895
|
-
await this.mastra?.getStorage()?.
|
|
1217
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
1218
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
896
1219
|
workflowName: this.id,
|
|
897
1220
|
runId: runIdToUse,
|
|
898
1221
|
resourceId: options?.resourceId,
|
|
@@ -915,6 +1238,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
915
1238
|
}
|
|
916
1239
|
return run;
|
|
917
1240
|
}
|
|
1241
|
+
//createCronFunction is only called if cronConfig.cron is defined.
|
|
1242
|
+
createCronFunction() {
|
|
1243
|
+
if (this.cronFunction) {
|
|
1244
|
+
return this.cronFunction;
|
|
1245
|
+
}
|
|
1246
|
+
this.cronFunction = this.inngest.createFunction(
|
|
1247
|
+
{
|
|
1248
|
+
id: `workflow.${this.id}.cron`,
|
|
1249
|
+
retries: 0,
|
|
1250
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
1251
|
+
...this.flowControlConfig
|
|
1252
|
+
},
|
|
1253
|
+
{ cron: this.cronConfig?.cron ?? "" },
|
|
1254
|
+
async () => {
|
|
1255
|
+
const run = await this.createRun();
|
|
1256
|
+
const result = await run.start({
|
|
1257
|
+
inputData: this.cronConfig?.inputData,
|
|
1258
|
+
initialState: this.cronConfig?.initialState
|
|
1259
|
+
});
|
|
1260
|
+
return { result, runId: run.runId };
|
|
1261
|
+
}
|
|
1262
|
+
);
|
|
1263
|
+
return this.cronFunction;
|
|
1264
|
+
}
|
|
918
1265
|
getFunction() {
|
|
919
1266
|
if (this.function) {
|
|
920
1267
|
return this.function;
|
|
@@ -922,41 +1269,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
922
1269
|
this.function = this.inngest.createFunction(
|
|
923
1270
|
{
|
|
924
1271
|
id: `workflow.${this.id}`,
|
|
925
|
-
retries:
|
|
1272
|
+
retries: 0,
|
|
926
1273
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
927
1274
|
// Spread flow control configuration
|
|
928
1275
|
...this.flowControlConfig
|
|
929
1276
|
},
|
|
930
1277
|
{ event: `workflow.${this.id}` },
|
|
931
1278
|
async ({ event, step, attempt, publish }) => {
|
|
932
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
1279
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
|
|
933
1280
|
if (!runId) {
|
|
934
1281
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
935
|
-
return crypto.randomUUID();
|
|
1282
|
+
return crypto$1.randomUUID();
|
|
936
1283
|
});
|
|
937
1284
|
}
|
|
938
|
-
const
|
|
939
|
-
emit: async (event2, data) => {
|
|
940
|
-
if (!publish) {
|
|
941
|
-
return;
|
|
942
|
-
}
|
|
943
|
-
try {
|
|
944
|
-
await publish({
|
|
945
|
-
channel: `workflow:${this.id}:${runId}`,
|
|
946
|
-
topic: event2,
|
|
947
|
-
data
|
|
948
|
-
});
|
|
949
|
-
} catch (err) {
|
|
950
|
-
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
951
|
-
}
|
|
952
|
-
},
|
|
953
|
-
on: (_event, _callback) => {
|
|
954
|
-
},
|
|
955
|
-
off: (_event, _callback) => {
|
|
956
|
-
},
|
|
957
|
-
once: (_event, _callback) => {
|
|
958
|
-
}
|
|
959
|
-
};
|
|
1285
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
960
1286
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
961
1287
|
const result = await engine.execute({
|
|
962
1288
|
workflowId: this.id,
|
|
@@ -966,23 +1292,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
966
1292
|
serializedStepGraph: this.serializedStepGraph,
|
|
967
1293
|
input: inputData,
|
|
968
1294
|
initialState,
|
|
969
|
-
|
|
1295
|
+
pubsub,
|
|
970
1296
|
retryConfig: this.retryConfig,
|
|
971
1297
|
requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
972
1298
|
resume,
|
|
973
1299
|
timeTravel,
|
|
1300
|
+
perStep,
|
|
974
1301
|
format,
|
|
975
1302
|
abortController: new AbortController(),
|
|
976
1303
|
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
977
1304
|
outputOptions,
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1305
|
+
outputWriter: async (chunk) => {
|
|
1306
|
+
try {
|
|
1307
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1308
|
+
type: "watch",
|
|
1309
|
+
runId,
|
|
1310
|
+
data: chunk
|
|
981
1311
|
});
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
982
1314
|
}
|
|
983
|
-
}
|
|
1315
|
+
}
|
|
984
1316
|
});
|
|
985
1317
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1318
|
+
if (result.status !== "paused") {
|
|
1319
|
+
await engine.invokeLifecycleCallbacksInternal(result);
|
|
1320
|
+
}
|
|
986
1321
|
if (result.status === "failed") {
|
|
987
1322
|
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
988
1323
|
cause: result
|
|
@@ -1009,7 +1344,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
1009
1344
|
});
|
|
1010
1345
|
}
|
|
1011
1346
|
getFunctions() {
|
|
1012
|
-
return [
|
|
1347
|
+
return [
|
|
1348
|
+
this.getFunction(),
|
|
1349
|
+
...this.cronConfig?.cron ? [this.createCronFunction()] : [],
|
|
1350
|
+
...this.getNestedFunctions(this.executionGraph.steps)
|
|
1351
|
+
];
|
|
1013
1352
|
}
|
|
1014
1353
|
};
|
|
1015
1354
|
function serve({
|
|
@@ -1041,20 +1380,14 @@ function serve({
|
|
|
1041
1380
|
var _compatibilityCheck = true;
|
|
1042
1381
|
|
|
1043
1382
|
// src/index.ts
|
|
1044
|
-
function
|
|
1045
|
-
|
|
1046
|
-
}
|
|
1047
|
-
function isTool(params) {
|
|
1048
|
-
return params instanceof tools.Tool;
|
|
1049
|
-
}
|
|
1050
|
-
function isInngestWorkflow(params) {
|
|
1051
|
-
return params instanceof InngestWorkflow;
|
|
1052
|
-
}
|
|
1053
|
-
function createStep(params, agentOptions) {
|
|
1054
|
-
if (isInngestWorkflow(params)) {
|
|
1383
|
+
function createStep(params, agentOrToolOptions) {
|
|
1384
|
+
if (params instanceof InngestWorkflow) {
|
|
1055
1385
|
return params;
|
|
1056
1386
|
}
|
|
1057
|
-
if (
|
|
1387
|
+
if (params instanceof agent.Agent) {
|
|
1388
|
+
const options = agentOrToolOptions;
|
|
1389
|
+
const outputSchema = options?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
|
|
1390
|
+
const { retries, scorers, ...agentOptions } = options ?? {};
|
|
1058
1391
|
return {
|
|
1059
1392
|
id: params.name,
|
|
1060
1393
|
description: params.getDescription(),
|
|
@@ -1063,12 +1396,13 @@ function createStep(params, agentOptions) {
|
|
|
1063
1396
|
// resourceId: z.string().optional(),
|
|
1064
1397
|
// threadId: z.string().optional(),
|
|
1065
1398
|
}),
|
|
1066
|
-
outputSchema
|
|
1067
|
-
|
|
1068
|
-
|
|
1399
|
+
outputSchema,
|
|
1400
|
+
retries,
|
|
1401
|
+
scorers,
|
|
1069
1402
|
execute: async ({
|
|
1070
1403
|
inputData,
|
|
1071
|
-
|
|
1404
|
+
runId,
|
|
1405
|
+
[_constants.PUBSUB_SYMBOL]: pubsub,
|
|
1072
1406
|
[_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
1073
1407
|
requestContext,
|
|
1074
1408
|
tracingContext,
|
|
@@ -1081,6 +1415,7 @@ function createStep(params, agentOptions) {
|
|
|
1081
1415
|
streamPromise.resolve = resolve;
|
|
1082
1416
|
streamPromise.reject = reject;
|
|
1083
1417
|
});
|
|
1418
|
+
let structuredResult = null;
|
|
1084
1419
|
const toolData = {
|
|
1085
1420
|
name: params.name,
|
|
1086
1421
|
args: inputData
|
|
@@ -1094,6 +1429,10 @@ function createStep(params, agentOptions) {
|
|
|
1094
1429
|
requestContext,
|
|
1095
1430
|
tracingContext,
|
|
1096
1431
|
onFinish: (result) => {
|
|
1432
|
+
const resultWithObject = result;
|
|
1433
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1434
|
+
structuredResult = resultWithObject.object;
|
|
1435
|
+
}
|
|
1097
1436
|
streamPromise.resolve(result.text);
|
|
1098
1437
|
void agentOptions?.onFinish?.(result);
|
|
1099
1438
|
},
|
|
@@ -1106,6 +1445,10 @@ function createStep(params, agentOptions) {
|
|
|
1106
1445
|
requestContext,
|
|
1107
1446
|
tracingContext,
|
|
1108
1447
|
onFinish: (result) => {
|
|
1448
|
+
const resultWithObject = result;
|
|
1449
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1450
|
+
structuredResult = resultWithObject.object;
|
|
1451
|
+
}
|
|
1109
1452
|
streamPromise.resolve(result.text);
|
|
1110
1453
|
void agentOptions?.onFinish?.(result);
|
|
1111
1454
|
},
|
|
@@ -1114,22 +1457,24 @@ function createStep(params, agentOptions) {
|
|
|
1114
1457
|
stream = modelOutput.fullStream;
|
|
1115
1458
|
}
|
|
1116
1459
|
if (streamFormat === "legacy") {
|
|
1117
|
-
await
|
|
1118
|
-
type: "
|
|
1119
|
-
|
|
1460
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1461
|
+
type: "watch",
|
|
1462
|
+
runId,
|
|
1463
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
1120
1464
|
});
|
|
1121
1465
|
for await (const chunk of stream) {
|
|
1122
1466
|
if (chunk.type === "text-delta") {
|
|
1123
|
-
await
|
|
1124
|
-
type: "
|
|
1125
|
-
|
|
1126
|
-
argsTextDelta: chunk.textDelta
|
|
1467
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1468
|
+
type: "watch",
|
|
1469
|
+
runId,
|
|
1470
|
+
data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
|
|
1127
1471
|
});
|
|
1128
1472
|
}
|
|
1129
1473
|
}
|
|
1130
|
-
await
|
|
1131
|
-
type: "
|
|
1132
|
-
|
|
1474
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1475
|
+
type: "watch",
|
|
1476
|
+
runId,
|
|
1477
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
1133
1478
|
});
|
|
1134
1479
|
} else {
|
|
1135
1480
|
for await (const chunk of stream) {
|
|
@@ -1139,6 +1484,9 @@ function createStep(params, agentOptions) {
|
|
|
1139
1484
|
if (abortSignal.aborted) {
|
|
1140
1485
|
return abort();
|
|
1141
1486
|
}
|
|
1487
|
+
if (structuredResult !== null) {
|
|
1488
|
+
return structuredResult;
|
|
1489
|
+
}
|
|
1142
1490
|
return {
|
|
1143
1491
|
text: await streamPromise.promise
|
|
1144
1492
|
};
|
|
@@ -1146,7 +1494,8 @@ function createStep(params, agentOptions) {
|
|
|
1146
1494
|
component: params.component
|
|
1147
1495
|
};
|
|
1148
1496
|
}
|
|
1149
|
-
if (
|
|
1497
|
+
if (params instanceof tools.Tool) {
|
|
1498
|
+
const toolOpts = agentOrToolOptions;
|
|
1150
1499
|
if (!params.inputSchema || !params.outputSchema) {
|
|
1151
1500
|
throw new Error("Tool must have input and output schemas defined");
|
|
1152
1501
|
}
|
|
@@ -1158,6 +1507,8 @@ function createStep(params, agentOptions) {
|
|
|
1158
1507
|
outputSchema: params.outputSchema,
|
|
1159
1508
|
suspendSchema: params.suspendSchema,
|
|
1160
1509
|
resumeSchema: params.resumeSchema,
|
|
1510
|
+
retries: toolOpts?.retries,
|
|
1511
|
+
scorers: toolOpts?.scorers,
|
|
1161
1512
|
execute: async ({
|
|
1162
1513
|
inputData,
|
|
1163
1514
|
mastra,
|
|
@@ -1195,6 +1546,8 @@ function createStep(params, agentOptions) {
|
|
|
1195
1546
|
outputSchema: params.outputSchema,
|
|
1196
1547
|
resumeSchema: params.resumeSchema,
|
|
1197
1548
|
suspendSchema: params.suspendSchema,
|
|
1549
|
+
retries: params.retries,
|
|
1550
|
+
scorers: params.scorers,
|
|
1198
1551
|
execute: params.execute
|
|
1199
1552
|
};
|
|
1200
1553
|
}
|
|
@@ -1239,6 +1592,7 @@ function init(inngest) {
|
|
|
1239
1592
|
}
|
|
1240
1593
|
|
|
1241
1594
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
1595
|
+
exports.InngestPubSub = InngestPubSub;
|
|
1242
1596
|
exports.InngestRun = InngestRun;
|
|
1243
1597
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1244
1598
|
exports._compatibilityCheck = _compatibilityCheck;
|