@mastra/inngest 0.0.0-feat-add-query-option-to-playground-20251209160219 → 0.0.0-feat-8782-cf-bindings-20260102164434
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 +771 -12
- package/dist/execution-engine.d.ts +31 -8
- package/dist/execution-engine.d.ts.map +1 -1
- package/dist/index.cjs +560 -184
- 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 +556 -181
- 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 crypto$1 = require('crypto');
|
|
8
9
|
var di = require('@mastra/core/di');
|
|
9
10
|
var inngest = require('inngest');
|
|
10
|
-
var
|
|
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,39 +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
|
};
|
|
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" } };
|
|
270
362
|
}
|
|
271
|
-
await
|
|
272
|
-
type: "
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
}
|
|
277
373
|
}
|
|
278
374
|
});
|
|
279
|
-
await
|
|
280
|
-
type: "
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
+
}
|
|
284
384
|
}
|
|
285
385
|
});
|
|
286
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
386
|
+
return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
|
|
287
387
|
}
|
|
288
388
|
);
|
|
289
389
|
Object.assign(executionContext, res.executionContext);
|
|
290
390
|
return {
|
|
291
391
|
...res.result,
|
|
292
392
|
startedAt,
|
|
293
|
-
endedAt: Date.now(),
|
|
294
393
|
payload: inputData,
|
|
295
394
|
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
296
395
|
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
297
396
|
};
|
|
298
397
|
}
|
|
299
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
|
+
};
|
|
300
511
|
var InngestRun = class extends workflows.Run {
|
|
301
512
|
inngest;
|
|
302
513
|
serializedStepGraph;
|
|
@@ -308,38 +519,90 @@ var InngestRun = class extends workflows.Run {
|
|
|
308
519
|
this.#mastra = params.mastra;
|
|
309
520
|
}
|
|
310
521
|
async getRuns(eventId) {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
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
|
+
}
|
|
314
554
|
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return json.data;
|
|
555
|
+
}
|
|
556
|
+
throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
318
557
|
}
|
|
319
|
-
async getRunOutput(eventId) {
|
|
320
|
-
|
|
558
|
+
async getRunOutput(eventId, maxWaitMs = 3e5) {
|
|
559
|
+
const startTime = Date.now();
|
|
321
560
|
const storage = this.#mastra?.getStorage();
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
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
|
+
}
|
|
325
577
|
if (runs?.[0]?.status === "Failed") {
|
|
326
|
-
const snapshot = await
|
|
578
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
327
579
|
workflowName: this.workflowId,
|
|
328
580
|
runId: this.runId
|
|
329
581
|
});
|
|
582
|
+
if (snapshot?.context) {
|
|
583
|
+
snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
|
|
584
|
+
}
|
|
330
585
|
return {
|
|
331
|
-
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
|
+
}
|
|
332
594
|
};
|
|
333
595
|
}
|
|
334
596
|
if (runs?.[0]?.status === "Cancelled") {
|
|
335
|
-
const snapshot = await
|
|
597
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
336
598
|
workflowName: this.workflowId,
|
|
337
599
|
runId: this.runId
|
|
338
600
|
});
|
|
339
601
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
340
602
|
}
|
|
603
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
341
604
|
}
|
|
342
|
-
|
|
605
|
+
throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
343
606
|
}
|
|
344
607
|
async cancel() {
|
|
345
608
|
const storage = this.#mastra?.getStorage();
|
|
@@ -349,12 +612,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
349
612
|
runId: this.runId
|
|
350
613
|
}
|
|
351
614
|
});
|
|
352
|
-
const
|
|
615
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
616
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
353
617
|
workflowName: this.workflowId,
|
|
354
618
|
runId: this.runId
|
|
355
619
|
});
|
|
356
620
|
if (snapshot) {
|
|
357
|
-
await
|
|
621
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
358
622
|
workflowName: this.workflowId,
|
|
359
623
|
runId: this.runId,
|
|
360
624
|
resourceId: this.resourceId,
|
|
@@ -369,15 +633,64 @@ var InngestRun = class extends workflows.Run {
|
|
|
369
633
|
async start(params) {
|
|
370
634
|
return this._start(params);
|
|
371
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
|
+
}
|
|
372
683
|
async _start({
|
|
373
684
|
inputData,
|
|
374
685
|
initialState,
|
|
375
686
|
outputOptions,
|
|
376
687
|
tracingOptions,
|
|
377
688
|
format,
|
|
378
|
-
requestContext
|
|
689
|
+
requestContext,
|
|
690
|
+
perStep
|
|
379
691
|
}) {
|
|
380
|
-
await this.#mastra.getStorage()?.
|
|
692
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
693
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
381
694
|
workflowName: this.workflowId,
|
|
382
695
|
runId: this.runId,
|
|
383
696
|
resourceId: this.resourceId,
|
|
@@ -407,7 +720,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
407
720
|
outputOptions,
|
|
408
721
|
tracingOptions,
|
|
409
722
|
format,
|
|
410
|
-
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
723
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
|
|
724
|
+
perStep
|
|
411
725
|
}
|
|
412
726
|
});
|
|
413
727
|
const eventId = eventOutput.ids[0];
|
|
@@ -416,9 +730,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
416
730
|
}
|
|
417
731
|
const runOutput = await this.getRunOutput(eventId);
|
|
418
732
|
const result = runOutput?.output?.result;
|
|
419
|
-
|
|
420
|
-
result.error = new Error(result.error);
|
|
421
|
-
}
|
|
733
|
+
this.hydrateFailedResult(result);
|
|
422
734
|
if (result.status !== "suspended") {
|
|
423
735
|
this.cleanup?.();
|
|
424
736
|
}
|
|
@@ -445,7 +757,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
445
757
|
(step) => typeof step === "string" ? step : step?.id
|
|
446
758
|
);
|
|
447
759
|
}
|
|
448
|
-
const
|
|
760
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
761
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
449
762
|
workflowName: this.workflowId,
|
|
450
763
|
runId: this.runId
|
|
451
764
|
});
|
|
@@ -468,7 +781,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
468
781
|
resumePayload: resumeDataToUse,
|
|
469
782
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
470
783
|
},
|
|
471
|
-
requestContext: mergedRequestContext
|
|
784
|
+
requestContext: mergedRequestContext,
|
|
785
|
+
perStep: params.perStep
|
|
472
786
|
}
|
|
473
787
|
});
|
|
474
788
|
const eventId = eventOutput.ids[0];
|
|
@@ -477,9 +791,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
477
791
|
}
|
|
478
792
|
const runOutput = await this.getRunOutput(eventId);
|
|
479
793
|
const result = runOutput?.output?.result;
|
|
480
|
-
|
|
481
|
-
result.error = new Error(result.error);
|
|
482
|
-
}
|
|
794
|
+
this.hydrateFailedResult(result);
|
|
483
795
|
return result;
|
|
484
796
|
}
|
|
485
797
|
async timeTravel(params) {
|
|
@@ -509,12 +821,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
509
821
|
throw new Error("No steps provided to timeTravel");
|
|
510
822
|
}
|
|
511
823
|
const storage = this.#mastra?.getStorage();
|
|
512
|
-
const
|
|
824
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
825
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
513
826
|
workflowName: this.workflowId,
|
|
514
827
|
runId: this.runId
|
|
515
828
|
});
|
|
516
829
|
if (!snapshot) {
|
|
517
|
-
await
|
|
830
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
518
831
|
workflowName: this.workflowId,
|
|
519
832
|
runId: this.runId,
|
|
520
833
|
resourceId: this.resourceId,
|
|
@@ -548,7 +861,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
548
861
|
nestedStepsContext: params.nestedStepsContext,
|
|
549
862
|
snapshot: snapshot ?? { context: {} },
|
|
550
863
|
graph: this.executionGraph,
|
|
551
|
-
initialState: params.initialState
|
|
864
|
+
initialState: params.initialState,
|
|
865
|
+
perStep: params.perStep
|
|
552
866
|
});
|
|
553
867
|
const eventOutput = await this.inngest.send({
|
|
554
868
|
name: `workflow.${this.workflowId}`,
|
|
@@ -560,7 +874,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
560
874
|
timeTravel: timeTravelData,
|
|
561
875
|
tracingOptions: params.tracingOptions,
|
|
562
876
|
outputOptions: params.outputOptions,
|
|
563
|
-
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
877
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
878
|
+
perStep: params.perStep
|
|
564
879
|
}
|
|
565
880
|
});
|
|
566
881
|
const eventId = eventOutput.ids[0];
|
|
@@ -569,9 +884,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
569
884
|
}
|
|
570
885
|
const runOutput = await this.getRunOutput(eventId);
|
|
571
886
|
const result = runOutput?.output?.result;
|
|
572
|
-
|
|
573
|
-
result.error = new Error(result.error);
|
|
574
|
-
}
|
|
887
|
+
this.hydrateFailedResult(result);
|
|
575
888
|
return result;
|
|
576
889
|
}
|
|
577
890
|
watch(cb) {
|
|
@@ -653,7 +966,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
653
966
|
tracingOptions,
|
|
654
967
|
closeOnSuspend = true,
|
|
655
968
|
initialState,
|
|
656
|
-
outputOptions
|
|
969
|
+
outputOptions,
|
|
970
|
+
perStep
|
|
657
971
|
} = {}) {
|
|
658
972
|
if (this.closeStreamAction && this.streamOutput) {
|
|
659
973
|
return this.streamOutput;
|
|
@@ -689,7 +1003,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
689
1003
|
initialState,
|
|
690
1004
|
tracingOptions,
|
|
691
1005
|
outputOptions,
|
|
692
|
-
format: "vnext"
|
|
1006
|
+
format: "vnext",
|
|
1007
|
+
perStep
|
|
693
1008
|
});
|
|
694
1009
|
let executionResults;
|
|
695
1010
|
try {
|
|
@@ -720,9 +1035,6 @@ var InngestRun = class extends workflows.Run {
|
|
|
720
1035
|
});
|
|
721
1036
|
return this.streamOutput;
|
|
722
1037
|
}
|
|
723
|
-
streamVNext(args = {}) {
|
|
724
|
-
return this.stream(args);
|
|
725
|
-
}
|
|
726
1038
|
timeTravelStream({
|
|
727
1039
|
inputData,
|
|
728
1040
|
resumeData,
|
|
@@ -732,7 +1044,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
732
1044
|
nestedStepsContext,
|
|
733
1045
|
requestContext,
|
|
734
1046
|
tracingOptions,
|
|
735
|
-
outputOptions
|
|
1047
|
+
outputOptions,
|
|
1048
|
+
perStep
|
|
736
1049
|
}) {
|
|
737
1050
|
this.closeStreamAction = async () => {
|
|
738
1051
|
};
|
|
@@ -767,7 +1080,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
767
1080
|
initialState,
|
|
768
1081
|
requestContext,
|
|
769
1082
|
tracingOptions,
|
|
770
|
-
outputOptions
|
|
1083
|
+
outputOptions,
|
|
1084
|
+
perStep
|
|
771
1085
|
});
|
|
772
1086
|
self.executionResults = executionResultsPromise;
|
|
773
1087
|
let executionResults;
|
|
@@ -792,6 +1106,18 @@ var InngestRun = class extends workflows.Run {
|
|
|
792
1106
|
});
|
|
793
1107
|
return this.streamOutput;
|
|
794
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
|
+
}
|
|
795
1121
|
};
|
|
796
1122
|
|
|
797
1123
|
// src/workflow.ts
|
|
@@ -799,9 +1125,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
799
1125
|
#mastra;
|
|
800
1126
|
inngest;
|
|
801
1127
|
function;
|
|
1128
|
+
cronFunction;
|
|
802
1129
|
flowControlConfig;
|
|
1130
|
+
cronConfig;
|
|
803
1131
|
constructor(params, inngest) {
|
|
804
|
-
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
1132
|
+
const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
|
|
805
1133
|
super(workflowParams);
|
|
806
1134
|
this.engineType = "inngest";
|
|
807
1135
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
@@ -810,6 +1138,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
810
1138
|
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
811
1139
|
this.#mastra = params.mastra;
|
|
812
1140
|
this.inngest = inngest;
|
|
1141
|
+
if (cron) {
|
|
1142
|
+
this.cronConfig = { cron, inputData, initialState };
|
|
1143
|
+
}
|
|
813
1144
|
}
|
|
814
1145
|
async listWorkflowRuns(args) {
|
|
815
1146
|
const storage = this.#mastra?.getStorage();
|
|
@@ -817,7 +1148,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
817
1148
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
818
1149
|
return { runs: [], total: 0 };
|
|
819
1150
|
}
|
|
820
|
-
|
|
1151
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1152
|
+
if (!workflowsStore) {
|
|
1153
|
+
return { runs: [], total: 0 };
|
|
1154
|
+
}
|
|
1155
|
+
return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
821
1156
|
}
|
|
822
1157
|
async getWorkflowRunById(runId) {
|
|
823
1158
|
const storage = this.#mastra?.getStorage();
|
|
@@ -825,10 +1160,15 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
825
1160
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
826
1161
|
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
827
1162
|
}
|
|
828
|
-
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 });
|
|
829
1168
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
830
1169
|
}
|
|
831
1170
|
__registerMastra(mastra) {
|
|
1171
|
+
super.__registerMastra(mastra);
|
|
832
1172
|
this.#mastra = mastra;
|
|
833
1173
|
this.executionEngine.__registerMastra(mastra);
|
|
834
1174
|
const updateNested = (step) => {
|
|
@@ -847,7 +1187,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
847
1187
|
}
|
|
848
1188
|
}
|
|
849
1189
|
async createRun(options) {
|
|
850
|
-
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
1190
|
+
const runIdToUse = options?.runId || crypto$1.randomUUID();
|
|
851
1191
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
852
1192
|
{
|
|
853
1193
|
workflowId: this.id,
|
|
@@ -870,9 +1210,12 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
870
1210
|
workflowStatus: run.workflowRunStatus,
|
|
871
1211
|
stepResults: {}
|
|
872
1212
|
});
|
|
873
|
-
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse,
|
|
1213
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
|
|
1214
|
+
withNestedWorkflows: false
|
|
1215
|
+
});
|
|
874
1216
|
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
875
|
-
await this.mastra?.getStorage()?.
|
|
1217
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
1218
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
876
1219
|
workflowName: this.id,
|
|
877
1220
|
runId: runIdToUse,
|
|
878
1221
|
resourceId: options?.resourceId,
|
|
@@ -895,6 +1238,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
895
1238
|
}
|
|
896
1239
|
return run;
|
|
897
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
|
+
}
|
|
898
1265
|
getFunction() {
|
|
899
1266
|
if (this.function) {
|
|
900
1267
|
return this.function;
|
|
@@ -902,41 +1269,20 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
902
1269
|
this.function = this.inngest.createFunction(
|
|
903
1270
|
{
|
|
904
1271
|
id: `workflow.${this.id}`,
|
|
905
|
-
retries:
|
|
1272
|
+
retries: 0,
|
|
906
1273
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
907
1274
|
// Spread flow control configuration
|
|
908
1275
|
...this.flowControlConfig
|
|
909
1276
|
},
|
|
910
1277
|
{ event: `workflow.${this.id}` },
|
|
911
1278
|
async ({ event, step, attempt, publish }) => {
|
|
912
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
1279
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
|
|
913
1280
|
if (!runId) {
|
|
914
1281
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
915
|
-
return crypto.randomUUID();
|
|
1282
|
+
return crypto$1.randomUUID();
|
|
916
1283
|
});
|
|
917
1284
|
}
|
|
918
|
-
const
|
|
919
|
-
emit: async (event2, data) => {
|
|
920
|
-
if (!publish) {
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
try {
|
|
924
|
-
await publish({
|
|
925
|
-
channel: `workflow:${this.id}:${runId}`,
|
|
926
|
-
topic: event2,
|
|
927
|
-
data
|
|
928
|
-
});
|
|
929
|
-
} catch (err) {
|
|
930
|
-
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
931
|
-
}
|
|
932
|
-
},
|
|
933
|
-
on: (_event, _callback) => {
|
|
934
|
-
},
|
|
935
|
-
off: (_event, _callback) => {
|
|
936
|
-
},
|
|
937
|
-
once: (_event, _callback) => {
|
|
938
|
-
}
|
|
939
|
-
};
|
|
1285
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
940
1286
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
941
1287
|
const result = await engine.execute({
|
|
942
1288
|
workflowId: this.id,
|
|
@@ -946,21 +1292,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
946
1292
|
serializedStepGraph: this.serializedStepGraph,
|
|
947
1293
|
input: inputData,
|
|
948
1294
|
initialState,
|
|
949
|
-
|
|
1295
|
+
pubsub,
|
|
950
1296
|
retryConfig: this.retryConfig,
|
|
951
1297
|
requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
952
1298
|
resume,
|
|
953
1299
|
timeTravel,
|
|
1300
|
+
perStep,
|
|
954
1301
|
format,
|
|
955
1302
|
abortController: new AbortController(),
|
|
956
1303
|
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
957
1304
|
outputOptions,
|
|
958
1305
|
outputWriter: async (chunk) => {
|
|
959
|
-
|
|
960
|
-
|
|
1306
|
+
try {
|
|
1307
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1308
|
+
type: "watch",
|
|
1309
|
+
runId,
|
|
1310
|
+
data: chunk
|
|
1311
|
+
});
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
1314
|
+
}
|
|
961
1315
|
}
|
|
962
1316
|
});
|
|
963
1317
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1318
|
+
if (result.status !== "paused") {
|
|
1319
|
+
await engine.invokeLifecycleCallbacksInternal(result);
|
|
1320
|
+
}
|
|
964
1321
|
if (result.status === "failed") {
|
|
965
1322
|
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
966
1323
|
cause: result
|
|
@@ -987,7 +1344,11 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
987
1344
|
});
|
|
988
1345
|
}
|
|
989
1346
|
getFunctions() {
|
|
990
|
-
return [
|
|
1347
|
+
return [
|
|
1348
|
+
this.getFunction(),
|
|
1349
|
+
...this.cronConfig?.cron ? [this.createCronFunction()] : [],
|
|
1350
|
+
...this.getNestedFunctions(this.executionGraph.steps)
|
|
1351
|
+
];
|
|
991
1352
|
}
|
|
992
1353
|
};
|
|
993
1354
|
function serve({
|
|
@@ -1019,20 +1380,14 @@ function serve({
|
|
|
1019
1380
|
var _compatibilityCheck = true;
|
|
1020
1381
|
|
|
1021
1382
|
// src/index.ts
|
|
1022
|
-
function
|
|
1023
|
-
|
|
1024
|
-
}
|
|
1025
|
-
function isTool(params) {
|
|
1026
|
-
return params instanceof tools.Tool;
|
|
1027
|
-
}
|
|
1028
|
-
function isInngestWorkflow(params) {
|
|
1029
|
-
return params instanceof InngestWorkflow;
|
|
1030
|
-
}
|
|
1031
|
-
function createStep(params, agentOptions) {
|
|
1032
|
-
if (isInngestWorkflow(params)) {
|
|
1383
|
+
function createStep(params, agentOrToolOptions) {
|
|
1384
|
+
if (params instanceof InngestWorkflow) {
|
|
1033
1385
|
return params;
|
|
1034
1386
|
}
|
|
1035
|
-
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 ?? {};
|
|
1036
1391
|
return {
|
|
1037
1392
|
id: params.name,
|
|
1038
1393
|
description: params.getDescription(),
|
|
@@ -1041,12 +1396,13 @@ function createStep(params, agentOptions) {
|
|
|
1041
1396
|
// resourceId: z.string().optional(),
|
|
1042
1397
|
// threadId: z.string().optional(),
|
|
1043
1398
|
}),
|
|
1044
|
-
outputSchema
|
|
1045
|
-
|
|
1046
|
-
|
|
1399
|
+
outputSchema,
|
|
1400
|
+
retries,
|
|
1401
|
+
scorers,
|
|
1047
1402
|
execute: async ({
|
|
1048
1403
|
inputData,
|
|
1049
|
-
|
|
1404
|
+
runId,
|
|
1405
|
+
[_constants.PUBSUB_SYMBOL]: pubsub,
|
|
1050
1406
|
[_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
1051
1407
|
requestContext,
|
|
1052
1408
|
tracingContext,
|
|
@@ -1059,6 +1415,7 @@ function createStep(params, agentOptions) {
|
|
|
1059
1415
|
streamPromise.resolve = resolve;
|
|
1060
1416
|
streamPromise.reject = reject;
|
|
1061
1417
|
});
|
|
1418
|
+
let structuredResult = null;
|
|
1062
1419
|
const toolData = {
|
|
1063
1420
|
name: params.name,
|
|
1064
1421
|
args: inputData
|
|
@@ -1072,6 +1429,10 @@ function createStep(params, agentOptions) {
|
|
|
1072
1429
|
requestContext,
|
|
1073
1430
|
tracingContext,
|
|
1074
1431
|
onFinish: (result) => {
|
|
1432
|
+
const resultWithObject = result;
|
|
1433
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1434
|
+
structuredResult = resultWithObject.object;
|
|
1435
|
+
}
|
|
1075
1436
|
streamPromise.resolve(result.text);
|
|
1076
1437
|
void agentOptions?.onFinish?.(result);
|
|
1077
1438
|
},
|
|
@@ -1084,6 +1445,10 @@ function createStep(params, agentOptions) {
|
|
|
1084
1445
|
requestContext,
|
|
1085
1446
|
tracingContext,
|
|
1086
1447
|
onFinish: (result) => {
|
|
1448
|
+
const resultWithObject = result;
|
|
1449
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1450
|
+
structuredResult = resultWithObject.object;
|
|
1451
|
+
}
|
|
1087
1452
|
streamPromise.resolve(result.text);
|
|
1088
1453
|
void agentOptions?.onFinish?.(result);
|
|
1089
1454
|
},
|
|
@@ -1092,22 +1457,24 @@ function createStep(params, agentOptions) {
|
|
|
1092
1457
|
stream = modelOutput.fullStream;
|
|
1093
1458
|
}
|
|
1094
1459
|
if (streamFormat === "legacy") {
|
|
1095
|
-
await
|
|
1096
|
-
type: "
|
|
1097
|
-
|
|
1460
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1461
|
+
type: "watch",
|
|
1462
|
+
runId,
|
|
1463
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
1098
1464
|
});
|
|
1099
1465
|
for await (const chunk of stream) {
|
|
1100
1466
|
if (chunk.type === "text-delta") {
|
|
1101
|
-
await
|
|
1102
|
-
type: "
|
|
1103
|
-
|
|
1104
|
-
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 }
|
|
1105
1471
|
});
|
|
1106
1472
|
}
|
|
1107
1473
|
}
|
|
1108
|
-
await
|
|
1109
|
-
type: "
|
|
1110
|
-
|
|
1474
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1475
|
+
type: "watch",
|
|
1476
|
+
runId,
|
|
1477
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
1111
1478
|
});
|
|
1112
1479
|
} else {
|
|
1113
1480
|
for await (const chunk of stream) {
|
|
@@ -1117,6 +1484,9 @@ function createStep(params, agentOptions) {
|
|
|
1117
1484
|
if (abortSignal.aborted) {
|
|
1118
1485
|
return abort();
|
|
1119
1486
|
}
|
|
1487
|
+
if (structuredResult !== null) {
|
|
1488
|
+
return structuredResult;
|
|
1489
|
+
}
|
|
1120
1490
|
return {
|
|
1121
1491
|
text: await streamPromise.promise
|
|
1122
1492
|
};
|
|
@@ -1124,7 +1494,8 @@ function createStep(params, agentOptions) {
|
|
|
1124
1494
|
component: params.component
|
|
1125
1495
|
};
|
|
1126
1496
|
}
|
|
1127
|
-
if (
|
|
1497
|
+
if (params instanceof tools.Tool) {
|
|
1498
|
+
const toolOpts = agentOrToolOptions;
|
|
1128
1499
|
if (!params.inputSchema || !params.outputSchema) {
|
|
1129
1500
|
throw new Error("Tool must have input and output schemas defined");
|
|
1130
1501
|
}
|
|
@@ -1136,6 +1507,8 @@ function createStep(params, agentOptions) {
|
|
|
1136
1507
|
outputSchema: params.outputSchema,
|
|
1137
1508
|
suspendSchema: params.suspendSchema,
|
|
1138
1509
|
resumeSchema: params.resumeSchema,
|
|
1510
|
+
retries: toolOpts?.retries,
|
|
1511
|
+
scorers: toolOpts?.scorers,
|
|
1139
1512
|
execute: async ({
|
|
1140
1513
|
inputData,
|
|
1141
1514
|
mastra,
|
|
@@ -1173,6 +1546,8 @@ function createStep(params, agentOptions) {
|
|
|
1173
1546
|
outputSchema: params.outputSchema,
|
|
1174
1547
|
resumeSchema: params.resumeSchema,
|
|
1175
1548
|
suspendSchema: params.suspendSchema,
|
|
1549
|
+
retries: params.retries,
|
|
1550
|
+
scorers: params.scorers,
|
|
1176
1551
|
execute: params.execute
|
|
1177
1552
|
};
|
|
1178
1553
|
}
|
|
@@ -1217,6 +1592,7 @@ function init(inngest) {
|
|
|
1217
1592
|
}
|
|
1218
1593
|
|
|
1219
1594
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
1595
|
+
exports.InngestPubSub = InngestPubSub;
|
|
1220
1596
|
exports.InngestRun = InngestRun;
|
|
1221
1597
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1222
1598
|
exports._compatibilityCheck = _compatibilityCheck;
|