@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.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { Agent } from '@mastra/core/agent';
|
|
1
2
|
import { Tool } from '@mastra/core/tools';
|
|
2
|
-
import { DefaultExecutionEngine, createTimeTravelExecutionParams, Run, Workflow } from '@mastra/core/workflows';
|
|
3
|
-
import {
|
|
3
|
+
import { DefaultExecutionEngine, createTimeTravelExecutionParams, Run, hydrateSerializedStepErrors, Workflow } from '@mastra/core/workflows';
|
|
4
|
+
import { PUBSUB_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import { randomUUID } from 'crypto';
|
|
6
|
-
import { ReadableStream, WritableStream } from 'stream/web';
|
|
7
7
|
import { RequestContext } from '@mastra/core/di';
|
|
8
|
-
import {
|
|
8
|
+
import { NonRetriableError } from 'inngest';
|
|
9
|
+
import { getErrorFromUnknown } from '@mastra/core/error';
|
|
9
10
|
import { subscribe } from '@inngest/realtime';
|
|
11
|
+
import { PubSub } from '@mastra/core/events';
|
|
12
|
+
import { ReadableStream } from 'stream/web';
|
|
10
13
|
import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
|
|
11
14
|
import { serve as serve$1 } from 'inngest/hono';
|
|
12
15
|
|
|
@@ -23,17 +26,18 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
23
26
|
// Hook Overrides
|
|
24
27
|
// =============================================================================
|
|
25
28
|
/**
|
|
26
|
-
* Format errors
|
|
29
|
+
* Format errors while preserving Error instances and their custom properties.
|
|
30
|
+
* Uses getErrorFromUnknown to ensure all error properties are preserved.
|
|
27
31
|
*/
|
|
28
32
|
formatResultError(error, lastOutput) {
|
|
29
|
-
if (error instanceof Error) {
|
|
30
|
-
return error.stack ?? error.message;
|
|
31
|
-
}
|
|
32
33
|
const outputError = lastOutput?.error;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
const errorSource = error || outputError;
|
|
35
|
+
const errorInstance = getErrorFromUnknown(errorSource, {
|
|
36
|
+
serializeStack: true,
|
|
37
|
+
// Include stack in JSON for better debugging in Inngest
|
|
38
|
+
fallbackMessage: "Unknown workflow error"
|
|
39
|
+
});
|
|
40
|
+
return errorInstance.toJSON();
|
|
37
41
|
}
|
|
38
42
|
/**
|
|
39
43
|
* Detect InngestWorkflow instances for special nested workflow handling
|
|
@@ -55,32 +59,46 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
55
59
|
* After retries exhausted, error propagates here and we return a failed result.
|
|
56
60
|
*/
|
|
57
61
|
async executeStepWithRetry(stepId, runStep, params) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} catch (e) {
|
|
62
|
-
const cause = e?.cause;
|
|
63
|
-
if (cause?.status === "failed") {
|
|
64
|
-
params.stepSpan?.error({
|
|
65
|
-
error: e,
|
|
66
|
-
attributes: { status: "failed" }
|
|
67
|
-
});
|
|
68
|
-
return { ok: false, error: cause };
|
|
62
|
+
for (let i = 0; i < params.retries + 1; i++) {
|
|
63
|
+
if (i > 0 && params.delay) {
|
|
64
|
+
await new Promise((resolve) => setTimeout(resolve, params.delay));
|
|
69
65
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
try {
|
|
67
|
+
const result = await this.wrapDurableOperation(stepId, runStep);
|
|
68
|
+
return { ok: true, result };
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (i === params.retries) {
|
|
71
|
+
const cause = e?.cause;
|
|
72
|
+
if (cause?.status === "failed") {
|
|
73
|
+
params.stepSpan?.error({
|
|
74
|
+
error: e,
|
|
75
|
+
attributes: { status: "failed" }
|
|
76
|
+
});
|
|
77
|
+
if (cause.error && !(cause.error instanceof Error)) {
|
|
78
|
+
cause.error = getErrorFromUnknown(cause.error, { serializeStack: false });
|
|
79
|
+
}
|
|
80
|
+
return { ok: false, error: cause };
|
|
81
|
+
}
|
|
82
|
+
const errorInstance = getErrorFromUnknown(e, {
|
|
83
|
+
serializeStack: false,
|
|
84
|
+
fallbackMessage: "Unknown step execution error"
|
|
85
|
+
});
|
|
86
|
+
params.stepSpan?.error({
|
|
87
|
+
error: errorInstance,
|
|
88
|
+
attributes: { status: "failed" }
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
ok: false,
|
|
92
|
+
error: {
|
|
93
|
+
status: "failed",
|
|
94
|
+
error: errorInstance,
|
|
95
|
+
endedAt: Date.now()
|
|
96
|
+
}
|
|
97
|
+
};
|
|
81
98
|
}
|
|
82
|
-
}
|
|
99
|
+
}
|
|
83
100
|
}
|
|
101
|
+
return { ok: false, error: { status: "failed", error: new Error("Unknown error"), endedAt: Date.now() } };
|
|
84
102
|
}
|
|
85
103
|
/**
|
|
86
104
|
* Use Inngest's sleep primitive for durability
|
|
@@ -99,21 +117,11 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
99
117
|
* If retryConfig is provided, throws RetryAfterError INSIDE step.run() to trigger
|
|
100
118
|
* Inngest's step-level retry mechanism (not function-level retry).
|
|
101
119
|
*/
|
|
102
|
-
async wrapDurableOperation(operationId, operationFn
|
|
120
|
+
async wrapDurableOperation(operationId, operationFn) {
|
|
103
121
|
return this.inngestStep.run(operationId, async () => {
|
|
104
122
|
try {
|
|
105
123
|
return await operationFn();
|
|
106
124
|
} catch (e) {
|
|
107
|
-
if (retryConfig) {
|
|
108
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
109
|
-
throw new RetryAfterError(errorMessage, retryConfig.delay, {
|
|
110
|
-
cause: {
|
|
111
|
-
status: "failed",
|
|
112
|
-
error: `Error: ${errorMessage}`,
|
|
113
|
-
endedAt: Date.now()
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
125
|
throw e;
|
|
118
126
|
}
|
|
119
127
|
});
|
|
@@ -124,6 +132,18 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
124
132
|
getEngineContext() {
|
|
125
133
|
return { step: this.inngestStep };
|
|
126
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* For Inngest, lifecycle callbacks are invoked in the workflow's finalize step
|
|
137
|
+
* (wrapped in step.run for durability), not in execute(). Override to skip.
|
|
138
|
+
*/
|
|
139
|
+
async invokeLifecycleCallbacks(_result) {
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Actually invoke the lifecycle callbacks. Called from workflow.ts finalize step.
|
|
143
|
+
*/
|
|
144
|
+
async invokeLifecycleCallbacksInternal(result) {
|
|
145
|
+
return super.invokeLifecycleCallbacks(result);
|
|
146
|
+
}
|
|
127
147
|
/**
|
|
128
148
|
* Execute nested InngestWorkflow using inngestStep.invoke() for durability.
|
|
129
149
|
* This MUST be called directly (not inside step.run()) due to Inngest constraints.
|
|
@@ -132,7 +152,18 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
132
152
|
if (!(params.step instanceof InngestWorkflow)) {
|
|
133
153
|
return null;
|
|
134
154
|
}
|
|
135
|
-
const {
|
|
155
|
+
const {
|
|
156
|
+
step,
|
|
157
|
+
stepResults,
|
|
158
|
+
executionContext,
|
|
159
|
+
resume,
|
|
160
|
+
timeTravel,
|
|
161
|
+
prevOutput,
|
|
162
|
+
inputData,
|
|
163
|
+
pubsub,
|
|
164
|
+
startedAt,
|
|
165
|
+
perStep
|
|
166
|
+
} = params;
|
|
136
167
|
const isResume = !!resume?.steps?.length;
|
|
137
168
|
let result;
|
|
138
169
|
let runId;
|
|
@@ -140,7 +171,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
140
171
|
try {
|
|
141
172
|
if (isResume) {
|
|
142
173
|
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? randomUUID();
|
|
143
|
-
const
|
|
174
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
175
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
144
176
|
workflowName: step.id,
|
|
145
177
|
runId
|
|
146
178
|
});
|
|
@@ -157,14 +189,16 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
157
189
|
resumePayload: resume.resumePayload,
|
|
158
190
|
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
159
191
|
},
|
|
160
|
-
outputOptions: { includeState: true }
|
|
192
|
+
outputOptions: { includeState: true },
|
|
193
|
+
perStep
|
|
161
194
|
}
|
|
162
195
|
});
|
|
163
196
|
result = invokeResp.result;
|
|
164
197
|
runId = invokeResp.runId;
|
|
165
198
|
executionContext.state = invokeResp.result.state;
|
|
166
199
|
} else if (isTimeTravel) {
|
|
167
|
-
const
|
|
200
|
+
const workflowsStoreForTimeTravel = await this.mastra?.getStorage()?.getStore("workflows");
|
|
201
|
+
const snapshot = await workflowsStoreForTimeTravel?.loadWorkflowSnapshot({
|
|
168
202
|
workflowName: step.id,
|
|
169
203
|
runId: executionContext.runId
|
|
170
204
|
}) ?? { context: {} };
|
|
@@ -183,7 +217,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
183
217
|
timeTravel: timeTravelParams,
|
|
184
218
|
initialState: executionContext.state ?? {},
|
|
185
219
|
runId: executionContext.runId,
|
|
186
|
-
outputOptions: { includeState: true }
|
|
220
|
+
outputOptions: { includeState: true },
|
|
221
|
+
perStep
|
|
187
222
|
}
|
|
188
223
|
});
|
|
189
224
|
result = invokeResp.result;
|
|
@@ -195,7 +230,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
195
230
|
data: {
|
|
196
231
|
inputData,
|
|
197
232
|
initialState: executionContext.state ?? {},
|
|
198
|
-
outputOptions: { includeState: true }
|
|
233
|
+
outputOptions: { includeState: true },
|
|
234
|
+
perStep
|
|
199
235
|
}
|
|
200
236
|
});
|
|
201
237
|
result = invokeResp.result;
|
|
@@ -221,16 +257,20 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
221
257
|
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
222
258
|
async () => {
|
|
223
259
|
if (result.status === "failed") {
|
|
224
|
-
await
|
|
225
|
-
type: "
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
260
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
261
|
+
type: "watch",
|
|
262
|
+
runId: executionContext.runId,
|
|
263
|
+
data: {
|
|
264
|
+
type: "workflow-step-result",
|
|
265
|
+
payload: {
|
|
266
|
+
id: step.id,
|
|
267
|
+
status: "failed",
|
|
268
|
+
error: result?.error,
|
|
269
|
+
payload: prevOutput
|
|
270
|
+
}
|
|
231
271
|
}
|
|
232
272
|
});
|
|
233
|
-
return { executionContext, result: { status: "failed", error: result?.error } };
|
|
273
|
+
return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
|
|
234
274
|
} else if (result.status === "suspended") {
|
|
235
275
|
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
236
276
|
const stepRes = stepResult;
|
|
@@ -239,17 +279,22 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
239
279
|
for (const [stepName, stepResult] of suspendedSteps) {
|
|
240
280
|
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
241
281
|
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
242
|
-
await
|
|
243
|
-
type: "
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
282
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
283
|
+
type: "watch",
|
|
284
|
+
runId: executionContext.runId,
|
|
285
|
+
data: {
|
|
286
|
+
type: "workflow-step-suspended",
|
|
287
|
+
payload: {
|
|
288
|
+
id: step.id,
|
|
289
|
+
status: "suspended"
|
|
290
|
+
}
|
|
247
291
|
}
|
|
248
292
|
});
|
|
249
293
|
return {
|
|
250
294
|
executionContext,
|
|
251
295
|
result: {
|
|
252
296
|
status: "suspended",
|
|
297
|
+
suspendedAt: Date.now(),
|
|
253
298
|
payload: stepResult.payload,
|
|
254
299
|
suspendPayload: {
|
|
255
300
|
...stepResult?.suspendPayload,
|
|
@@ -262,59 +307,205 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
|
|
|
262
307
|
executionContext,
|
|
263
308
|
result: {
|
|
264
309
|
status: "suspended",
|
|
310
|
+
suspendedAt: Date.now(),
|
|
265
311
|
payload: {}
|
|
266
312
|
}
|
|
267
313
|
};
|
|
268
314
|
} else if (result.status === "tripwire") {
|
|
269
|
-
await
|
|
270
|
-
type: "
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
315
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
316
|
+
type: "watch",
|
|
317
|
+
runId: executionContext.runId,
|
|
318
|
+
data: {
|
|
319
|
+
type: "workflow-step-result",
|
|
320
|
+
payload: {
|
|
321
|
+
id: step.id,
|
|
322
|
+
status: "tripwire",
|
|
323
|
+
error: result?.tripwire?.reason,
|
|
324
|
+
payload: prevOutput
|
|
325
|
+
}
|
|
276
326
|
}
|
|
277
327
|
});
|
|
278
328
|
return {
|
|
279
329
|
executionContext,
|
|
280
330
|
result: {
|
|
281
331
|
status: "tripwire",
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
metadata: result?.metadata,
|
|
285
|
-
processorId: result?.processorId
|
|
332
|
+
tripwire: result?.tripwire,
|
|
333
|
+
endedAt: Date.now()
|
|
286
334
|
}
|
|
287
335
|
};
|
|
336
|
+
} else if (perStep || result.status === "paused") {
|
|
337
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
338
|
+
type: "watch",
|
|
339
|
+
runId: executionContext.runId,
|
|
340
|
+
data: {
|
|
341
|
+
type: "workflow-step-result",
|
|
342
|
+
payload: {
|
|
343
|
+
id: step.id,
|
|
344
|
+
status: "paused"
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
349
|
+
type: "watch",
|
|
350
|
+
runId: executionContext.runId,
|
|
351
|
+
data: {
|
|
352
|
+
type: "workflow-step-finish",
|
|
353
|
+
payload: {
|
|
354
|
+
id: step.id,
|
|
355
|
+
metadata: {}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
return { executionContext, result: { status: "paused" } };
|
|
288
360
|
}
|
|
289
|
-
await
|
|
290
|
-
type: "
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
361
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
362
|
+
type: "watch",
|
|
363
|
+
runId: executionContext.runId,
|
|
364
|
+
data: {
|
|
365
|
+
type: "workflow-step-result",
|
|
366
|
+
payload: {
|
|
367
|
+
id: step.id,
|
|
368
|
+
status: "success",
|
|
369
|
+
output: result?.result
|
|
370
|
+
}
|
|
295
371
|
}
|
|
296
372
|
});
|
|
297
|
-
await
|
|
298
|
-
type: "
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
373
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
374
|
+
type: "watch",
|
|
375
|
+
runId: executionContext.runId,
|
|
376
|
+
data: {
|
|
377
|
+
type: "workflow-step-finish",
|
|
378
|
+
payload: {
|
|
379
|
+
id: step.id,
|
|
380
|
+
metadata: {}
|
|
381
|
+
}
|
|
302
382
|
}
|
|
303
383
|
});
|
|
304
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
384
|
+
return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
|
|
305
385
|
}
|
|
306
386
|
);
|
|
307
387
|
Object.assign(executionContext, res.executionContext);
|
|
308
388
|
return {
|
|
309
389
|
...res.result,
|
|
310
390
|
startedAt,
|
|
311
|
-
endedAt: Date.now(),
|
|
312
391
|
payload: inputData,
|
|
313
392
|
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
314
393
|
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
315
394
|
};
|
|
316
395
|
}
|
|
317
396
|
};
|
|
397
|
+
var InngestPubSub = class extends PubSub {
|
|
398
|
+
inngest;
|
|
399
|
+
workflowId;
|
|
400
|
+
publishFn;
|
|
401
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
402
|
+
constructor(inngest, workflowId, publishFn) {
|
|
403
|
+
super();
|
|
404
|
+
this.inngest = inngest;
|
|
405
|
+
this.workflowId = workflowId;
|
|
406
|
+
this.publishFn = publishFn;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Publish an event to Inngest's realtime system.
|
|
410
|
+
*
|
|
411
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
412
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
413
|
+
*/
|
|
414
|
+
async publish(topic, event) {
|
|
415
|
+
if (!this.publishFn) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
419
|
+
if (!match) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const runId = match[1];
|
|
423
|
+
try {
|
|
424
|
+
await this.publishFn({
|
|
425
|
+
channel: `workflow:${this.workflowId}:${runId}`,
|
|
426
|
+
topic: "watch",
|
|
427
|
+
data: event.data
|
|
428
|
+
});
|
|
429
|
+
} catch (err) {
|
|
430
|
+
console.error("InngestPubSub publish error:", err?.message ?? err);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Subscribe to events from Inngest's realtime system.
|
|
435
|
+
*
|
|
436
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
437
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
438
|
+
*/
|
|
439
|
+
async subscribe(topic, cb) {
|
|
440
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
441
|
+
if (!match || !match[1]) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const runId = match[1];
|
|
445
|
+
if (this.subscriptions.has(topic)) {
|
|
446
|
+
this.subscriptions.get(topic).callbacks.add(cb);
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const callbacks = /* @__PURE__ */ new Set([cb]);
|
|
450
|
+
const channel = `workflow:${this.workflowId}:${runId}`;
|
|
451
|
+
const streamPromise = subscribe(
|
|
452
|
+
{
|
|
453
|
+
channel,
|
|
454
|
+
topics: ["watch"],
|
|
455
|
+
app: this.inngest
|
|
456
|
+
},
|
|
457
|
+
(message) => {
|
|
458
|
+
const event = {
|
|
459
|
+
id: crypto.randomUUID(),
|
|
460
|
+
type: "watch",
|
|
461
|
+
runId,
|
|
462
|
+
data: message.data,
|
|
463
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
464
|
+
};
|
|
465
|
+
for (const callback of callbacks) {
|
|
466
|
+
callback(event);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
);
|
|
470
|
+
this.subscriptions.set(topic, {
|
|
471
|
+
unsubscribe: () => {
|
|
472
|
+
streamPromise.then((stream) => stream.cancel()).catch((err) => {
|
|
473
|
+
console.error("InngestPubSub unsubscribe error:", err);
|
|
474
|
+
});
|
|
475
|
+
},
|
|
476
|
+
callbacks
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Unsubscribe a callback from a topic.
|
|
481
|
+
* If no callbacks remain, the underlying Inngest subscription is cancelled.
|
|
482
|
+
*/
|
|
483
|
+
async unsubscribe(topic, cb) {
|
|
484
|
+
const sub = this.subscriptions.get(topic);
|
|
485
|
+
if (!sub) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
sub.callbacks.delete(cb);
|
|
489
|
+
if (sub.callbacks.size === 0) {
|
|
490
|
+
sub.unsubscribe();
|
|
491
|
+
this.subscriptions.delete(topic);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Flush any pending operations. No-op for Inngest.
|
|
496
|
+
*/
|
|
497
|
+
async flush() {
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Clean up all subscriptions during graceful shutdown.
|
|
501
|
+
*/
|
|
502
|
+
async close() {
|
|
503
|
+
for (const [, sub] of this.subscriptions) {
|
|
504
|
+
sub.unsubscribe();
|
|
505
|
+
}
|
|
506
|
+
this.subscriptions.clear();
|
|
507
|
+
}
|
|
508
|
+
};
|
|
318
509
|
var InngestRun = class extends Run {
|
|
319
510
|
inngest;
|
|
320
511
|
serializedStepGraph;
|
|
@@ -326,38 +517,90 @@ var InngestRun = class extends Run {
|
|
|
326
517
|
this.#mastra = params.mastra;
|
|
327
518
|
}
|
|
328
519
|
async getRuns(eventId) {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
520
|
+
const maxRetries = 3;
|
|
521
|
+
let lastError = null;
|
|
522
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
523
|
+
try {
|
|
524
|
+
const response = await fetch(
|
|
525
|
+
`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
|
|
526
|
+
{
|
|
527
|
+
headers: {
|
|
528
|
+
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
);
|
|
532
|
+
if (response.status === 429) {
|
|
533
|
+
const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
|
|
534
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
if (!response.ok) {
|
|
538
|
+
throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
|
|
539
|
+
}
|
|
540
|
+
const text = await response.text();
|
|
541
|
+
if (!text) {
|
|
542
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
const json = JSON.parse(text);
|
|
546
|
+
return json.data;
|
|
547
|
+
} catch (error) {
|
|
548
|
+
lastError = error;
|
|
549
|
+
if (attempt < maxRetries - 1) {
|
|
550
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
|
551
|
+
}
|
|
332
552
|
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return json.data;
|
|
553
|
+
}
|
|
554
|
+
throw new NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
336
555
|
}
|
|
337
|
-
async getRunOutput(eventId) {
|
|
338
|
-
|
|
556
|
+
async getRunOutput(eventId, maxWaitMs = 3e5) {
|
|
557
|
+
const startTime = Date.now();
|
|
339
558
|
const storage = this.#mastra?.getStorage();
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
runs
|
|
559
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
560
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
561
|
+
let runs;
|
|
562
|
+
try {
|
|
563
|
+
runs = await this.getRuns(eventId);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
if (error instanceof NonRetriableError) {
|
|
566
|
+
throw error;
|
|
567
|
+
}
|
|
568
|
+
throw new NonRetriableError(
|
|
569
|
+
`Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
|
|
573
|
+
return runs[0];
|
|
574
|
+
}
|
|
343
575
|
if (runs?.[0]?.status === "Failed") {
|
|
344
|
-
const snapshot = await
|
|
576
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
345
577
|
workflowName: this.workflowId,
|
|
346
578
|
runId: this.runId
|
|
347
579
|
});
|
|
580
|
+
if (snapshot?.context) {
|
|
581
|
+
snapshot.context = hydrateSerializedStepErrors(snapshot.context);
|
|
582
|
+
}
|
|
348
583
|
return {
|
|
349
|
-
output: {
|
|
584
|
+
output: {
|
|
585
|
+
result: {
|
|
586
|
+
steps: snapshot?.context,
|
|
587
|
+
status: "failed",
|
|
588
|
+
// Get the original error from NonRetriableError's cause (which contains the workflow result)
|
|
589
|
+
error: getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
|
|
590
|
+
}
|
|
591
|
+
}
|
|
350
592
|
};
|
|
351
593
|
}
|
|
352
594
|
if (runs?.[0]?.status === "Cancelled") {
|
|
353
|
-
const snapshot = await
|
|
595
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
354
596
|
workflowName: this.workflowId,
|
|
355
597
|
runId: this.runId
|
|
356
598
|
});
|
|
357
599
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
358
600
|
}
|
|
601
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
359
602
|
}
|
|
360
|
-
|
|
603
|
+
throw new NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
361
604
|
}
|
|
362
605
|
async cancel() {
|
|
363
606
|
const storage = this.#mastra?.getStorage();
|
|
@@ -367,12 +610,13 @@ var InngestRun = class extends Run {
|
|
|
367
610
|
runId: this.runId
|
|
368
611
|
}
|
|
369
612
|
});
|
|
370
|
-
const
|
|
613
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
614
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
371
615
|
workflowName: this.workflowId,
|
|
372
616
|
runId: this.runId
|
|
373
617
|
});
|
|
374
618
|
if (snapshot) {
|
|
375
|
-
await
|
|
619
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
376
620
|
workflowName: this.workflowId,
|
|
377
621
|
runId: this.runId,
|
|
378
622
|
resourceId: this.resourceId,
|
|
@@ -387,15 +631,64 @@ var InngestRun = class extends Run {
|
|
|
387
631
|
async start(params) {
|
|
388
632
|
return this._start(params);
|
|
389
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Starts the workflow execution without waiting for completion (fire-and-forget).
|
|
636
|
+
* Returns immediately with the runId after sending the event to Inngest.
|
|
637
|
+
* The workflow executes independently in Inngest.
|
|
638
|
+
* Use this when you don't need to wait for the result or want to avoid polling failures.
|
|
639
|
+
*/
|
|
640
|
+
async startAsync(params) {
|
|
641
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
642
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
643
|
+
workflowName: this.workflowId,
|
|
644
|
+
runId: this.runId,
|
|
645
|
+
resourceId: this.resourceId,
|
|
646
|
+
snapshot: {
|
|
647
|
+
runId: this.runId,
|
|
648
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
649
|
+
status: "running",
|
|
650
|
+
value: {},
|
|
651
|
+
context: {},
|
|
652
|
+
activePaths: [],
|
|
653
|
+
suspendedPaths: {},
|
|
654
|
+
activeStepsPath: {},
|
|
655
|
+
resumeLabels: {},
|
|
656
|
+
waitingPaths: {},
|
|
657
|
+
timestamp: Date.now()
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
const inputDataToUse = await this._validateInput(params.inputData);
|
|
661
|
+
const initialStateToUse = await this._validateInitialState(params.initialState ?? {});
|
|
662
|
+
const eventOutput = await this.inngest.send({
|
|
663
|
+
name: `workflow.${this.workflowId}`,
|
|
664
|
+
data: {
|
|
665
|
+
inputData: inputDataToUse,
|
|
666
|
+
initialState: initialStateToUse,
|
|
667
|
+
runId: this.runId,
|
|
668
|
+
resourceId: this.resourceId,
|
|
669
|
+
outputOptions: params.outputOptions,
|
|
670
|
+
tracingOptions: params.tracingOptions,
|
|
671
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
672
|
+
perStep: params.perStep
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
const eventId = eventOutput.ids[0];
|
|
676
|
+
if (!eventId) {
|
|
677
|
+
throw new Error("Event ID is not set");
|
|
678
|
+
}
|
|
679
|
+
return { runId: this.runId };
|
|
680
|
+
}
|
|
390
681
|
async _start({
|
|
391
682
|
inputData,
|
|
392
683
|
initialState,
|
|
393
684
|
outputOptions,
|
|
394
685
|
tracingOptions,
|
|
395
686
|
format,
|
|
396
|
-
requestContext
|
|
687
|
+
requestContext,
|
|
688
|
+
perStep
|
|
397
689
|
}) {
|
|
398
|
-
await this.#mastra.getStorage()?.
|
|
690
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
691
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
399
692
|
workflowName: this.workflowId,
|
|
400
693
|
runId: this.runId,
|
|
401
694
|
resourceId: this.resourceId,
|
|
@@ -425,7 +718,8 @@ var InngestRun = class extends Run {
|
|
|
425
718
|
outputOptions,
|
|
426
719
|
tracingOptions,
|
|
427
720
|
format,
|
|
428
|
-
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {}
|
|
721
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
|
|
722
|
+
perStep
|
|
429
723
|
}
|
|
430
724
|
});
|
|
431
725
|
const eventId = eventOutput.ids[0];
|
|
@@ -434,9 +728,7 @@ var InngestRun = class extends Run {
|
|
|
434
728
|
}
|
|
435
729
|
const runOutput = await this.getRunOutput(eventId);
|
|
436
730
|
const result = runOutput?.output?.result;
|
|
437
|
-
|
|
438
|
-
result.error = new Error(result.error);
|
|
439
|
-
}
|
|
731
|
+
this.hydrateFailedResult(result);
|
|
440
732
|
if (result.status !== "suspended") {
|
|
441
733
|
this.cleanup?.();
|
|
442
734
|
}
|
|
@@ -463,7 +755,8 @@ var InngestRun = class extends Run {
|
|
|
463
755
|
(step) => typeof step === "string" ? step : step?.id
|
|
464
756
|
);
|
|
465
757
|
}
|
|
466
|
-
const
|
|
758
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
759
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
467
760
|
workflowName: this.workflowId,
|
|
468
761
|
runId: this.runId
|
|
469
762
|
});
|
|
@@ -486,7 +779,8 @@ var InngestRun = class extends Run {
|
|
|
486
779
|
resumePayload: resumeDataToUse,
|
|
487
780
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
488
781
|
},
|
|
489
|
-
requestContext: mergedRequestContext
|
|
782
|
+
requestContext: mergedRequestContext,
|
|
783
|
+
perStep: params.perStep
|
|
490
784
|
}
|
|
491
785
|
});
|
|
492
786
|
const eventId = eventOutput.ids[0];
|
|
@@ -495,9 +789,7 @@ var InngestRun = class extends Run {
|
|
|
495
789
|
}
|
|
496
790
|
const runOutput = await this.getRunOutput(eventId);
|
|
497
791
|
const result = runOutput?.output?.result;
|
|
498
|
-
|
|
499
|
-
result.error = new Error(result.error);
|
|
500
|
-
}
|
|
792
|
+
this.hydrateFailedResult(result);
|
|
501
793
|
return result;
|
|
502
794
|
}
|
|
503
795
|
async timeTravel(params) {
|
|
@@ -527,12 +819,13 @@ var InngestRun = class extends Run {
|
|
|
527
819
|
throw new Error("No steps provided to timeTravel");
|
|
528
820
|
}
|
|
529
821
|
const storage = this.#mastra?.getStorage();
|
|
530
|
-
const
|
|
822
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
823
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
531
824
|
workflowName: this.workflowId,
|
|
532
825
|
runId: this.runId
|
|
533
826
|
});
|
|
534
827
|
if (!snapshot) {
|
|
535
|
-
await
|
|
828
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
536
829
|
workflowName: this.workflowId,
|
|
537
830
|
runId: this.runId,
|
|
538
831
|
resourceId: this.resourceId,
|
|
@@ -566,7 +859,8 @@ var InngestRun = class extends Run {
|
|
|
566
859
|
nestedStepsContext: params.nestedStepsContext,
|
|
567
860
|
snapshot: snapshot ?? { context: {} },
|
|
568
861
|
graph: this.executionGraph,
|
|
569
|
-
initialState: params.initialState
|
|
862
|
+
initialState: params.initialState,
|
|
863
|
+
perStep: params.perStep
|
|
570
864
|
});
|
|
571
865
|
const eventOutput = await this.inngest.send({
|
|
572
866
|
name: `workflow.${this.workflowId}`,
|
|
@@ -578,7 +872,8 @@ var InngestRun = class extends Run {
|
|
|
578
872
|
timeTravel: timeTravelData,
|
|
579
873
|
tracingOptions: params.tracingOptions,
|
|
580
874
|
outputOptions: params.outputOptions,
|
|
581
|
-
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {}
|
|
875
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
876
|
+
perStep: params.perStep
|
|
582
877
|
}
|
|
583
878
|
});
|
|
584
879
|
const eventId = eventOutput.ids[0];
|
|
@@ -587,9 +882,7 @@ var InngestRun = class extends Run {
|
|
|
587
882
|
}
|
|
588
883
|
const runOutput = await this.getRunOutput(eventId);
|
|
589
884
|
const result = runOutput?.output?.result;
|
|
590
|
-
|
|
591
|
-
result.error = new Error(result.error);
|
|
592
|
-
}
|
|
885
|
+
this.hydrateFailedResult(result);
|
|
593
886
|
return result;
|
|
594
887
|
}
|
|
595
888
|
watch(cb) {
|
|
@@ -671,7 +964,8 @@ var InngestRun = class extends Run {
|
|
|
671
964
|
tracingOptions,
|
|
672
965
|
closeOnSuspend = true,
|
|
673
966
|
initialState,
|
|
674
|
-
outputOptions
|
|
967
|
+
outputOptions,
|
|
968
|
+
perStep
|
|
675
969
|
} = {}) {
|
|
676
970
|
if (this.closeStreamAction && this.streamOutput) {
|
|
677
971
|
return this.streamOutput;
|
|
@@ -707,7 +1001,8 @@ var InngestRun = class extends Run {
|
|
|
707
1001
|
initialState,
|
|
708
1002
|
tracingOptions,
|
|
709
1003
|
outputOptions,
|
|
710
|
-
format: "vnext"
|
|
1004
|
+
format: "vnext",
|
|
1005
|
+
perStep
|
|
711
1006
|
});
|
|
712
1007
|
let executionResults;
|
|
713
1008
|
try {
|
|
@@ -738,9 +1033,6 @@ var InngestRun = class extends Run {
|
|
|
738
1033
|
});
|
|
739
1034
|
return this.streamOutput;
|
|
740
1035
|
}
|
|
741
|
-
streamVNext(args = {}) {
|
|
742
|
-
return this.stream(args);
|
|
743
|
-
}
|
|
744
1036
|
timeTravelStream({
|
|
745
1037
|
inputData,
|
|
746
1038
|
resumeData,
|
|
@@ -750,7 +1042,8 @@ var InngestRun = class extends Run {
|
|
|
750
1042
|
nestedStepsContext,
|
|
751
1043
|
requestContext,
|
|
752
1044
|
tracingOptions,
|
|
753
|
-
outputOptions
|
|
1045
|
+
outputOptions,
|
|
1046
|
+
perStep
|
|
754
1047
|
}) {
|
|
755
1048
|
this.closeStreamAction = async () => {
|
|
756
1049
|
};
|
|
@@ -785,7 +1078,8 @@ var InngestRun = class extends Run {
|
|
|
785
1078
|
initialState,
|
|
786
1079
|
requestContext,
|
|
787
1080
|
tracingOptions,
|
|
788
|
-
outputOptions
|
|
1081
|
+
outputOptions,
|
|
1082
|
+
perStep
|
|
789
1083
|
});
|
|
790
1084
|
self.executionResults = executionResultsPromise;
|
|
791
1085
|
let executionResults;
|
|
@@ -810,6 +1104,18 @@ var InngestRun = class extends Run {
|
|
|
810
1104
|
});
|
|
811
1105
|
return this.streamOutput;
|
|
812
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 = getErrorFromUnknown(result.error, { serializeStack: false });
|
|
1114
|
+
if (result.steps) {
|
|
1115
|
+
hydrateSerializedStepErrors(result.steps);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
813
1119
|
};
|
|
814
1120
|
|
|
815
1121
|
// src/workflow.ts
|
|
@@ -817,9 +1123,11 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
817
1123
|
#mastra;
|
|
818
1124
|
inngest;
|
|
819
1125
|
function;
|
|
1126
|
+
cronFunction;
|
|
820
1127
|
flowControlConfig;
|
|
1128
|
+
cronConfig;
|
|
821
1129
|
constructor(params, inngest) {
|
|
822
|
-
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
1130
|
+
const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
|
|
823
1131
|
super(workflowParams);
|
|
824
1132
|
this.engineType = "inngest";
|
|
825
1133
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
@@ -828,6 +1136,9 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
828
1136
|
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
829
1137
|
this.#mastra = params.mastra;
|
|
830
1138
|
this.inngest = inngest;
|
|
1139
|
+
if (cron) {
|
|
1140
|
+
this.cronConfig = { cron, inputData, initialState };
|
|
1141
|
+
}
|
|
831
1142
|
}
|
|
832
1143
|
async listWorkflowRuns(args) {
|
|
833
1144
|
const storage = this.#mastra?.getStorage();
|
|
@@ -835,7 +1146,11 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
835
1146
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
836
1147
|
return { runs: [], total: 0 };
|
|
837
1148
|
}
|
|
838
|
-
|
|
1149
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1150
|
+
if (!workflowsStore) {
|
|
1151
|
+
return { runs: [], total: 0 };
|
|
1152
|
+
}
|
|
1153
|
+
return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
839
1154
|
}
|
|
840
1155
|
async getWorkflowRunById(runId) {
|
|
841
1156
|
const storage = this.#mastra?.getStorage();
|
|
@@ -843,10 +1158,15 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
843
1158
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
844
1159
|
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
845
1160
|
}
|
|
846
|
-
const
|
|
1161
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1162
|
+
if (!workflowsStore) {
|
|
1163
|
+
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
1164
|
+
}
|
|
1165
|
+
const run = await workflowsStore.getWorkflowRunById({ runId, workflowName: this.id });
|
|
847
1166
|
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
848
1167
|
}
|
|
849
1168
|
__registerMastra(mastra) {
|
|
1169
|
+
super.__registerMastra(mastra);
|
|
850
1170
|
this.#mastra = mastra;
|
|
851
1171
|
this.executionEngine.__registerMastra(mastra);
|
|
852
1172
|
const updateNested = (step) => {
|
|
@@ -888,9 +1208,12 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
888
1208
|
workflowStatus: run.workflowRunStatus,
|
|
889
1209
|
stepResults: {}
|
|
890
1210
|
});
|
|
891
|
-
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse,
|
|
1211
|
+
const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse, {
|
|
1212
|
+
withNestedWorkflows: false
|
|
1213
|
+
});
|
|
892
1214
|
if (!workflowSnapshotInStorage && shouldPersistSnapshot) {
|
|
893
|
-
await this.mastra?.getStorage()?.
|
|
1215
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
1216
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
894
1217
|
workflowName: this.id,
|
|
895
1218
|
runId: runIdToUse,
|
|
896
1219
|
resourceId: options?.resourceId,
|
|
@@ -913,6 +1236,30 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
913
1236
|
}
|
|
914
1237
|
return run;
|
|
915
1238
|
}
|
|
1239
|
+
//createCronFunction is only called if cronConfig.cron is defined.
|
|
1240
|
+
createCronFunction() {
|
|
1241
|
+
if (this.cronFunction) {
|
|
1242
|
+
return this.cronFunction;
|
|
1243
|
+
}
|
|
1244
|
+
this.cronFunction = this.inngest.createFunction(
|
|
1245
|
+
{
|
|
1246
|
+
id: `workflow.${this.id}.cron`,
|
|
1247
|
+
retries: 0,
|
|
1248
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
1249
|
+
...this.flowControlConfig
|
|
1250
|
+
},
|
|
1251
|
+
{ cron: this.cronConfig?.cron ?? "" },
|
|
1252
|
+
async () => {
|
|
1253
|
+
const run = await this.createRun();
|
|
1254
|
+
const result = await run.start({
|
|
1255
|
+
inputData: this.cronConfig?.inputData,
|
|
1256
|
+
initialState: this.cronConfig?.initialState
|
|
1257
|
+
});
|
|
1258
|
+
return { result, runId: run.runId };
|
|
1259
|
+
}
|
|
1260
|
+
);
|
|
1261
|
+
return this.cronFunction;
|
|
1262
|
+
}
|
|
916
1263
|
getFunction() {
|
|
917
1264
|
if (this.function) {
|
|
918
1265
|
return this.function;
|
|
@@ -920,41 +1267,20 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
920
1267
|
this.function = this.inngest.createFunction(
|
|
921
1268
|
{
|
|
922
1269
|
id: `workflow.${this.id}`,
|
|
923
|
-
retries:
|
|
1270
|
+
retries: 0,
|
|
924
1271
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
925
1272
|
// Spread flow control configuration
|
|
926
1273
|
...this.flowControlConfig
|
|
927
1274
|
},
|
|
928
1275
|
{ event: `workflow.${this.id}` },
|
|
929
1276
|
async ({ event, step, attempt, publish }) => {
|
|
930
|
-
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel } = event.data;
|
|
1277
|
+
let { inputData, initialState, runId, resourceId, resume, outputOptions, format, timeTravel, perStep } = event.data;
|
|
931
1278
|
if (!runId) {
|
|
932
1279
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
933
1280
|
return randomUUID();
|
|
934
1281
|
});
|
|
935
1282
|
}
|
|
936
|
-
const
|
|
937
|
-
emit: async (event2, data) => {
|
|
938
|
-
if (!publish) {
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
try {
|
|
942
|
-
await publish({
|
|
943
|
-
channel: `workflow:${this.id}:${runId}`,
|
|
944
|
-
topic: event2,
|
|
945
|
-
data
|
|
946
|
-
});
|
|
947
|
-
} catch (err) {
|
|
948
|
-
this.logger.error("Error emitting event: " + (err?.stack ?? err?.message ?? err));
|
|
949
|
-
}
|
|
950
|
-
},
|
|
951
|
-
on: (_event, _callback) => {
|
|
952
|
-
},
|
|
953
|
-
off: (_event, _callback) => {
|
|
954
|
-
},
|
|
955
|
-
once: (_event, _callback) => {
|
|
956
|
-
}
|
|
957
|
-
};
|
|
1283
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
958
1284
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
959
1285
|
const result = await engine.execute({
|
|
960
1286
|
workflowId: this.id,
|
|
@@ -964,23 +1290,32 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
964
1290
|
serializedStepGraph: this.serializedStepGraph,
|
|
965
1291
|
input: inputData,
|
|
966
1292
|
initialState,
|
|
967
|
-
|
|
1293
|
+
pubsub,
|
|
968
1294
|
retryConfig: this.retryConfig,
|
|
969
1295
|
requestContext: new RequestContext(Object.entries(event.data.requestContext ?? {})),
|
|
970
1296
|
resume,
|
|
971
1297
|
timeTravel,
|
|
1298
|
+
perStep,
|
|
972
1299
|
format,
|
|
973
1300
|
abortController: new AbortController(),
|
|
974
1301
|
// currentSpan: undefined, // TODO: Pass actual parent Span from workflow execution context
|
|
975
1302
|
outputOptions,
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1303
|
+
outputWriter: async (chunk) => {
|
|
1304
|
+
try {
|
|
1305
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1306
|
+
type: "watch",
|
|
1307
|
+
runId,
|
|
1308
|
+
data: chunk
|
|
979
1309
|
});
|
|
1310
|
+
} catch (err) {
|
|
1311
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
980
1312
|
}
|
|
981
|
-
}
|
|
1313
|
+
}
|
|
982
1314
|
});
|
|
983
1315
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1316
|
+
if (result.status !== "paused") {
|
|
1317
|
+
await engine.invokeLifecycleCallbacksInternal(result);
|
|
1318
|
+
}
|
|
984
1319
|
if (result.status === "failed") {
|
|
985
1320
|
throw new NonRetriableError(`Workflow failed`, {
|
|
986
1321
|
cause: result
|
|
@@ -1007,7 +1342,11 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
|
|
|
1007
1342
|
});
|
|
1008
1343
|
}
|
|
1009
1344
|
getFunctions() {
|
|
1010
|
-
return [
|
|
1345
|
+
return [
|
|
1346
|
+
this.getFunction(),
|
|
1347
|
+
...this.cronConfig?.cron ? [this.createCronFunction()] : [],
|
|
1348
|
+
...this.getNestedFunctions(this.executionGraph.steps)
|
|
1349
|
+
];
|
|
1011
1350
|
}
|
|
1012
1351
|
};
|
|
1013
1352
|
function serve({
|
|
@@ -1039,20 +1378,14 @@ function serve({
|
|
|
1039
1378
|
var _compatibilityCheck = true;
|
|
1040
1379
|
|
|
1041
1380
|
// src/index.ts
|
|
1042
|
-
function
|
|
1043
|
-
|
|
1044
|
-
}
|
|
1045
|
-
function isTool(params) {
|
|
1046
|
-
return params instanceof Tool;
|
|
1047
|
-
}
|
|
1048
|
-
function isInngestWorkflow(params) {
|
|
1049
|
-
return params instanceof InngestWorkflow;
|
|
1050
|
-
}
|
|
1051
|
-
function createStep(params, agentOptions) {
|
|
1052
|
-
if (isInngestWorkflow(params)) {
|
|
1381
|
+
function createStep(params, agentOrToolOptions) {
|
|
1382
|
+
if (params instanceof InngestWorkflow) {
|
|
1053
1383
|
return params;
|
|
1054
1384
|
}
|
|
1055
|
-
if (
|
|
1385
|
+
if (params instanceof Agent) {
|
|
1386
|
+
const options = agentOrToolOptions;
|
|
1387
|
+
const outputSchema = options?.structuredOutput?.schema ?? z.object({ text: z.string() });
|
|
1388
|
+
const { retries, scorers, ...agentOptions } = options ?? {};
|
|
1056
1389
|
return {
|
|
1057
1390
|
id: params.name,
|
|
1058
1391
|
description: params.getDescription(),
|
|
@@ -1061,12 +1394,13 @@ function createStep(params, agentOptions) {
|
|
|
1061
1394
|
// resourceId: z.string().optional(),
|
|
1062
1395
|
// threadId: z.string().optional(),
|
|
1063
1396
|
}),
|
|
1064
|
-
outputSchema
|
|
1065
|
-
|
|
1066
|
-
|
|
1397
|
+
outputSchema,
|
|
1398
|
+
retries,
|
|
1399
|
+
scorers,
|
|
1067
1400
|
execute: async ({
|
|
1068
1401
|
inputData,
|
|
1069
|
-
|
|
1402
|
+
runId,
|
|
1403
|
+
[PUBSUB_SYMBOL]: pubsub,
|
|
1070
1404
|
[STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
1071
1405
|
requestContext,
|
|
1072
1406
|
tracingContext,
|
|
@@ -1079,6 +1413,7 @@ function createStep(params, agentOptions) {
|
|
|
1079
1413
|
streamPromise.resolve = resolve;
|
|
1080
1414
|
streamPromise.reject = reject;
|
|
1081
1415
|
});
|
|
1416
|
+
let structuredResult = null;
|
|
1082
1417
|
const toolData = {
|
|
1083
1418
|
name: params.name,
|
|
1084
1419
|
args: inputData
|
|
@@ -1092,6 +1427,10 @@ function createStep(params, agentOptions) {
|
|
|
1092
1427
|
requestContext,
|
|
1093
1428
|
tracingContext,
|
|
1094
1429
|
onFinish: (result) => {
|
|
1430
|
+
const resultWithObject = result;
|
|
1431
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1432
|
+
structuredResult = resultWithObject.object;
|
|
1433
|
+
}
|
|
1095
1434
|
streamPromise.resolve(result.text);
|
|
1096
1435
|
void agentOptions?.onFinish?.(result);
|
|
1097
1436
|
},
|
|
@@ -1104,6 +1443,10 @@ function createStep(params, agentOptions) {
|
|
|
1104
1443
|
requestContext,
|
|
1105
1444
|
tracingContext,
|
|
1106
1445
|
onFinish: (result) => {
|
|
1446
|
+
const resultWithObject = result;
|
|
1447
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1448
|
+
structuredResult = resultWithObject.object;
|
|
1449
|
+
}
|
|
1107
1450
|
streamPromise.resolve(result.text);
|
|
1108
1451
|
void agentOptions?.onFinish?.(result);
|
|
1109
1452
|
},
|
|
@@ -1112,22 +1455,24 @@ function createStep(params, agentOptions) {
|
|
|
1112
1455
|
stream = modelOutput.fullStream;
|
|
1113
1456
|
}
|
|
1114
1457
|
if (streamFormat === "legacy") {
|
|
1115
|
-
await
|
|
1116
|
-
type: "
|
|
1117
|
-
|
|
1458
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1459
|
+
type: "watch",
|
|
1460
|
+
runId,
|
|
1461
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
1118
1462
|
});
|
|
1119
1463
|
for await (const chunk of stream) {
|
|
1120
1464
|
if (chunk.type === "text-delta") {
|
|
1121
|
-
await
|
|
1122
|
-
type: "
|
|
1123
|
-
|
|
1124
|
-
argsTextDelta: chunk.textDelta
|
|
1465
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1466
|
+
type: "watch",
|
|
1467
|
+
runId,
|
|
1468
|
+
data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
|
|
1125
1469
|
});
|
|
1126
1470
|
}
|
|
1127
1471
|
}
|
|
1128
|
-
await
|
|
1129
|
-
type: "
|
|
1130
|
-
|
|
1472
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1473
|
+
type: "watch",
|
|
1474
|
+
runId,
|
|
1475
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
1131
1476
|
});
|
|
1132
1477
|
} else {
|
|
1133
1478
|
for await (const chunk of stream) {
|
|
@@ -1137,6 +1482,9 @@ function createStep(params, agentOptions) {
|
|
|
1137
1482
|
if (abortSignal.aborted) {
|
|
1138
1483
|
return abort();
|
|
1139
1484
|
}
|
|
1485
|
+
if (structuredResult !== null) {
|
|
1486
|
+
return structuredResult;
|
|
1487
|
+
}
|
|
1140
1488
|
return {
|
|
1141
1489
|
text: await streamPromise.promise
|
|
1142
1490
|
};
|
|
@@ -1144,7 +1492,8 @@ function createStep(params, agentOptions) {
|
|
|
1144
1492
|
component: params.component
|
|
1145
1493
|
};
|
|
1146
1494
|
}
|
|
1147
|
-
if (
|
|
1495
|
+
if (params instanceof Tool) {
|
|
1496
|
+
const toolOpts = agentOrToolOptions;
|
|
1148
1497
|
if (!params.inputSchema || !params.outputSchema) {
|
|
1149
1498
|
throw new Error("Tool must have input and output schemas defined");
|
|
1150
1499
|
}
|
|
@@ -1156,6 +1505,8 @@ function createStep(params, agentOptions) {
|
|
|
1156
1505
|
outputSchema: params.outputSchema,
|
|
1157
1506
|
suspendSchema: params.suspendSchema,
|
|
1158
1507
|
resumeSchema: params.resumeSchema,
|
|
1508
|
+
retries: toolOpts?.retries,
|
|
1509
|
+
scorers: toolOpts?.scorers,
|
|
1159
1510
|
execute: async ({
|
|
1160
1511
|
inputData,
|
|
1161
1512
|
mastra,
|
|
@@ -1193,6 +1544,8 @@ function createStep(params, agentOptions) {
|
|
|
1193
1544
|
outputSchema: params.outputSchema,
|
|
1194
1545
|
resumeSchema: params.resumeSchema,
|
|
1195
1546
|
suspendSchema: params.suspendSchema,
|
|
1547
|
+
retries: params.retries,
|
|
1548
|
+
scorers: params.scorers,
|
|
1196
1549
|
execute: params.execute
|
|
1197
1550
|
};
|
|
1198
1551
|
}
|
|
@@ -1236,6 +1589,6 @@ function init(inngest) {
|
|
|
1236
1589
|
};
|
|
1237
1590
|
}
|
|
1238
1591
|
|
|
1239
|
-
export { InngestExecutionEngine, InngestRun, InngestWorkflow, _compatibilityCheck, createStep, init, serve };
|
|
1592
|
+
export { InngestExecutionEngine, InngestPubSub, InngestRun, InngestWorkflow, _compatibilityCheck, createStep, init, serve };
|
|
1240
1593
|
//# sourceMappingURL=index.js.map
|
|
1241
1594
|
//# sourceMappingURL=index.js.map
|