@mastra/inngest 0.0.0-fix-prompt-enhance-route-20251210210827 → 0.0.0-fix-11329-windows-path-20251222155941
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 +410 -12
- package/dist/execution-engine.d.ts +30 -5
- package/dist/execution-engine.d.ts.map +1 -1
- package/dist/index.cjs +441 -120
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +436 -116
- 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 +37 -4
- package/dist/run.d.ts.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/package.json +7 -8
package/dist/index.cjs
CHANGED
|
@@ -4,11 +4,13 @@ var tools = require('@mastra/core/tools');
|
|
|
4
4
|
var workflows = require('@mastra/core/workflows');
|
|
5
5
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
6
6
|
var zod = require('zod');
|
|
7
|
-
var crypto = require('crypto');
|
|
7
|
+
var crypto$1 = require('crypto');
|
|
8
8
|
var di = require('@mastra/core/di');
|
|
9
9
|
var inngest = require('inngest');
|
|
10
|
-
var
|
|
10
|
+
var error = require('@mastra/core/error');
|
|
11
11
|
var realtime = require('@inngest/realtime');
|
|
12
|
+
var events = require('@mastra/core/events');
|
|
13
|
+
var web = require('stream/web');
|
|
12
14
|
var stream = require('@mastra/core/stream');
|
|
13
15
|
var hono = require('inngest/hono');
|
|
14
16
|
|
|
@@ -25,17 +27,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
25
27
|
// Hook Overrides
|
|
26
28
|
// =============================================================================
|
|
27
29
|
/**
|
|
28
|
-
* Format errors
|
|
30
|
+
* Format errors while preserving Error instances and their custom properties.
|
|
31
|
+
* Uses getErrorFromUnknown to ensure all error properties are preserved.
|
|
29
32
|
*/
|
|
30
|
-
formatResultError(error, lastOutput) {
|
|
31
|
-
if (error instanceof Error) {
|
|
32
|
-
return error.stack ?? error.message;
|
|
33
|
-
}
|
|
33
|
+
formatResultError(error$1, lastOutput) {
|
|
34
34
|
const outputError = lastOutput?.error;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
const errorSource = error$1 || outputError;
|
|
36
|
+
const errorInstance = error.getErrorFromUnknown(errorSource, {
|
|
37
|
+
serializeStack: true,
|
|
38
|
+
// Include stack in JSON for better debugging in Inngest
|
|
39
|
+
fallbackMessage: "Unknown workflow error"
|
|
40
|
+
});
|
|
41
|
+
return errorInstance.toJSON();
|
|
39
42
|
}
|
|
40
43
|
/**
|
|
41
44
|
* Detect InngestWorkflow instances for special nested workflow handling
|
|
@@ -67,18 +70,24 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
67
70
|
error: e,
|
|
68
71
|
attributes: { status: "failed" }
|
|
69
72
|
});
|
|
73
|
+
if (cause.error && !(cause.error instanceof Error)) {
|
|
74
|
+
cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
|
|
75
|
+
}
|
|
70
76
|
return { ok: false, error: cause };
|
|
71
77
|
}
|
|
72
|
-
const
|
|
78
|
+
const errorInstance = error.getErrorFromUnknown(e, {
|
|
79
|
+
serializeStack: false,
|
|
80
|
+
fallbackMessage: "Unknown step execution error"
|
|
81
|
+
});
|
|
73
82
|
params.stepSpan?.error({
|
|
74
|
-
error:
|
|
83
|
+
error: errorInstance,
|
|
75
84
|
attributes: { status: "failed" }
|
|
76
85
|
});
|
|
77
86
|
return {
|
|
78
87
|
ok: false,
|
|
79
88
|
error: {
|
|
80
89
|
status: "failed",
|
|
81
|
-
error:
|
|
90
|
+
error: errorInstance,
|
|
82
91
|
endedAt: Date.now()
|
|
83
92
|
}
|
|
84
93
|
};
|
|
@@ -107,11 +116,14 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
107
116
|
return await operationFn();
|
|
108
117
|
} catch (e) {
|
|
109
118
|
if (retryConfig) {
|
|
110
|
-
const
|
|
111
|
-
|
|
119
|
+
const errorInstance = error.getErrorFromUnknown(e, {
|
|
120
|
+
serializeStack: false,
|
|
121
|
+
fallbackMessage: "Unknown step execution error"
|
|
122
|
+
});
|
|
123
|
+
throw new inngest.RetryAfterError(errorInstance.message, retryConfig.delay, {
|
|
112
124
|
cause: {
|
|
113
125
|
status: "failed",
|
|
114
|
-
error:
|
|
126
|
+
error: errorInstance,
|
|
115
127
|
endedAt: Date.now()
|
|
116
128
|
}
|
|
117
129
|
});
|
|
@@ -126,6 +138,18 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
126
138
|
getEngineContext() {
|
|
127
139
|
return { step: this.inngestStep };
|
|
128
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* For Inngest, lifecycle callbacks are invoked in the workflow's finalize step
|
|
143
|
+
* (wrapped in step.run for durability), not in execute(). Override to skip.
|
|
144
|
+
*/
|
|
145
|
+
async invokeLifecycleCallbacks(_result) {
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Actually invoke the lifecycle callbacks. Called from workflow.ts finalize step.
|
|
149
|
+
*/
|
|
150
|
+
async invokeLifecycleCallbacksInternal(result) {
|
|
151
|
+
return super.invokeLifecycleCallbacks(result);
|
|
152
|
+
}
|
|
129
153
|
/**
|
|
130
154
|
* Execute nested InngestWorkflow using inngestStep.invoke() for durability.
|
|
131
155
|
* This MUST be called directly (not inside step.run()) due to Inngest constraints.
|
|
@@ -134,14 +158,25 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
134
158
|
if (!(params.step instanceof InngestWorkflow)) {
|
|
135
159
|
return null;
|
|
136
160
|
}
|
|
137
|
-
const {
|
|
161
|
+
const {
|
|
162
|
+
step,
|
|
163
|
+
stepResults,
|
|
164
|
+
executionContext,
|
|
165
|
+
resume,
|
|
166
|
+
timeTravel,
|
|
167
|
+
prevOutput,
|
|
168
|
+
inputData,
|
|
169
|
+
pubsub,
|
|
170
|
+
startedAt,
|
|
171
|
+
perStep
|
|
172
|
+
} = params;
|
|
138
173
|
const isResume = !!resume?.steps?.length;
|
|
139
174
|
let result;
|
|
140
175
|
let runId;
|
|
141
176
|
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
142
177
|
try {
|
|
143
178
|
if (isResume) {
|
|
144
|
-
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
179
|
+
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
|
|
145
180
|
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
146
181
|
workflowName: step.id,
|
|
147
182
|
runId
|
|
@@ -159,7 +194,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
159
194
|
resumePayload: resume.resumePayload,
|
|
160
195
|
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
161
196
|
},
|
|
162
|
-
outputOptions: { includeState: true }
|
|
197
|
+
outputOptions: { includeState: true },
|
|
198
|
+
perStep
|
|
163
199
|
}
|
|
164
200
|
});
|
|
165
201
|
result = invokeResp.result;
|
|
@@ -185,7 +221,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
185
221
|
timeTravel: timeTravelParams,
|
|
186
222
|
initialState: executionContext.state ?? {},
|
|
187
223
|
runId: executionContext.runId,
|
|
188
|
-
outputOptions: { includeState: true }
|
|
224
|
+
outputOptions: { includeState: true },
|
|
225
|
+
perStep
|
|
189
226
|
}
|
|
190
227
|
});
|
|
191
228
|
result = invokeResp.result;
|
|
@@ -197,7 +234,8 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
197
234
|
data: {
|
|
198
235
|
inputData,
|
|
199
236
|
initialState: executionContext.state ?? {},
|
|
200
|
-
outputOptions: { includeState: true }
|
|
237
|
+
outputOptions: { includeState: true },
|
|
238
|
+
perStep
|
|
201
239
|
}
|
|
202
240
|
});
|
|
203
241
|
result = invokeResp.result;
|
|
@@ -208,9 +246,9 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
208
246
|
const errorCause = e?.cause;
|
|
209
247
|
if (errorCause && typeof errorCause === "object") {
|
|
210
248
|
result = errorCause;
|
|
211
|
-
runId = errorCause.runId || crypto.randomUUID();
|
|
249
|
+
runId = errorCause.runId || crypto$1.randomUUID();
|
|
212
250
|
} else {
|
|
213
|
-
runId = crypto.randomUUID();
|
|
251
|
+
runId = crypto$1.randomUUID();
|
|
214
252
|
result = {
|
|
215
253
|
status: "failed",
|
|
216
254
|
error: e instanceof Error ? e : new Error(String(e)),
|
|
@@ -223,16 +261,20 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
223
261
|
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
224
262
|
async () => {
|
|
225
263
|
if (result.status === "failed") {
|
|
226
|
-
await
|
|
227
|
-
type: "
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
264
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
265
|
+
type: "watch",
|
|
266
|
+
runId: executionContext.runId,
|
|
267
|
+
data: {
|
|
268
|
+
type: "workflow-step-result",
|
|
269
|
+
payload: {
|
|
270
|
+
id: step.id,
|
|
271
|
+
status: "failed",
|
|
272
|
+
error: result?.error,
|
|
273
|
+
payload: prevOutput
|
|
274
|
+
}
|
|
233
275
|
}
|
|
234
276
|
});
|
|
235
|
-
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
277
|
+
return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
|
|
236
278
|
} else if (result.status === "suspended") {
|
|
237
279
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
238
280
|
const stepRes = stepResult;
|
|
@@ -241,17 +283,22 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
241
283
|
for (const [stepName, stepResult] of suspendedSteps) {
|
|
242
284
|
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
243
285
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
244
|
-
await
|
|
245
|
-
type: "
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
286
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
287
|
+
type: "watch",
|
|
288
|
+
runId: executionContext.runId,
|
|
289
|
+
data: {
|
|
290
|
+
type: "workflow-step-suspended",
|
|
291
|
+
payload: {
|
|
292
|
+
id: step.id,
|
|
293
|
+
status: "suspended"
|
|
294
|
+
}
|
|
249
295
|
}
|
|
250
296
|
});
|
|
251
297
|
return {
|
|
252
298
|
executionContext,
|
|
253
299
|
result: {
|
|
254
300
|
status: "suspended",
|
|
301
|
+
suspendedAt: Date.now(),
|
|
255
302
|
payload: stepResult.payload,
|
|
256
303
|
suspendPayload: {
|
|
257
304
|
...stepResult?.suspendPayload,
|
|
@@ -264,39 +311,205 @@ var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
|
264
311
|
executionContext,
|
|
265
312
|
result: {
|
|
266
313
|
status: "suspended",
|
|
314
|
+
suspendedAt: Date.now(),
|
|
267
315
|
payload: {}
|
|
268
316
|
}
|
|
269
317
|
};
|
|
318
|
+
} else if (result.status === "tripwire") {
|
|
319
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
320
|
+
type: "watch",
|
|
321
|
+
runId: executionContext.runId,
|
|
322
|
+
data: {
|
|
323
|
+
type: "workflow-step-result",
|
|
324
|
+
payload: {
|
|
325
|
+
id: step.id,
|
|
326
|
+
status: "tripwire",
|
|
327
|
+
error: result?.tripwire?.reason,
|
|
328
|
+
payload: prevOutput
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
executionContext,
|
|
334
|
+
result: {
|
|
335
|
+
status: "tripwire",
|
|
336
|
+
tripwire: result?.tripwire,
|
|
337
|
+
endedAt: Date.now()
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
} else if (perStep || result.status === "paused") {
|
|
341
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
342
|
+
type: "watch",
|
|
343
|
+
runId: executionContext.runId,
|
|
344
|
+
data: {
|
|
345
|
+
type: "workflow-step-result",
|
|
346
|
+
payload: {
|
|
347
|
+
id: step.id,
|
|
348
|
+
status: "paused"
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
353
|
+
type: "watch",
|
|
354
|
+
runId: executionContext.runId,
|
|
355
|
+
data: {
|
|
356
|
+
type: "workflow-step-finish",
|
|
357
|
+
payload: {
|
|
358
|
+
id: step.id,
|
|
359
|
+
metadata: {}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
return { executionContext, result: { status: "paused" } };
|
|
270
364
|
}
|
|
271
|
-
await
|
|
272
|
-
type: "
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
365
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
366
|
+
type: "watch",
|
|
367
|
+
runId: executionContext.runId,
|
|
368
|
+
data: {
|
|
369
|
+
type: "workflow-step-result",
|
|
370
|
+
payload: {
|
|
371
|
+
id: step.id,
|
|
372
|
+
status: "success",
|
|
373
|
+
output: result?.result
|
|
374
|
+
}
|
|
277
375
|
}
|
|
278
376
|
});
|
|
279
|
-
await
|
|
280
|
-
type: "
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
377
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
378
|
+
type: "watch",
|
|
379
|
+
runId: executionContext.runId,
|
|
380
|
+
data: {
|
|
381
|
+
type: "workflow-step-finish",
|
|
382
|
+
payload: {
|
|
383
|
+
id: step.id,
|
|
384
|
+
metadata: {}
|
|
385
|
+
}
|
|
284
386
|
}
|
|
285
387
|
});
|
|
286
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
388
|
+
return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
|
|
287
389
|
}
|
|
288
390
|
);
|
|
289
391
|
Object.assign(executionContext, res.executionContext);
|
|
290
392
|
return {
|
|
291
393
|
...res.result,
|
|
292
394
|
startedAt,
|
|
293
|
-
endedAt: Date.now(),
|
|
294
395
|
payload: inputData,
|
|
295
396
|
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
296
397
|
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
297
398
|
};
|
|
298
399
|
}
|
|
299
400
|
};
|
|
401
|
+
var InngestPubSub = class extends events.PubSub {
|
|
402
|
+
inngest;
|
|
403
|
+
workflowId;
|
|
404
|
+
publishFn;
|
|
405
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
406
|
+
constructor(inngest, workflowId, publishFn) {
|
|
407
|
+
super();
|
|
408
|
+
this.inngest = inngest;
|
|
409
|
+
this.workflowId = workflowId;
|
|
410
|
+
this.publishFn = publishFn;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Publish an event to Inngest's realtime system.
|
|
414
|
+
*
|
|
415
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
416
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
417
|
+
*/
|
|
418
|
+
async publish(topic, event) {
|
|
419
|
+
if (!this.publishFn) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
423
|
+
if (!match) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const runId = match[1];
|
|
427
|
+
try {
|
|
428
|
+
await this.publishFn({
|
|
429
|
+
channel: `workflow:${this.workflowId}:${runId}`,
|
|
430
|
+
topic: "watch",
|
|
431
|
+
data: event.data
|
|
432
|
+
});
|
|
433
|
+
} catch (err) {
|
|
434
|
+
console.error("InngestPubSub publish error:", err?.message ?? err);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Subscribe to events from Inngest's realtime system.
|
|
439
|
+
*
|
|
440
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
441
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
442
|
+
*/
|
|
443
|
+
async subscribe(topic, cb) {
|
|
444
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
445
|
+
if (!match || !match[1]) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const runId = match[1];
|
|
449
|
+
if (this.subscriptions.has(topic)) {
|
|
450
|
+
this.subscriptions.get(topic).callbacks.add(cb);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
const callbacks = /* @__PURE__ */ new Set([cb]);
|
|
454
|
+
const channel = `workflow:${this.workflowId}:${runId}`;
|
|
455
|
+
const streamPromise = realtime.subscribe(
|
|
456
|
+
{
|
|
457
|
+
channel,
|
|
458
|
+
topics: ["watch"],
|
|
459
|
+
app: this.inngest
|
|
460
|
+
},
|
|
461
|
+
(message) => {
|
|
462
|
+
const event = {
|
|
463
|
+
id: crypto.randomUUID(),
|
|
464
|
+
type: "watch",
|
|
465
|
+
runId,
|
|
466
|
+
data: message.data,
|
|
467
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
468
|
+
};
|
|
469
|
+
for (const callback of callbacks) {
|
|
470
|
+
callback(event);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
this.subscriptions.set(topic, {
|
|
475
|
+
unsubscribe: () => {
|
|
476
|
+
streamPromise.then((stream) => stream.cancel()).catch((err) => {
|
|
477
|
+
console.error("InngestPubSub unsubscribe error:", err);
|
|
478
|
+
});
|
|
479
|
+
},
|
|
480
|
+
callbacks
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Unsubscribe a callback from a topic.
|
|
485
|
+
* If no callbacks remain, the underlying Inngest subscription is cancelled.
|
|
486
|
+
*/
|
|
487
|
+
async unsubscribe(topic, cb) {
|
|
488
|
+
const sub = this.subscriptions.get(topic);
|
|
489
|
+
if (!sub) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
sub.callbacks.delete(cb);
|
|
493
|
+
if (sub.callbacks.size === 0) {
|
|
494
|
+
sub.unsubscribe();
|
|
495
|
+
this.subscriptions.delete(topic);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Flush any pending operations. No-op for Inngest.
|
|
500
|
+
*/
|
|
501
|
+
async flush() {
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Clean up all subscriptions during graceful shutdown.
|
|
505
|
+
*/
|
|
506
|
+
async close() {
|
|
507
|
+
for (const [, sub] of this.subscriptions) {
|
|
508
|
+
sub.unsubscribe();
|
|
509
|
+
}
|
|
510
|
+
this.subscriptions.clear();
|
|
511
|
+
}
|
|
512
|
+
};
|
|
300
513
|
var InngestRun = class extends workflows.Run {
|
|
301
514
|
inngest;
|
|
302
515
|
serializedStepGraph;
|
|
@@ -308,27 +521,77 @@ var InngestRun = class extends workflows.Run {
|
|
|
308
521
|
this.#mastra = params.mastra;
|
|
309
522
|
}
|
|
310
523
|
async getRuns(eventId) {
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
524
|
+
const maxRetries = 3;
|
|
525
|
+
let lastError = null;
|
|
526
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
527
|
+
try {
|
|
528
|
+
const response = await fetch(
|
|
529
|
+
`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
|
|
530
|
+
{
|
|
531
|
+
headers: {
|
|
532
|
+
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
if (response.status === 429) {
|
|
537
|
+
const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
|
|
538
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (!response.ok) {
|
|
542
|
+
throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
|
|
543
|
+
}
|
|
544
|
+
const text = await response.text();
|
|
545
|
+
if (!text) {
|
|
546
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const json = JSON.parse(text);
|
|
550
|
+
return json.data;
|
|
551
|
+
} catch (error) {
|
|
552
|
+
lastError = error;
|
|
553
|
+
if (attempt < maxRetries - 1) {
|
|
554
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
|
555
|
+
}
|
|
314
556
|
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return json.data;
|
|
557
|
+
}
|
|
558
|
+
throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
318
559
|
}
|
|
319
|
-
async getRunOutput(eventId) {
|
|
320
|
-
|
|
560
|
+
async getRunOutput(eventId, maxWaitMs = 3e5) {
|
|
561
|
+
const startTime = Date.now();
|
|
321
562
|
const storage = this.#mastra?.getStorage();
|
|
322
|
-
while (
|
|
323
|
-
|
|
324
|
-
|
|
563
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
564
|
+
let runs;
|
|
565
|
+
try {
|
|
566
|
+
runs = await this.getRuns(eventId);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
if (error instanceof inngest.NonRetriableError) {
|
|
569
|
+
throw error;
|
|
570
|
+
}
|
|
571
|
+
throw new inngest.NonRetriableError(
|
|
572
|
+
`Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
|
|
576
|
+
return runs[0];
|
|
577
|
+
}
|
|
325
578
|
if (runs?.[0]?.status === "Failed") {
|
|
326
579
|
const snapshot = await storage?.loadWorkflowSnapshot({
|
|
327
580
|
workflowName: this.workflowId,
|
|
328
581
|
runId: this.runId
|
|
329
582
|
});
|
|
583
|
+
if (snapshot?.context) {
|
|
584
|
+
snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
|
|
585
|
+
}
|
|
330
586
|
return {
|
|
331
|
-
output: {
|
|
587
|
+
output: {
|
|
588
|
+
result: {
|
|
589
|
+
steps: snapshot?.context,
|
|
590
|
+
status: "failed",
|
|
591
|
+
// Get the original error from NonRetriableError's cause (which contains the workflow result)
|
|
592
|
+
error: error.getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
|
|
593
|
+
}
|
|
594
|
+
}
|
|
332
595
|
};
|
|
333
596
|
}
|
|
334
597
|
if (runs?.[0]?.status === "Cancelled") {
|
|
@@ -338,8 +601,9 @@ var InngestRun = class extends workflows.Run {
|
|
|
338
601
|
});
|
|
339
602
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
340
603
|
}
|
|
604
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
341
605
|
}
|
|
342
|
-
|
|
606
|
+
throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
343
607
|
}
|
|
344
608
|
async cancel() {
|
|
345
609
|
const storage = this.#mastra?.getStorage();
|
|
@@ -369,13 +633,60 @@ 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
|
+
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
644
|
+
workflowName: this.workflowId,
|
|
645
|
+
runId: this.runId,
|
|
646
|
+
resourceId: this.resourceId,
|
|
647
|
+
snapshot: {
|
|
648
|
+
runId: this.runId,
|
|
649
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
650
|
+
status: "running",
|
|
651
|
+
value: {},
|
|
652
|
+
context: {},
|
|
653
|
+
activePaths: [],
|
|
654
|
+
suspendedPaths: {},
|
|
655
|
+
activeStepsPath: {},
|
|
656
|
+
resumeLabels: {},
|
|
657
|
+
waitingPaths: {},
|
|
658
|
+
timestamp: Date.now()
|
|
659
|
+
}
|
|
660
|
+
});
|
|
661
|
+
const inputDataToUse = await this._validateInput(params.inputData);
|
|
662
|
+
const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
|
|
663
|
+
const eventOutput = await this.inngest.send({
|
|
664
|
+
name: `workflow.${this.workflowId}`,
|
|
665
|
+
data: {
|
|
666
|
+
inputData: inputDataToUse,
|
|
667
|
+
initialState: initialStateToUse,
|
|
668
|
+
runId: this.runId,
|
|
669
|
+
resourceId: this.resourceId,
|
|
670
|
+
outputOptions: params.outputOptions,
|
|
671
|
+
tracingOptions: params.tracingOptions,
|
|
672
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
673
|
+
perStep: params.perStep
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
const eventId = eventOutput.ids[0];
|
|
677
|
+
if (!eventId) {
|
|
678
|
+
throw new Error("Event ID is not set");
|
|
679
|
+
}
|
|
680
|
+
return { runId: this.runId };
|
|
681
|
+
}
|
|
372
682
|
async _start({
|
|
373
683
|
inputData,
|
|
374
684
|
initialState,
|
|
375
685
|
outputOptions,
|
|
376
686
|
tracingOptions,
|
|
377
687
|
format,
|
|
378
|
-
requestContext
|
|
688
|
+
requestContext,
|
|
689
|
+
perStep
|
|
379
690
|
}) {
|
|
380
691
|
await this.#mastra.getStorage()?.persistWorkflowSnapshot({
|
|
381
692
|
workflowName: this.workflowId,
|
|
@@ -407,7 +718,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
407
718
|
outputOptions,
|
|
408
719
|
tracingOptions,
|
|
409
720
|
format,
|
|
410
|
-
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
721
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
|
|
722
|
+
perStep
|
|
411
723
|
}
|
|
412
724
|
});
|
|
413
725
|
const eventId = eventOutput.ids[0];
|
|
@@ -416,9 +728,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
416
728
|
}
|
|
417
729
|
const runOutput = await this.getRunOutput(eventId);
|
|
418
730
|
const result = runOutput?.output?.result;
|
|
419
|
-
|
|
420
|
-
result.error = new Error(result.error);
|
|
421
|
-
}
|
|
731
|
+
this.hydrateFailedResult(result);
|
|
422
732
|
if (result.status !== "suspended") {
|
|
423
733
|
this.cleanup?.();
|
|
424
734
|
}
|
|
@@ -468,7 +778,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
468
778
|
resumePayload: resumeDataToUse,
|
|
469
779
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
470
780
|
},
|
|
471
|
-
requestContext: mergedRequestContext
|
|
781
|
+
requestContext: mergedRequestContext,
|
|
782
|
+
perStep: params.perStep
|
|
472
783
|
}
|
|
473
784
|
});
|
|
474
785
|
const eventId = eventOutput.ids[0];
|
|
@@ -477,9 +788,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
477
788
|
}
|
|
478
789
|
const runOutput = await this.getRunOutput(eventId);
|
|
479
790
|
const result = runOutput?.output?.result;
|
|
480
|
-
|
|
481
|
-
result.error = new Error(result.error);
|
|
482
|
-
}
|
|
791
|
+
this.hydrateFailedResult(result);
|
|
483
792
|
return result;
|
|
484
793
|
}
|
|
485
794
|
async timeTravel(params) {
|
|
@@ -560,7 +869,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
560
869
|
timeTravel: timeTravelData,
|
|
561
870
|
tracingOptions: params.tracingOptions,
|
|
562
871
|
outputOptions: params.outputOptions,
|
|
563
|
-
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
872
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
873
|
+
perStep: params.perStep
|
|
564
874
|
}
|
|
565
875
|
});
|
|
566
876
|
const eventId = eventOutput.ids[0];
|
|
@@ -569,9 +879,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
569
879
|
}
|
|
570
880
|
const runOutput = await this.getRunOutput(eventId);
|
|
571
881
|
const result = runOutput?.output?.result;
|
|
572
|
-
|
|
573
|
-
result.error = new Error(result.error);
|
|
574
|
-
}
|
|
882
|
+
this.hydrateFailedResult(result);
|
|
575
883
|
return result;
|
|
576
884
|
}
|
|
577
885
|
watch(cb) {
|
|
@@ -653,7 +961,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
653
961
|
tracingOptions,
|
|
654
962
|
closeOnSuspend = true,
|
|
655
963
|
initialState,
|
|
656
|
-
outputOptions
|
|
964
|
+
outputOptions,
|
|
965
|
+
perStep
|
|
657
966
|
} = {}) {
|
|
658
967
|
if (this.closeStreamAction && this.streamOutput) {
|
|
659
968
|
return this.streamOutput;
|
|
@@ -689,7 +998,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
689
998
|
initialState,
|
|
690
999
|
tracingOptions,
|
|
691
1000
|
outputOptions,
|
|
692
|
-
format: "vnext"
|
|
1001
|
+
format: "vnext",
|
|
1002
|
+
perStep
|
|
693
1003
|
});
|
|
694
1004
|
let executionResults;
|
|
695
1005
|
try {
|
|
@@ -732,7 +1042,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
732
1042
|
nestedStepsContext,
|
|
733
1043
|
requestContext,
|
|
734
1044
|
tracingOptions,
|
|
735
|
-
outputOptions
|
|
1045
|
+
outputOptions,
|
|
1046
|
+
perStep
|
|
736
1047
|
}) {
|
|
737
1048
|
this.closeStreamAction = async () => {
|
|
738
1049
|
};
|
|
@@ -767,7 +1078,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
767
1078
|
initialState,
|
|
768
1079
|
requestContext,
|
|
769
1080
|
tracingOptions,
|
|
770
|
-
outputOptions
|
|
1081
|
+
outputOptions,
|
|
1082
|
+
perStep
|
|
771
1083
|
});
|
|
772
1084
|
self.executionResults = executionResultsPromise;
|
|
773
1085
|
let executionResults;
|
|
@@ -792,6 +1104,18 @@ var InngestRun = class extends workflows.Run {
|
|
|
792
1104
|
});
|
|
793
1105
|
return this.streamOutput;
|
|
794
1106
|
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Hydrates errors in a failed workflow result back to proper Error instances.
|
|
1109
|
+
* This ensures error.cause chains and custom properties are preserved.
|
|
1110
|
+
*/
|
|
1111
|
+
hydrateFailedResult(result) {
|
|
1112
|
+
if (result.status === "failed") {
|
|
1113
|
+
result.error = error.getErrorFromUnknown(result.error, { serializeStack: false });
|
|
1114
|
+
if (result.steps) {
|
|
1115
|
+
workflows.hydrateSerializedStepErrors(result.steps);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
795
1119
|
};
|
|
796
1120
|
|
|
797
1121
|
// src/workflow.ts
|
|
@@ -829,6 +1153,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
829
1153
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
830
1154
|
}
|
|
831
1155
|
__registerMastra(mastra) {
|
|
1156
|
+
super.__registerMastra(mastra);
|
|
832
1157
|
this.#mastra = mastra;
|
|
833
1158
|
this.executionEngine.__registerMastra(mastra);
|
|
834
1159
|
const updateNested = (step) => {
|
|
@@ -847,7 +1172,7 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
847
1172
|
}
|
|
848
1173
|
}
|
|
849
1174
|
async createRun(options) {
|
|
850
|
-
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
1175
|
+
const runIdToUse = options?.runId || crypto$1.randomUUID();
|
|
851
1176
|
const run = this.runs.get(runIdToUse) ?? new InngestRun(
|
|
852
1177
|
{
|
|
853
1178
|
workflowId: this.id,
|
|
@@ -870,7 +1195,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
870
1195
|
workflowStatus: run.workflowRunStatus,
|
|
871
1196
|
stepResults: {}
|
|
872
1197
|
});
|
|
873
|
-
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse,
|
|
1198
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
|
|
1199
|
+
withNestedWorkflows: false
|
|
1200
|
+
});
|
|
874
1201
|
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
875
1202
|
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
876
1203
|
workflowName: this.id,
|
|
@@ -909,34 +1236,13 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
909
1236
|
},
|
|
910
1237
|
{ event: `workflow.${this.id}` },
|
|
911
1238
|
async ({ event, step, attempt, publish }) => {
|
|
912
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
1239
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
|
|
913
1240
|
if (!runId) {
|
|
914
1241
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
915
|
-
return crypto.randomUUID();
|
|
1242
|
+
return crypto$1.randomUUID();
|
|
916
1243
|
});
|
|
917
1244
|
}
|
|
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
|
-
};
|
|
1245
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
940
1246
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
941
1247
|
const result = await engine.execute({
|
|
942
1248
|
workflowId: this.id,
|
|
@@ -946,21 +1252,32 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
946
1252
|
serializedStepGraph: this.serializedStepGraph,
|
|
947
1253
|
input: inputData,
|
|
948
1254
|
initialState,
|
|
949
|
-
|
|
1255
|
+
pubsub,
|
|
950
1256
|
retryConfig: this.retryConfig,
|
|
951
1257
|
requestContext: new di.RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
952
1258
|
resume,
|
|
953
1259
|
timeTravel,
|
|
1260
|
+
perStep,
|
|
954
1261
|
format,
|
|
955
1262
|
abortController: new AbortController(),
|
|
956
1263
|
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
957
1264
|
outputOptions,
|
|
958
1265
|
outputWriter: async (chunk) => {
|
|
959
|
-
|
|
960
|
-
|
|
1266
|
+
try {
|
|
1267
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1268
|
+
type: "watch",
|
|
1269
|
+
runId,
|
|
1270
|
+
data: chunk
|
|
1271
|
+
});
|
|
1272
|
+
} catch (err) {
|
|
1273
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
1274
|
+
}
|
|
961
1275
|
}
|
|
962
1276
|
});
|
|
963
1277
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1278
|
+
if (result.status !== "paused") {
|
|
1279
|
+
await engine.invokeLifecycleCallbacksInternal(result);
|
|
1280
|
+
}
|
|
964
1281
|
if (result.status === "failed") {
|
|
965
1282
|
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
966
1283
|
cause: result
|
|
@@ -1045,7 +1362,8 @@ function createStep(params, agentOptions) {
|
|
|
1045
1362
|
outputSchema,
|
|
1046
1363
|
execute: async ({
|
|
1047
1364
|
inputData,
|
|
1048
|
-
|
|
1365
|
+
runId,
|
|
1366
|
+
[_constants.PUBSUB_SYMBOL]: pubsub,
|
|
1049
1367
|
[_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
1050
1368
|
requestContext,
|
|
1051
1369
|
tracingContext,
|
|
@@ -1100,22 +1418,24 @@ function createStep(params, agentOptions) {
|
|
|
1100
1418
|
stream = modelOutput.fullStream;
|
|
1101
1419
|
}
|
|
1102
1420
|
if (streamFormat === "legacy") {
|
|
1103
|
-
await
|
|
1104
|
-
type: "
|
|
1105
|
-
|
|
1421
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1422
|
+
type: "watch",
|
|
1423
|
+
runId,
|
|
1424
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
1106
1425
|
});
|
|
1107
1426
|
for await (const chunk of stream) {
|
|
1108
1427
|
if (chunk.type === "text-delta") {
|
|
1109
|
-
await
|
|
1110
|
-
type: "
|
|
1111
|
-
|
|
1112
|
-
argsTextDelta: chunk.textDelta
|
|
1428
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1429
|
+
type: "watch",
|
|
1430
|
+
runId,
|
|
1431
|
+
data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
|
|
1113
1432
|
});
|
|
1114
1433
|
}
|
|
1115
1434
|
}
|
|
1116
|
-
await
|
|
1117
|
-
type: "
|
|
1118
|
-
|
|
1435
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1436
|
+
type: "watch",
|
|
1437
|
+
runId,
|
|
1438
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
1119
1439
|
});
|
|
1120
1440
|
} else {
|
|
1121
1441
|
for await (const chunk of stream) {
|
|
@@ -1228,6 +1548,7 @@ function init(inngest) {
|
|
|
1228
1548
|
}
|
|
1229
1549
|
|
|
1230
1550
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
1551
|
+
exports.InngestPubSub = InngestPubSub;
|
|
1231
1552
|
exports.InngestRun = InngestRun;
|
|
1232
1553
|
exports.InngestWorkflow = InngestWorkflow;
|
|
1233
1554
|
exports._compatibilityCheck = _compatibilityCheck;
|