@mastra/inngest 0.0.0-span-scorring-test-20251124132129 → 0.0.0-standard-schema-20260126101119
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 +1301 -12
- package/dist/__tests__/adapters/_utils.d.ts +18 -0
- package/dist/__tests__/adapters/_utils.d.ts.map +1 -0
- package/dist/execution-engine.d.ts +206 -0
- package/dist/execution-engine.d.ts.map +1 -0
- package/dist/index.cjs +1640 -1143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +84 -338
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1643 -1149
- 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 +175 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/serve.d.ts +76 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/workflow.d.ts +52 -0
- package/dist/workflow.d.ts.map +1 -0
- package/package.json +26 -14
package/dist/index.cjs
CHANGED
|
@@ -1,43 +1,631 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var realtime = require('@inngest/realtime');
|
|
6
|
-
var di = require('@mastra/core/di');
|
|
3
|
+
var agent = require('@mastra/core/agent');
|
|
4
|
+
var error = require('@mastra/core/error');
|
|
7
5
|
var observability = require('@mastra/core/observability');
|
|
8
|
-
var
|
|
6
|
+
var processors = require('@mastra/core/processors');
|
|
7
|
+
var schema = require('@mastra/core/schema');
|
|
9
8
|
var tools = require('@mastra/core/tools');
|
|
10
9
|
var workflows = require('@mastra/core/workflows');
|
|
11
10
|
var _constants = require('@mastra/core/workflows/_constants');
|
|
11
|
+
var zod = require('zod');
|
|
12
|
+
var crypto$1 = require('crypto');
|
|
13
|
+
var di = require('@mastra/core/di');
|
|
12
14
|
var inngest = require('inngest');
|
|
15
|
+
var realtime = require('@inngest/realtime');
|
|
16
|
+
var events = require('@mastra/core/events');
|
|
17
|
+
var web = require('stream/web');
|
|
18
|
+
var stream = require('@mastra/core/stream');
|
|
13
19
|
var hono = require('inngest/hono');
|
|
14
|
-
var zod = require('zod');
|
|
15
20
|
|
|
16
21
|
// src/index.ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
23
|
+
inngestStep;
|
|
24
|
+
inngestAttempts;
|
|
25
|
+
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
26
|
+
super({ mastra, options });
|
|
27
|
+
this.inngestStep = inngestStep;
|
|
28
|
+
this.inngestAttempts = inngestAttempts;
|
|
29
|
+
}
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Hook Overrides
|
|
32
|
+
// =============================================================================
|
|
33
|
+
/**
|
|
34
|
+
* Format errors while preserving Error instances and their custom properties.
|
|
35
|
+
* Uses getErrorFromUnknown to ensure all error properties are preserved.
|
|
36
|
+
*/
|
|
37
|
+
formatResultError(error$1, lastOutput) {
|
|
38
|
+
const outputError = lastOutput?.error;
|
|
39
|
+
const errorSource = error$1 || outputError;
|
|
40
|
+
const errorInstance = error.getErrorFromUnknown(errorSource, {
|
|
41
|
+
serializeStack: true,
|
|
42
|
+
// Include stack in JSON for better debugging in Inngest
|
|
43
|
+
fallbackMessage: "Unknown workflow error"
|
|
44
|
+
});
|
|
45
|
+
return errorInstance.toJSON();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Detect InngestWorkflow instances for special nested workflow handling
|
|
49
|
+
*/
|
|
50
|
+
isNestedWorkflowStep(step) {
|
|
51
|
+
return step instanceof InngestWorkflow;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Inngest requires requestContext serialization for memoization.
|
|
55
|
+
* When steps are replayed, the original function doesn't re-execute,
|
|
56
|
+
* so requestContext modifications must be captured and restored.
|
|
57
|
+
*/
|
|
58
|
+
requiresDurableContextSerialization() {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Execute a step with retry logic for Inngest.
|
|
63
|
+
* Retries are handled via step-level retry (RetryAfterError thrown INSIDE step.run()).
|
|
64
|
+
* After retries exhausted, error propagates here and we return a failed result.
|
|
65
|
+
*/
|
|
66
|
+
async executeStepWithRetry(stepId, runStep, params) {
|
|
67
|
+
for (let i = 0; i < params.retries + 1; i++) {
|
|
68
|
+
if (i > 0 && params.delay) {
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, params.delay));
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const result = await this.wrapDurableOperation(stepId, runStep);
|
|
73
|
+
return { ok: true, result };
|
|
74
|
+
} catch (e) {
|
|
75
|
+
if (i === params.retries) {
|
|
76
|
+
const cause = e?.cause;
|
|
77
|
+
if (cause?.status === "failed") {
|
|
78
|
+
params.stepSpan?.error({
|
|
79
|
+
error: e,
|
|
80
|
+
attributes: { status: "failed" }
|
|
81
|
+
});
|
|
82
|
+
if (cause.error && !(cause.error instanceof Error)) {
|
|
83
|
+
cause.error = error.getErrorFromUnknown(cause.error, { serializeStack: false });
|
|
84
|
+
}
|
|
85
|
+
return { ok: false, error: cause };
|
|
86
|
+
}
|
|
87
|
+
const errorInstance = error.getErrorFromUnknown(e, {
|
|
88
|
+
serializeStack: false,
|
|
89
|
+
fallbackMessage: "Unknown step execution error"
|
|
90
|
+
});
|
|
91
|
+
params.stepSpan?.error({
|
|
92
|
+
error: errorInstance,
|
|
93
|
+
attributes: { status: "failed" }
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
error: {
|
|
98
|
+
status: "failed",
|
|
99
|
+
error: errorInstance,
|
|
100
|
+
endedAt: Date.now()
|
|
101
|
+
}
|
|
102
|
+
};
|
|
30
103
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { ok: false, error: { status: "failed", error: new Error("Unknown error"), endedAt: Date.now() } };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Use Inngest's sleep primitive for durability
|
|
110
|
+
*/
|
|
111
|
+
async executeSleepDuration(duration, sleepId, workflowId) {
|
|
112
|
+
await this.inngestStep.sleep(`workflow.${workflowId}.sleep.${sleepId}`, duration < 0 ? 0 : duration);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Use Inngest's sleepUntil primitive for durability
|
|
116
|
+
*/
|
|
117
|
+
async executeSleepUntilDate(date, sleepUntilId, workflowId) {
|
|
118
|
+
await this.inngestStep.sleepUntil(`workflow.${workflowId}.sleepUntil.${sleepUntilId}`, date);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Wrap durable operations in Inngest step.run() for durability.
|
|
122
|
+
*
|
|
123
|
+
* IMPORTANT: Errors are wrapped with a cause structure before throwing.
|
|
124
|
+
* This is necessary because Inngest's error serialization (serialize-error-cjs)
|
|
125
|
+
* only captures standard Error properties (message, name, stack, code, cause).
|
|
126
|
+
* Custom properties like statusCode, responseHeaders from AI SDK errors would
|
|
127
|
+
* be lost. By putting our serialized error (via getErrorFromUnknown with toJSON())
|
|
128
|
+
* in the cause property, we ensure custom properties survive serialization.
|
|
129
|
+
* The cause property is in serialize-error-cjs's allowlist, and when the cause
|
|
130
|
+
* object is finally JSON.stringify'd, our error's toJSON() is called.
|
|
131
|
+
*/
|
|
132
|
+
async wrapDurableOperation(operationId, operationFn) {
|
|
133
|
+
return this.inngestStep.run(operationId, async () => {
|
|
134
|
+
try {
|
|
135
|
+
return await operationFn();
|
|
136
|
+
} catch (e) {
|
|
137
|
+
const errorInstance = error.getErrorFromUnknown(e, {
|
|
138
|
+
serializeStack: false,
|
|
139
|
+
fallbackMessage: "Unknown step execution error"
|
|
140
|
+
});
|
|
141
|
+
throw new Error(errorInstance.message, {
|
|
142
|
+
cause: {
|
|
143
|
+
status: "failed",
|
|
144
|
+
error: errorInstance,
|
|
145
|
+
endedAt: Date.now()
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Provide Inngest step primitive in engine context
|
|
153
|
+
*/
|
|
154
|
+
getEngineContext() {
|
|
155
|
+
return { step: this.inngestStep };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* For Inngest, lifecycle callbacks are invoked in the workflow's finalize step
|
|
159
|
+
* (wrapped in step.run for durability), not in execute(). Override to skip.
|
|
160
|
+
*/
|
|
161
|
+
async invokeLifecycleCallbacks(_result) {
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Actually invoke the lifecycle callbacks. Called from workflow.ts finalize step.
|
|
165
|
+
*/
|
|
166
|
+
async invokeLifecycleCallbacksInternal(result) {
|
|
167
|
+
return super.invokeLifecycleCallbacks(result);
|
|
168
|
+
}
|
|
169
|
+
// =============================================================================
|
|
170
|
+
// Durable Span Lifecycle Hooks
|
|
171
|
+
// =============================================================================
|
|
172
|
+
/**
|
|
173
|
+
* Create a step span durably - on first execution, creates and exports span.
|
|
174
|
+
* On replay, returns cached span data without re-creating.
|
|
175
|
+
*/
|
|
176
|
+
async createStepSpan(params) {
|
|
177
|
+
const { executionContext, operationId, options, parentSpan } = params;
|
|
178
|
+
const parentSpanId = parentSpan?.id ?? executionContext.tracingIds?.workflowSpanId;
|
|
179
|
+
const exportedSpan = await this.wrapDurableOperation(operationId, async () => {
|
|
180
|
+
const observability = this.mastra?.observability?.getSelectedInstance({});
|
|
181
|
+
if (!observability) return void 0;
|
|
182
|
+
const span = observability.startSpan({
|
|
183
|
+
...options,
|
|
184
|
+
entityType: options.entityType,
|
|
185
|
+
traceId: executionContext.tracingIds?.traceId,
|
|
186
|
+
parentSpanId
|
|
187
|
+
});
|
|
188
|
+
return span?.exportSpan();
|
|
189
|
+
});
|
|
190
|
+
if (exportedSpan) {
|
|
191
|
+
const observability = this.mastra?.observability?.getSelectedInstance({});
|
|
192
|
+
return observability?.rebuildSpan(exportedSpan);
|
|
193
|
+
}
|
|
194
|
+
return void 0;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* End a step span durably.
|
|
198
|
+
*/
|
|
199
|
+
async endStepSpan(params) {
|
|
200
|
+
const { span, operationId, endOptions } = params;
|
|
201
|
+
if (!span) return;
|
|
202
|
+
await this.wrapDurableOperation(operationId, async () => {
|
|
203
|
+
span.end(endOptions);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Record error on step span durably.
|
|
208
|
+
*/
|
|
209
|
+
async errorStepSpan(params) {
|
|
210
|
+
const { span, operationId, errorOptions } = params;
|
|
211
|
+
if (!span) return;
|
|
212
|
+
await this.wrapDurableOperation(operationId, async () => {
|
|
213
|
+
span.error(errorOptions);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a generic child span durably (for control-flow operations).
|
|
218
|
+
* On first execution, creates and exports span. On replay, returns cached span data.
|
|
219
|
+
*/
|
|
220
|
+
async createChildSpan(params) {
|
|
221
|
+
const { executionContext, operationId, options, parentSpan } = params;
|
|
222
|
+
const parentSpanId = parentSpan?.id ?? executionContext.tracingIds?.workflowSpanId;
|
|
223
|
+
const exportedSpan = await this.wrapDurableOperation(operationId, async () => {
|
|
224
|
+
const observability = this.mastra?.observability?.getSelectedInstance({});
|
|
225
|
+
if (!observability) return void 0;
|
|
226
|
+
const span = observability.startSpan({
|
|
227
|
+
...options,
|
|
228
|
+
traceId: executionContext.tracingIds?.traceId,
|
|
229
|
+
parentSpanId
|
|
230
|
+
});
|
|
231
|
+
return span?.exportSpan();
|
|
232
|
+
});
|
|
233
|
+
if (exportedSpan) {
|
|
234
|
+
const observability = this.mastra?.observability?.getSelectedInstance({});
|
|
235
|
+
return observability?.rebuildSpan(exportedSpan);
|
|
236
|
+
}
|
|
237
|
+
return void 0;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* End a generic child span durably (for control-flow operations).
|
|
241
|
+
*/
|
|
242
|
+
async endChildSpan(params) {
|
|
243
|
+
const { span, operationId, endOptions } = params;
|
|
244
|
+
if (!span) return;
|
|
245
|
+
await this.wrapDurableOperation(operationId, async () => {
|
|
246
|
+
span.end(endOptions);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Record error on a generic child span durably (for control-flow operations).
|
|
251
|
+
*/
|
|
252
|
+
async errorChildSpan(params) {
|
|
253
|
+
const { span, operationId, errorOptions } = params;
|
|
254
|
+
if (!span) return;
|
|
255
|
+
await this.wrapDurableOperation(operationId, async () => {
|
|
256
|
+
span.error(errorOptions);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Execute nested InngestWorkflow using inngestStep.invoke() for durability.
|
|
261
|
+
* This MUST be called directly (not inside step.run()) due to Inngest constraints.
|
|
262
|
+
*/
|
|
263
|
+
async executeWorkflowStep(params) {
|
|
264
|
+
if (!(params.step instanceof InngestWorkflow)) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
const {
|
|
268
|
+
step,
|
|
269
|
+
stepResults,
|
|
270
|
+
executionContext,
|
|
271
|
+
resume,
|
|
272
|
+
timeTravel,
|
|
273
|
+
prevOutput,
|
|
274
|
+
inputData,
|
|
275
|
+
pubsub,
|
|
276
|
+
startedAt,
|
|
277
|
+
perStep,
|
|
278
|
+
stepSpan
|
|
279
|
+
} = params;
|
|
280
|
+
const nestedTracingContext = executionContext.tracingIds?.traceId ? {
|
|
281
|
+
traceId: executionContext.tracingIds.traceId,
|
|
282
|
+
parentSpanId: stepSpan?.id
|
|
283
|
+
} : void 0;
|
|
284
|
+
const isResume = !!resume?.steps?.length;
|
|
285
|
+
let result;
|
|
286
|
+
let runId;
|
|
287
|
+
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
288
|
+
try {
|
|
289
|
+
if (isResume) {
|
|
290
|
+
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto$1.randomUUID();
|
|
291
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
292
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
293
|
+
workflowName: step.id,
|
|
294
|
+
runId
|
|
295
|
+
});
|
|
296
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
297
|
+
function: step.getFunction(),
|
|
298
|
+
data: {
|
|
299
|
+
inputData,
|
|
300
|
+
initialState: executionContext.state ?? snapshot?.value ?? {},
|
|
301
|
+
runId,
|
|
302
|
+
resume: {
|
|
303
|
+
runId,
|
|
304
|
+
steps: resume.steps.slice(1),
|
|
305
|
+
stepResults: snapshot?.context,
|
|
306
|
+
resumePayload: resume.resumePayload,
|
|
307
|
+
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
308
|
+
},
|
|
309
|
+
outputOptions: { includeState: true },
|
|
310
|
+
perStep,
|
|
311
|
+
tracingOptions: nestedTracingContext
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
result = invokeResp.result;
|
|
315
|
+
runId = invokeResp.runId;
|
|
316
|
+
executionContext.state = invokeResp.result.state;
|
|
317
|
+
} else if (isTimeTravel) {
|
|
318
|
+
const workflowsStoreForTimeTravel = await this.mastra?.getStorage()?.getStore("workflows");
|
|
319
|
+
const snapshot = await workflowsStoreForTimeTravel?.loadWorkflowSnapshot({
|
|
320
|
+
workflowName: step.id,
|
|
321
|
+
runId: executionContext.runId
|
|
322
|
+
}) ?? { context: {} };
|
|
323
|
+
const timeTravelParams = workflows.createTimeTravelExecutionParams({
|
|
324
|
+
steps: timeTravel.steps.slice(1),
|
|
325
|
+
inputData: timeTravel.inputData,
|
|
326
|
+
resumeData: timeTravel.resumeData,
|
|
327
|
+
context: timeTravel.nestedStepResults?.[step.id] ?? {},
|
|
328
|
+
nestedStepsContext: timeTravel.nestedStepResults ?? {},
|
|
329
|
+
snapshot,
|
|
330
|
+
graph: step.buildExecutionGraph()
|
|
331
|
+
});
|
|
332
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
333
|
+
function: step.getFunction(),
|
|
334
|
+
data: {
|
|
335
|
+
timeTravel: timeTravelParams,
|
|
336
|
+
initialState: executionContext.state ?? {},
|
|
337
|
+
runId: executionContext.runId,
|
|
338
|
+
outputOptions: { includeState: true },
|
|
339
|
+
perStep,
|
|
340
|
+
tracingOptions: nestedTracingContext
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
result = invokeResp.result;
|
|
344
|
+
runId = invokeResp.runId;
|
|
345
|
+
executionContext.state = invokeResp.result.state;
|
|
346
|
+
} else {
|
|
347
|
+
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
348
|
+
function: step.getFunction(),
|
|
349
|
+
data: {
|
|
350
|
+
inputData,
|
|
351
|
+
initialState: executionContext.state ?? {},
|
|
352
|
+
outputOptions: { includeState: true },
|
|
353
|
+
perStep,
|
|
354
|
+
tracingOptions: nestedTracingContext
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
result = invokeResp.result;
|
|
358
|
+
runId = invokeResp.runId;
|
|
359
|
+
executionContext.state = invokeResp.result.state;
|
|
360
|
+
}
|
|
361
|
+
} catch (e) {
|
|
362
|
+
const errorCause = e?.cause;
|
|
363
|
+
if (errorCause && typeof errorCause === "object") {
|
|
364
|
+
result = errorCause;
|
|
365
|
+
runId = errorCause.runId || crypto$1.randomUUID();
|
|
366
|
+
} else {
|
|
367
|
+
runId = crypto$1.randomUUID();
|
|
368
|
+
result = {
|
|
369
|
+
status: "failed",
|
|
370
|
+
error: e instanceof Error ? e : new Error(String(e)),
|
|
371
|
+
steps: {},
|
|
372
|
+
input: inputData
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const res = await this.inngestStep.run(
|
|
377
|
+
`workflow.${executionContext.workflowId}.step.${step.id}.nestedwf-results`,
|
|
378
|
+
async () => {
|
|
379
|
+
if (result.status === "failed") {
|
|
380
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
381
|
+
type: "watch",
|
|
382
|
+
runId: executionContext.runId,
|
|
383
|
+
data: {
|
|
384
|
+
type: "workflow-step-result",
|
|
385
|
+
payload: {
|
|
386
|
+
id: step.id,
|
|
387
|
+
status: "failed",
|
|
388
|
+
error: result?.error,
|
|
389
|
+
payload: prevOutput
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
return { executionContext, result: { status: "failed", error: result?.error, endedAt: Date.now() } };
|
|
394
|
+
} else if (result.status === "suspended") {
|
|
395
|
+
const suspendedSteps = Object.entries(result.steps).filter(([_stepName, stepResult]) => {
|
|
396
|
+
const stepRes = stepResult;
|
|
397
|
+
return stepRes?.status === "suspended";
|
|
398
|
+
});
|
|
399
|
+
for (const [stepName, stepResult] of suspendedSteps) {
|
|
400
|
+
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
401
|
+
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
402
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
403
|
+
type: "watch",
|
|
404
|
+
runId: executionContext.runId,
|
|
405
|
+
data: {
|
|
406
|
+
type: "workflow-step-suspended",
|
|
407
|
+
payload: {
|
|
408
|
+
id: step.id,
|
|
409
|
+
status: "suspended"
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
return {
|
|
414
|
+
executionContext,
|
|
415
|
+
result: {
|
|
416
|
+
status: "suspended",
|
|
417
|
+
suspendedAt: Date.now(),
|
|
418
|
+
payload: stepResult.payload,
|
|
419
|
+
suspendPayload: {
|
|
420
|
+
...stepResult?.suspendPayload,
|
|
421
|
+
__workflow_meta: { runId, path: suspendPath }
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
executionContext,
|
|
428
|
+
result: {
|
|
429
|
+
status: "suspended",
|
|
430
|
+
suspendedAt: Date.now(),
|
|
431
|
+
payload: {}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
} else if (result.status === "tripwire") {
|
|
435
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
436
|
+
type: "watch",
|
|
437
|
+
runId: executionContext.runId,
|
|
438
|
+
data: {
|
|
439
|
+
type: "workflow-step-result",
|
|
440
|
+
payload: {
|
|
441
|
+
id: step.id,
|
|
442
|
+
status: "tripwire",
|
|
443
|
+
error: result?.tripwire?.reason,
|
|
444
|
+
payload: prevOutput
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
return {
|
|
449
|
+
executionContext,
|
|
450
|
+
result: {
|
|
451
|
+
status: "tripwire",
|
|
452
|
+
tripwire: result?.tripwire,
|
|
453
|
+
endedAt: Date.now()
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
} else if (perStep || result.status === "paused") {
|
|
457
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
458
|
+
type: "watch",
|
|
459
|
+
runId: executionContext.runId,
|
|
460
|
+
data: {
|
|
461
|
+
type: "workflow-step-result",
|
|
462
|
+
payload: {
|
|
463
|
+
id: step.id,
|
|
464
|
+
status: "paused"
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
469
|
+
type: "watch",
|
|
470
|
+
runId: executionContext.runId,
|
|
471
|
+
data: {
|
|
472
|
+
type: "workflow-step-finish",
|
|
473
|
+
payload: {
|
|
474
|
+
id: step.id,
|
|
475
|
+
metadata: {}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
return { executionContext, result: { status: "paused" } };
|
|
480
|
+
}
|
|
481
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
482
|
+
type: "watch",
|
|
483
|
+
runId: executionContext.runId,
|
|
484
|
+
data: {
|
|
485
|
+
type: "workflow-step-result",
|
|
486
|
+
payload: {
|
|
487
|
+
id: step.id,
|
|
488
|
+
status: "success",
|
|
489
|
+
output: result?.result
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
await pubsub.publish(`workflow.events.v2.${executionContext.runId}`, {
|
|
494
|
+
type: "watch",
|
|
495
|
+
runId: executionContext.runId,
|
|
496
|
+
data: {
|
|
497
|
+
type: "workflow-step-finish",
|
|
498
|
+
payload: {
|
|
499
|
+
id: step.id,
|
|
500
|
+
metadata: {}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
return { executionContext, result: { status: "success", output: result?.result, endedAt: Date.now() } };
|
|
505
|
+
}
|
|
506
|
+
);
|
|
507
|
+
Object.assign(executionContext, res.executionContext);
|
|
508
|
+
return {
|
|
509
|
+
...res.result,
|
|
510
|
+
startedAt,
|
|
511
|
+
payload: inputData,
|
|
512
|
+
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
513
|
+
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
var InngestPubSub = class extends events.PubSub {
|
|
518
|
+
inngest;
|
|
519
|
+
workflowId;
|
|
520
|
+
publishFn;
|
|
521
|
+
subscriptions = /* @__PURE__ */ new Map();
|
|
522
|
+
constructor(inngest, workflowId, publishFn) {
|
|
523
|
+
super();
|
|
524
|
+
this.inngest = inngest;
|
|
525
|
+
this.workflowId = workflowId;
|
|
526
|
+
this.publishFn = publishFn;
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Publish an event to Inngest's realtime system.
|
|
530
|
+
*
|
|
531
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
532
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
533
|
+
*/
|
|
534
|
+
async publish(topic, event) {
|
|
535
|
+
if (!this.publishFn) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
539
|
+
if (!match) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const runId = match[1];
|
|
543
|
+
try {
|
|
544
|
+
await this.publishFn({
|
|
545
|
+
channel: `workflow:${this.workflowId}:${runId}`,
|
|
546
|
+
topic: "watch",
|
|
547
|
+
data: event.data
|
|
548
|
+
});
|
|
549
|
+
} catch (err) {
|
|
550
|
+
console.error("InngestPubSub publish error:", err?.message ?? err);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Subscribe to events from Inngest's realtime system.
|
|
555
|
+
*
|
|
556
|
+
* Topic format: "workflow.events.v2.{runId}"
|
|
557
|
+
* Maps to Inngest channel: "workflow:{workflowId}:{runId}"
|
|
558
|
+
*/
|
|
559
|
+
async subscribe(topic, cb) {
|
|
560
|
+
const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
|
|
561
|
+
if (!match || !match[1]) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const runId = match[1];
|
|
565
|
+
if (this.subscriptions.has(topic)) {
|
|
566
|
+
this.subscriptions.get(topic).callbacks.add(cb);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const callbacks = /* @__PURE__ */ new Set([cb]);
|
|
570
|
+
const channel = `workflow:${this.workflowId}:${runId}`;
|
|
571
|
+
const streamPromise = realtime.subscribe(
|
|
572
|
+
{
|
|
573
|
+
channel,
|
|
574
|
+
topics: ["watch"],
|
|
575
|
+
app: this.inngest
|
|
576
|
+
},
|
|
577
|
+
(message) => {
|
|
578
|
+
const event = {
|
|
579
|
+
id: crypto.randomUUID(),
|
|
580
|
+
type: "watch",
|
|
581
|
+
runId,
|
|
582
|
+
data: message.data,
|
|
583
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
584
|
+
};
|
|
585
|
+
for (const callback of callbacks) {
|
|
586
|
+
callback(event);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
this.subscriptions.set(topic, {
|
|
591
|
+
unsubscribe: () => {
|
|
592
|
+
streamPromise.then((stream) => stream.cancel()).catch((err) => {
|
|
593
|
+
console.error("InngestPubSub unsubscribe error:", err);
|
|
594
|
+
});
|
|
595
|
+
},
|
|
596
|
+
callbacks
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Unsubscribe a callback from a topic.
|
|
601
|
+
* If no callbacks remain, the underlying Inngest subscription is cancelled.
|
|
602
|
+
*/
|
|
603
|
+
async unsubscribe(topic, cb) {
|
|
604
|
+
const sub = this.subscriptions.get(topic);
|
|
605
|
+
if (!sub) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
sub.callbacks.delete(cb);
|
|
609
|
+
if (sub.callbacks.size === 0) {
|
|
610
|
+
sub.unsubscribe();
|
|
611
|
+
this.subscriptions.delete(topic);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Flush any pending operations. No-op for Inngest.
|
|
616
|
+
*/
|
|
617
|
+
async flush() {
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Clean up all subscriptions during graceful shutdown.
|
|
621
|
+
*/
|
|
622
|
+
async close() {
|
|
623
|
+
for (const [, sub] of this.subscriptions) {
|
|
624
|
+
sub.unsubscribe();
|
|
625
|
+
}
|
|
626
|
+
this.subscriptions.clear();
|
|
627
|
+
}
|
|
628
|
+
};
|
|
41
629
|
var InngestRun = class extends workflows.Run {
|
|
42
630
|
inngest;
|
|
43
631
|
serializedStepGraph;
|
|
@@ -49,38 +637,90 @@ var InngestRun = class extends workflows.Run {
|
|
|
49
637
|
this.#mastra = params.mastra;
|
|
50
638
|
}
|
|
51
639
|
async getRuns(eventId) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
640
|
+
const maxRetries = 3;
|
|
641
|
+
let lastError = null;
|
|
642
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
643
|
+
try {
|
|
644
|
+
const response = await fetch(
|
|
645
|
+
`${this.inngest.apiBaseUrl ?? "https://api.inngest.com"}/v1/events/${eventId}/runs`,
|
|
646
|
+
{
|
|
647
|
+
headers: {
|
|
648
|
+
Authorization: `Bearer ${process.env.INNGEST_SIGNING_KEY}`
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
if (response.status === 429) {
|
|
653
|
+
const retryAfter = parseInt(response.headers.get("retry-after") || "2", 10);
|
|
654
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1e3));
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (!response.ok) {
|
|
658
|
+
throw new Error(`Inngest API error: ${response.status} ${response.statusText}`);
|
|
659
|
+
}
|
|
660
|
+
const text = await response.text();
|
|
661
|
+
if (!text) {
|
|
662
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
const json = JSON.parse(text);
|
|
666
|
+
return json.data;
|
|
667
|
+
} catch (error) {
|
|
668
|
+
lastError = error;
|
|
669
|
+
if (attempt < maxRetries - 1) {
|
|
670
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 * Math.pow(2, attempt)));
|
|
671
|
+
}
|
|
55
672
|
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return json.data;
|
|
673
|
+
}
|
|
674
|
+
throw new inngest.NonRetriableError(`Failed to get runs after ${maxRetries} attempts: ${lastError?.message}`);
|
|
59
675
|
}
|
|
60
|
-
async getRunOutput(eventId) {
|
|
61
|
-
|
|
676
|
+
async getRunOutput(eventId, maxWaitMs = 3e5) {
|
|
677
|
+
const startTime = Date.now();
|
|
62
678
|
const storage = this.#mastra?.getStorage();
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
runs
|
|
679
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
680
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
681
|
+
let runs;
|
|
682
|
+
try {
|
|
683
|
+
runs = await this.getRuns(eventId);
|
|
684
|
+
} catch (error) {
|
|
685
|
+
if (error instanceof inngest.NonRetriableError) {
|
|
686
|
+
throw error;
|
|
687
|
+
}
|
|
688
|
+
throw new inngest.NonRetriableError(
|
|
689
|
+
`Failed to poll workflow status: ${error instanceof Error ? error.message : String(error)}`
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
if (runs?.[0]?.status === "Completed" && runs?.[0]?.event_id === eventId) {
|
|
693
|
+
return runs[0];
|
|
694
|
+
}
|
|
66
695
|
if (runs?.[0]?.status === "Failed") {
|
|
67
|
-
const snapshot = await
|
|
696
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
68
697
|
workflowName: this.workflowId,
|
|
69
698
|
runId: this.runId
|
|
70
699
|
});
|
|
700
|
+
if (snapshot?.context) {
|
|
701
|
+
snapshot.context = workflows.hydrateSerializedStepErrors(snapshot.context);
|
|
702
|
+
}
|
|
71
703
|
return {
|
|
72
|
-
output: {
|
|
704
|
+
output: {
|
|
705
|
+
result: {
|
|
706
|
+
steps: snapshot?.context,
|
|
707
|
+
status: "failed",
|
|
708
|
+
// Get the original error from NonRetriableError's cause (which contains the workflow result)
|
|
709
|
+
error: error.getErrorFromUnknown(runs?.[0]?.output?.cause?.error, { serializeStack: false })
|
|
710
|
+
}
|
|
711
|
+
}
|
|
73
712
|
};
|
|
74
713
|
}
|
|
75
714
|
if (runs?.[0]?.status === "Cancelled") {
|
|
76
|
-
const snapshot = await
|
|
715
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
77
716
|
workflowName: this.workflowId,
|
|
78
717
|
runId: this.runId
|
|
79
718
|
});
|
|
80
719
|
return { output: { result: { steps: snapshot?.context, status: "canceled" } } };
|
|
81
720
|
}
|
|
721
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3 + Math.random() * 1e3));
|
|
82
722
|
}
|
|
83
|
-
|
|
723
|
+
throw new inngest.NonRetriableError(`Workflow did not complete within ${maxWaitMs}ms`);
|
|
84
724
|
}
|
|
85
725
|
async cancel() {
|
|
86
726
|
const storage = this.#mastra?.getStorage();
|
|
@@ -90,12 +730,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
90
730
|
runId: this.runId
|
|
91
731
|
}
|
|
92
732
|
});
|
|
93
|
-
const
|
|
733
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
734
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
94
735
|
workflowName: this.workflowId,
|
|
95
736
|
runId: this.runId
|
|
96
737
|
});
|
|
97
738
|
if (snapshot) {
|
|
98
|
-
await
|
|
739
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
99
740
|
workflowName: this.workflowId,
|
|
100
741
|
runId: this.runId,
|
|
101
742
|
resourceId: this.resourceId,
|
|
@@ -107,17 +748,18 @@ var InngestRun = class extends workflows.Run {
|
|
|
107
748
|
});
|
|
108
749
|
}
|
|
109
750
|
}
|
|
110
|
-
async start(
|
|
111
|
-
return this._start(
|
|
751
|
+
async start(args) {
|
|
752
|
+
return this._start(args);
|
|
112
753
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
await this.#mastra.getStorage()?.
|
|
754
|
+
/**
|
|
755
|
+
* Starts the workflow execution without waiting for completion (fire-and-forget).
|
|
756
|
+
* Returns immediately with the runId after sending the event to Inngest.
|
|
757
|
+
* The workflow executes independently in Inngest.
|
|
758
|
+
* Use this when you don't need to wait for the result or want to avoid polling failures.
|
|
759
|
+
*/
|
|
760
|
+
async startAsync(args) {
|
|
761
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
762
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
121
763
|
workflowName: this.workflowId,
|
|
122
764
|
runId: this.runId,
|
|
123
765
|
resourceId: this.resourceId,
|
|
@@ -135,8 +777,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
135
777
|
timestamp: Date.now()
|
|
136
778
|
}
|
|
137
779
|
});
|
|
138
|
-
const inputDataToUse = await this._validateInput(inputData);
|
|
139
|
-
const initialStateToUse = await this._validateInitialState(initialState ?? {});
|
|
780
|
+
const inputDataToUse = await this._validateInput(args.inputData);
|
|
781
|
+
const initialStateToUse = await this._validateInitialState(args.initialState ?? {});
|
|
140
782
|
const eventOutput = await this.inngest.send({
|
|
141
783
|
name: `workflow.${this.workflowId}`,
|
|
142
784
|
data: {
|
|
@@ -144,24 +786,73 @@ var InngestRun = class extends workflows.Run {
|
|
|
144
786
|
initialState: initialStateToUse,
|
|
145
787
|
runId: this.runId,
|
|
146
788
|
resourceId: this.resourceId,
|
|
147
|
-
outputOptions,
|
|
148
|
-
tracingOptions,
|
|
149
|
-
|
|
789
|
+
outputOptions: args.outputOptions,
|
|
790
|
+
tracingOptions: args.tracingOptions,
|
|
791
|
+
requestContext: args.requestContext ? Object.fromEntries(args.requestContext.entries()) : {},
|
|
792
|
+
perStep: args.perStep
|
|
150
793
|
}
|
|
151
794
|
});
|
|
152
795
|
const eventId = eventOutput.ids[0];
|
|
153
796
|
if (!eventId) {
|
|
154
797
|
throw new Error("Event ID is not set");
|
|
155
798
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
799
|
+
return { runId: this.runId };
|
|
800
|
+
}
|
|
801
|
+
async _start({
|
|
802
|
+
inputData,
|
|
803
|
+
initialState,
|
|
804
|
+
outputOptions,
|
|
805
|
+
tracingOptions,
|
|
806
|
+
format,
|
|
807
|
+
requestContext,
|
|
808
|
+
perStep
|
|
809
|
+
}) {
|
|
810
|
+
const workflowsStore = await this.#mastra.getStorage()?.getStore("workflows");
|
|
811
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
812
|
+
workflowName: this.workflowId,
|
|
813
|
+
runId: this.runId,
|
|
814
|
+
resourceId: this.resourceId,
|
|
815
|
+
snapshot: {
|
|
816
|
+
runId: this.runId,
|
|
817
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
818
|
+
status: "running",
|
|
819
|
+
value: {},
|
|
820
|
+
context: {},
|
|
821
|
+
activePaths: [],
|
|
822
|
+
suspendedPaths: {},
|
|
823
|
+
activeStepsPath: {},
|
|
824
|
+
resumeLabels: {},
|
|
825
|
+
waitingPaths: {},
|
|
826
|
+
timestamp: Date.now()
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
const inputDataToUse = await this._validateInput(inputData);
|
|
830
|
+
const initialStateToUse = await this._validateInitialState(initialState ?? {});
|
|
831
|
+
const eventOutput = await this.inngest.send({
|
|
832
|
+
name: `workflow.${this.workflowId}`,
|
|
833
|
+
data: {
|
|
834
|
+
inputData: inputDataToUse,
|
|
835
|
+
initialState: initialStateToUse,
|
|
836
|
+
runId: this.runId,
|
|
837
|
+
resourceId: this.resourceId,
|
|
838
|
+
outputOptions,
|
|
839
|
+
tracingOptions,
|
|
840
|
+
format,
|
|
841
|
+
requestContext: requestContext ? Object.fromEntries(requestContext.entries()) : {},
|
|
842
|
+
perStep
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
const eventId = eventOutput.ids[0];
|
|
846
|
+
if (!eventId) {
|
|
847
|
+
throw new Error("Event ID is not set");
|
|
848
|
+
}
|
|
849
|
+
const runOutput = await this.getRunOutput(eventId);
|
|
850
|
+
const result = runOutput?.output?.result;
|
|
851
|
+
this.hydrateFailedResult(result);
|
|
852
|
+
if (result.status !== "suspended") {
|
|
853
|
+
this.cleanup?.();
|
|
854
|
+
}
|
|
855
|
+
return result;
|
|
165
856
|
}
|
|
166
857
|
async resume(params) {
|
|
167
858
|
const p = this._resume(params).then((result) => {
|
|
@@ -184,12 +875,16 @@ var InngestRun = class extends workflows.Run {
|
|
|
184
875
|
(step) => typeof step === "string" ? step : step?.id
|
|
185
876
|
);
|
|
186
877
|
}
|
|
187
|
-
const
|
|
878
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
879
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
188
880
|
workflowName: this.workflowId,
|
|
189
881
|
runId: this.runId
|
|
190
882
|
});
|
|
191
883
|
const suspendedStep = this.workflowSteps[steps?.[0] ?? ""];
|
|
192
884
|
const resumeDataToUse = await this._validateResumeData(params.resumeData, suspendedStep);
|
|
885
|
+
const persistedRequestContext = snapshot?.requestContext ?? {};
|
|
886
|
+
const newRequestContext = params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {};
|
|
887
|
+
const mergedRequestContext = { ...persistedRequestContext, ...newRequestContext };
|
|
193
888
|
const eventOutput = await this.inngest.send({
|
|
194
889
|
name: `workflow.${this.workflowId}`,
|
|
195
890
|
data: {
|
|
@@ -203,7 +898,9 @@ var InngestRun = class extends workflows.Run {
|
|
|
203
898
|
stepResults: snapshot?.context,
|
|
204
899
|
resumePayload: resumeDataToUse,
|
|
205
900
|
resumePath: steps?.[0] ? snapshot?.suspendedPaths?.[steps?.[0]] : void 0
|
|
206
|
-
}
|
|
901
|
+
},
|
|
902
|
+
requestContext: mergedRequestContext,
|
|
903
|
+
perStep: params.perStep
|
|
207
904
|
}
|
|
208
905
|
});
|
|
209
906
|
const eventId = eventOutput.ids[0];
|
|
@@ -212,9 +909,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
212
909
|
}
|
|
213
910
|
const runOutput = await this.getRunOutput(eventId);
|
|
214
911
|
const result = runOutput?.output?.result;
|
|
215
|
-
|
|
216
|
-
result.error = new Error(result.error);
|
|
217
|
-
}
|
|
912
|
+
this.hydrateFailedResult(result);
|
|
218
913
|
return result;
|
|
219
914
|
}
|
|
220
915
|
async timeTravel(params) {
|
|
@@ -244,12 +939,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
244
939
|
throw new Error("No steps provided to timeTravel");
|
|
245
940
|
}
|
|
246
941
|
const storage = this.#mastra?.getStorage();
|
|
247
|
-
const
|
|
942
|
+
const workflowsStore = await storage?.getStore("workflows");
|
|
943
|
+
const snapshot = await workflowsStore?.loadWorkflowSnapshot({
|
|
248
944
|
workflowName: this.workflowId,
|
|
249
945
|
runId: this.runId
|
|
250
946
|
});
|
|
251
947
|
if (!snapshot) {
|
|
252
|
-
await
|
|
948
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
253
949
|
workflowName: this.workflowId,
|
|
254
950
|
runId: this.runId,
|
|
255
951
|
resourceId: this.resourceId,
|
|
@@ -283,7 +979,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
283
979
|
nestedStepsContext: params.nestedStepsContext,
|
|
284
980
|
snapshot: snapshot ?? { context: {} },
|
|
285
981
|
graph: this.executionGraph,
|
|
286
|
-
initialState: params.initialState
|
|
982
|
+
initialState: params.initialState,
|
|
983
|
+
perStep: params.perStep
|
|
287
984
|
});
|
|
288
985
|
const eventOutput = await this.inngest.send({
|
|
289
986
|
name: `workflow.${this.workflowId}`,
|
|
@@ -294,7 +991,9 @@ var InngestRun = class extends workflows.Run {
|
|
|
294
991
|
stepResults: timeTravelData.stepResults,
|
|
295
992
|
timeTravel: timeTravelData,
|
|
296
993
|
tracingOptions: params.tracingOptions,
|
|
297
|
-
outputOptions: params.outputOptions
|
|
994
|
+
outputOptions: params.outputOptions,
|
|
995
|
+
requestContext: params.requestContext ? Object.fromEntries(params.requestContext.entries()) : {},
|
|
996
|
+
perStep: params.perStep
|
|
298
997
|
}
|
|
299
998
|
});
|
|
300
999
|
const eventId = eventOutput.ids[0];
|
|
@@ -303,9 +1002,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
303
1002
|
}
|
|
304
1003
|
const runOutput = await this.getRunOutput(eventId);
|
|
305
1004
|
const result = runOutput?.output?.result;
|
|
306
|
-
|
|
307
|
-
result.error = new Error(result.error);
|
|
308
|
-
}
|
|
1005
|
+
this.hydrateFailedResult(result);
|
|
309
1006
|
return result;
|
|
310
1007
|
}
|
|
311
1008
|
watch(cb) {
|
|
@@ -334,14 +1031,13 @@ var InngestRun = class extends workflows.Run {
|
|
|
334
1031
|
streamLegacy({ inputData, requestContext } = {}) {
|
|
335
1032
|
const { readable, writable } = new TransformStream();
|
|
336
1033
|
const writer = writable.getWriter();
|
|
1034
|
+
void writer.write({
|
|
1035
|
+
// @ts-expect-error
|
|
1036
|
+
type: "start",
|
|
1037
|
+
payload: { runId: this.runId }
|
|
1038
|
+
});
|
|
337
1039
|
const unwatch = this.watch(async (event) => {
|
|
338
1040
|
try {
|
|
339
|
-
await writer.write({
|
|
340
|
-
// @ts-ignore
|
|
341
|
-
type: "start",
|
|
342
|
-
// @ts-ignore
|
|
343
|
-
payload: { runId: this.runId }
|
|
344
|
-
});
|
|
345
1041
|
const e = {
|
|
346
1042
|
...event,
|
|
347
1043
|
type: event.type.replace("workflow-", "")
|
|
@@ -357,7 +1053,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
357
1053
|
this.closeStreamAction = async () => {
|
|
358
1054
|
await writer.write({
|
|
359
1055
|
type: "finish",
|
|
360
|
-
// @ts-
|
|
1056
|
+
// @ts-expect-error
|
|
361
1057
|
payload: { runId: this.runId }
|
|
362
1058
|
});
|
|
363
1059
|
unwatch();
|
|
@@ -387,7 +1083,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
387
1083
|
tracingOptions,
|
|
388
1084
|
closeOnSuspend = true,
|
|
389
1085
|
initialState,
|
|
390
|
-
outputOptions
|
|
1086
|
+
outputOptions,
|
|
1087
|
+
perStep
|
|
391
1088
|
} = {}) {
|
|
392
1089
|
if (this.closeStreamAction && this.streamOutput) {
|
|
393
1090
|
return this.streamOutput;
|
|
@@ -423,7 +1120,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
423
1120
|
initialState,
|
|
424
1121
|
tracingOptions,
|
|
425
1122
|
outputOptions,
|
|
426
|
-
format: "vnext"
|
|
1123
|
+
format: "vnext",
|
|
1124
|
+
perStep
|
|
427
1125
|
});
|
|
428
1126
|
let executionResults;
|
|
429
1127
|
try {
|
|
@@ -454,9 +1152,6 @@ var InngestRun = class extends workflows.Run {
|
|
|
454
1152
|
});
|
|
455
1153
|
return this.streamOutput;
|
|
456
1154
|
}
|
|
457
|
-
streamVNext(args = {}) {
|
|
458
|
-
return this.stream(args);
|
|
459
|
-
}
|
|
460
1155
|
timeTravelStream({
|
|
461
1156
|
inputData,
|
|
462
1157
|
resumeData,
|
|
@@ -465,8 +1160,10 @@ var InngestRun = class extends workflows.Run {
|
|
|
465
1160
|
context,
|
|
466
1161
|
nestedStepsContext,
|
|
467
1162
|
requestContext,
|
|
1163
|
+
// tracingContext,
|
|
468
1164
|
tracingOptions,
|
|
469
|
-
outputOptions
|
|
1165
|
+
outputOptions,
|
|
1166
|
+
perStep
|
|
470
1167
|
}) {
|
|
471
1168
|
this.closeStreamAction = async () => {
|
|
472
1169
|
};
|
|
@@ -487,7 +1184,7 @@ var InngestRun = class extends workflows.Run {
|
|
|
487
1184
|
self.closeStreamAction = async () => {
|
|
488
1185
|
unwatch();
|
|
489
1186
|
try {
|
|
490
|
-
|
|
1187
|
+
controller.close();
|
|
491
1188
|
} catch (err) {
|
|
492
1189
|
console.error("Error closing stream:", err);
|
|
493
1190
|
}
|
|
@@ -501,7 +1198,8 @@ var InngestRun = class extends workflows.Run {
|
|
|
501
1198
|
initialState,
|
|
502
1199
|
requestContext,
|
|
503
1200
|
tracingOptions,
|
|
504
|
-
outputOptions
|
|
1201
|
+
outputOptions,
|
|
1202
|
+
perStep
|
|
505
1203
|
});
|
|
506
1204
|
self.executionResults = executionResultsPromise;
|
|
507
1205
|
let executionResults;
|
|
@@ -526,14 +1224,30 @@ var InngestRun = class extends workflows.Run {
|
|
|
526
1224
|
});
|
|
527
1225
|
return this.streamOutput;
|
|
528
1226
|
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Hydrates errors in a failed workflow result back to proper Error instances.
|
|
1229
|
+
* This ensures error.cause chains and custom properties are preserved.
|
|
1230
|
+
*/
|
|
1231
|
+
hydrateFailedResult(result) {
|
|
1232
|
+
if (result.status === "failed") {
|
|
1233
|
+
result.error = error.getErrorFromUnknown(result.error, { serializeStack: false });
|
|
1234
|
+
if (result.steps) {
|
|
1235
|
+
workflows.hydrateSerializedStepErrors(result.steps);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
529
1239
|
};
|
|
1240
|
+
|
|
1241
|
+
// src/workflow.ts
|
|
530
1242
|
var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
531
1243
|
#mastra;
|
|
532
1244
|
inngest;
|
|
533
1245
|
function;
|
|
1246
|
+
cronFunction;
|
|
534
1247
|
flowControlConfig;
|
|
1248
|
+
cronConfig;
|
|
535
1249
|
constructor(params, inngest) {
|
|
536
|
-
const { concurrency, rateLimit, throttle, debounce, priority, ...workflowParams } = params;
|
|
1250
|
+
const { concurrency, rateLimit, throttle, debounce, priority, cron, inputData, initialState, ...workflowParams } = params;
|
|
537
1251
|
super(workflowParams);
|
|
538
1252
|
this.engineType = "inngest";
|
|
539
1253
|
const flowControlEntries = Object.entries({ concurrency, rateLimit, throttle, debounce, priority }).filter(
|
|
@@ -542,6 +1256,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
542
1256
|
this.flowControlConfig = flowControlEntries.length > 0 ? Object.fromEntries(flowControlEntries) : void 0;
|
|
543
1257
|
this.#mastra = params.mastra;
|
|
544
1258
|
this.inngest = inngest;
|
|
1259
|
+
if (cron) {
|
|
1260
|
+
this.cronConfig = { cron, inputData, initialState };
|
|
1261
|
+
}
|
|
545
1262
|
}
|
|
546
1263
|
async listWorkflowRuns(args) {
|
|
547
1264
|
const storage = this.#mastra?.getStorage();
|
|
@@ -549,18 +1266,14 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
549
1266
|
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
550
1267
|
return { runs: [], total: 0 };
|
|
551
1268
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const storage = this.#mastra?.getStorage();
|
|
556
|
-
if (!storage) {
|
|
557
|
-
this.logger.debug("Cannot get workflow runs. Mastra engine is not initialized");
|
|
558
|
-
return this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null;
|
|
1269
|
+
const workflowsStore = await storage.getStore("workflows");
|
|
1270
|
+
if (!workflowsStore) {
|
|
1271
|
+
return { runs: [], total: 0 };
|
|
559
1272
|
}
|
|
560
|
-
|
|
561
|
-
return run ?? (this.runs.get(runId) ? { ...this.runs.get(runId), workflowName: this.id } : null);
|
|
1273
|
+
return workflowsStore.listWorkflowRuns({ workflowName: this.id, ...args ?? {} });
|
|
562
1274
|
}
|
|
563
1275
|
__registerMastra(mastra) {
|
|
1276
|
+
super.__registerMastra(mastra);
|
|
564
1277
|
this.#mastra = mastra;
|
|
565
1278
|
this.executionEngine.__registerMastra(mastra);
|
|
566
1279
|
const updateNested = (step) => {
|
|
@@ -579,8 +1292,9 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
579
1292
|
}
|
|
580
1293
|
}
|
|
581
1294
|
async createRun(options) {
|
|
582
|
-
const runIdToUse = options?.runId || crypto.randomUUID();
|
|
583
|
-
const
|
|
1295
|
+
const runIdToUse = options?.runId || crypto$1.randomUUID();
|
|
1296
|
+
const existingInMemoryRun = this.runs.get(runIdToUse);
|
|
1297
|
+
const newRun = new InngestRun(
|
|
584
1298
|
{
|
|
585
1299
|
workflowId: this.id,
|
|
586
1300
|
runId: runIdToUse,
|
|
@@ -597,14 +1311,19 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
597
1311
|
},
|
|
598
1312
|
this.inngest
|
|
599
1313
|
);
|
|
1314
|
+
const run = existingInMemoryRun ?? newRun;
|
|
600
1315
|
this.runs.set(runIdToUse, run);
|
|
601
1316
|
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({
|
|
602
1317
|
workflowStatus: run.workflowRunStatus,
|
|
603
1318
|
stepResults: {}
|
|
604
1319
|
});
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
1320
|
+
const existingStoredRun = await this.getWorkflowRunById(runIdToUse, {
|
|
1321
|
+
withNestedWorkflows: false
|
|
1322
|
+
});
|
|
1323
|
+
const existsInStorage = existingStoredRun && !existingStoredRun.isFromInMemory;
|
|
1324
|
+
if (!existsInStorage && shouldPersistSnapshot) {
|
|
1325
|
+
const workflowsStore = await this.mastra?.getStorage()?.getStore("workflows");
|
|
1326
|
+
await workflowsStore?.persistWorkflowSnapshot({
|
|
608
1327
|
workflowName: this.id,
|
|
609
1328
|
runId: runIdToUse,
|
|
610
1329
|
resourceId: options?.resourceId,
|
|
@@ -627,6 +1346,30 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
627
1346
|
}
|
|
628
1347
|
return run;
|
|
629
1348
|
}
|
|
1349
|
+
//createCronFunction is only called if cronConfig.cron is defined.
|
|
1350
|
+
createCronFunction() {
|
|
1351
|
+
if (this.cronFunction) {
|
|
1352
|
+
return this.cronFunction;
|
|
1353
|
+
}
|
|
1354
|
+
this.cronFunction = this.inngest.createFunction(
|
|
1355
|
+
{
|
|
1356
|
+
id: `workflow.${this.id}.cron`,
|
|
1357
|
+
retries: 0,
|
|
1358
|
+
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
1359
|
+
...this.flowControlConfig
|
|
1360
|
+
},
|
|
1361
|
+
{ cron: this.cronConfig?.cron ?? "" },
|
|
1362
|
+
async () => {
|
|
1363
|
+
const run = await this.createRun();
|
|
1364
|
+
const result = await run.start({
|
|
1365
|
+
inputData: this.cronConfig?.inputData,
|
|
1366
|
+
initialState: this.cronConfig?.initialState
|
|
1367
|
+
});
|
|
1368
|
+
return { result, runId: run.runId };
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
return this.cronFunction;
|
|
1372
|
+
}
|
|
630
1373
|
getFunction() {
|
|
631
1374
|
if (this.function) {
|
|
632
1375
|
return this.function;
|
|
@@ -634,68 +1377,128 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
634
1377
|
this.function = this.inngest.createFunction(
|
|
635
1378
|
{
|
|
636
1379
|
id: `workflow.${this.id}`,
|
|
637
|
-
retries:
|
|
1380
|
+
retries: 0,
|
|
638
1381
|
cancelOn: [{ event: `cancel.workflow.${this.id}` }],
|
|
639
1382
|
// Spread flow control configuration
|
|
640
1383
|
...this.flowControlConfig
|
|
641
1384
|
},
|
|
642
1385
|
{ event: `workflow.${this.id}` },
|
|
643
1386
|
async ({ event, step, attempt, publish }) => {
|
|
644
|
-
let {
|
|
1387
|
+
let {
|
|
1388
|
+
inputData,
|
|
1389
|
+
initialState,
|
|
1390
|
+
runId,
|
|
1391
|
+
resourceId,
|
|
1392
|
+
resume,
|
|
1393
|
+
outputOptions,
|
|
1394
|
+
format,
|
|
1395
|
+
timeTravel,
|
|
1396
|
+
perStep,
|
|
1397
|
+
tracingOptions
|
|
1398
|
+
} = event.data;
|
|
645
1399
|
if (!runId) {
|
|
646
1400
|
runId = await step.run(`workflow.${this.id}.runIdGen`, async () => {
|
|
647
|
-
return crypto.randomUUID();
|
|
1401
|
+
return crypto$1.randomUUID();
|
|
648
1402
|
});
|
|
649
1403
|
}
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
|
|
1404
|
+
const pubsub = new InngestPubSub(this.inngest, this.id, publish);
|
|
1405
|
+
const requestContext = new di.RequestContext(Object.entries(event.data.requestContext ?? {}));
|
|
1406
|
+
const mastra = this.#mastra;
|
|
1407
|
+
const tracingPolicy = this.options.tracingPolicy;
|
|
1408
|
+
const workflowSpanData = await step.run(`workflow.${this.id}.span.start`, async () => {
|
|
1409
|
+
const observability$1 = mastra?.observability?.getSelectedInstance({ requestContext });
|
|
1410
|
+
if (!observability$1) return void 0;
|
|
1411
|
+
const span = observability$1.startSpan({
|
|
1412
|
+
type: observability.SpanType.WORKFLOW_RUN,
|
|
1413
|
+
name: `workflow run: '${this.id}'`,
|
|
1414
|
+
entityType: observability.EntityType.WORKFLOW_RUN,
|
|
1415
|
+
entityId: this.id,
|
|
1416
|
+
input: inputData,
|
|
1417
|
+
metadata: {
|
|
1418
|
+
resourceId,
|
|
1419
|
+
runId
|
|
1420
|
+
},
|
|
1421
|
+
tracingPolicy,
|
|
1422
|
+
tracingOptions,
|
|
1423
|
+
requestContext
|
|
1424
|
+
});
|
|
1425
|
+
return span?.exportSpan();
|
|
1426
|
+
});
|
|
672
1427
|
const engine = new InngestExecutionEngine(this.#mastra, step, attempt, this.options);
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
1428
|
+
let result;
|
|
1429
|
+
try {
|
|
1430
|
+
result = await engine.execute({
|
|
1431
|
+
workflowId: this.id,
|
|
1432
|
+
runId,
|
|
1433
|
+
resourceId,
|
|
1434
|
+
graph: this.executionGraph,
|
|
1435
|
+
serializedStepGraph: this.serializedStepGraph,
|
|
1436
|
+
input: inputData,
|
|
1437
|
+
initialState,
|
|
1438
|
+
pubsub,
|
|
1439
|
+
retryConfig: this.retryConfig,
|
|
1440
|
+
requestContext,
|
|
1441
|
+
resume,
|
|
1442
|
+
timeTravel,
|
|
1443
|
+
perStep,
|
|
1444
|
+
format,
|
|
1445
|
+
abortController: new AbortController(),
|
|
1446
|
+
// For Inngest, we don't pass workflowSpan - step spans use tracingIds instead
|
|
1447
|
+
workflowSpan: void 0,
|
|
1448
|
+
// Pass tracing IDs for durable span operations
|
|
1449
|
+
tracingIds: workflowSpanData ? {
|
|
1450
|
+
traceId: workflowSpanData.traceId,
|
|
1451
|
+
workflowSpanId: workflowSpanData.id
|
|
1452
|
+
} : void 0,
|
|
1453
|
+
outputOptions,
|
|
1454
|
+
outputWriter: async (chunk) => {
|
|
1455
|
+
try {
|
|
1456
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1457
|
+
type: "watch",
|
|
1458
|
+
runId,
|
|
1459
|
+
data: chunk
|
|
1460
|
+
});
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
this.logger.debug?.("Failed to publish watch event:", err);
|
|
1463
|
+
}
|
|
695
1464
|
}
|
|
696
|
-
})
|
|
697
|
-
})
|
|
1465
|
+
});
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
throw error;
|
|
1468
|
+
}
|
|
698
1469
|
await step.run(`workflow.${this.id}.finalize`, async () => {
|
|
1470
|
+
if (result.status !== "paused") {
|
|
1471
|
+
await engine.invokeLifecycleCallbacksInternal({
|
|
1472
|
+
status: result.status,
|
|
1473
|
+
result: "result" in result ? result.result : void 0,
|
|
1474
|
+
error: "error" in result ? result.error : void 0,
|
|
1475
|
+
steps: result.steps,
|
|
1476
|
+
tripwire: "tripwire" in result ? result.tripwire : void 0,
|
|
1477
|
+
runId,
|
|
1478
|
+
workflowId: this.id,
|
|
1479
|
+
resourceId,
|
|
1480
|
+
input: inputData,
|
|
1481
|
+
requestContext,
|
|
1482
|
+
state: result.state ?? initialState ?? {}
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
if (workflowSpanData) {
|
|
1486
|
+
const observability = mastra?.observability?.getSelectedInstance({ requestContext });
|
|
1487
|
+
if (observability) {
|
|
1488
|
+
const workflowSpan = observability.rebuildSpan(workflowSpanData);
|
|
1489
|
+
if (result.status === "failed") {
|
|
1490
|
+
workflowSpan.error({
|
|
1491
|
+
error: result.error instanceof Error ? result.error : new Error(String(result.error)),
|
|
1492
|
+
attributes: { status: "failed" }
|
|
1493
|
+
});
|
|
1494
|
+
} else {
|
|
1495
|
+
workflowSpan.end({
|
|
1496
|
+
output: result.status === "success" ? result.result : void 0,
|
|
1497
|
+
attributes: { status: result.status }
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
699
1502
|
if (result.status === "failed") {
|
|
700
1503
|
throw new inngest.NonRetriableError(`Workflow failed`, {
|
|
701
1504
|
cause: result
|
|
@@ -722,147 +1525,203 @@ var InngestWorkflow = class _InngestWorkflow extends workflows.Workflow {
|
|
|
722
1525
|
});
|
|
723
1526
|
}
|
|
724
1527
|
getFunctions() {
|
|
725
|
-
return [
|
|
1528
|
+
return [
|
|
1529
|
+
this.getFunction(),
|
|
1530
|
+
...this.cronConfig?.cron ? [this.createCronFunction()] : [],
|
|
1531
|
+
...this.getNestedFunctions(this.executionGraph.steps)
|
|
1532
|
+
];
|
|
726
1533
|
}
|
|
727
1534
|
};
|
|
728
|
-
function
|
|
729
|
-
|
|
1535
|
+
function prepareServeOptions({ mastra, inngest, functions: userFunctions = [], registerOptions }) {
|
|
1536
|
+
const wfs = mastra.listWorkflows();
|
|
1537
|
+
const workflowFunctions = Array.from(
|
|
1538
|
+
new Set(
|
|
1539
|
+
Object.values(wfs).flatMap((wf) => {
|
|
1540
|
+
if (wf instanceof InngestWorkflow) {
|
|
1541
|
+
wf.__registerMastra(mastra);
|
|
1542
|
+
return wf.getFunctions();
|
|
1543
|
+
}
|
|
1544
|
+
return [];
|
|
1545
|
+
})
|
|
1546
|
+
)
|
|
1547
|
+
);
|
|
1548
|
+
return {
|
|
1549
|
+
...registerOptions,
|
|
1550
|
+
client: inngest,
|
|
1551
|
+
functions: [...workflowFunctions, ...userFunctions]
|
|
1552
|
+
};
|
|
730
1553
|
}
|
|
731
|
-
function
|
|
732
|
-
return
|
|
1554
|
+
function createServe(adapter) {
|
|
1555
|
+
return (options) => {
|
|
1556
|
+
const serveOptions = prepareServeOptions(options);
|
|
1557
|
+
return adapter(serveOptions);
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
var serve = createServe(hono.serve);
|
|
1561
|
+
|
|
1562
|
+
// src/types.ts
|
|
1563
|
+
var _compatibilityCheck = true;
|
|
1564
|
+
|
|
1565
|
+
// src/index.ts
|
|
1566
|
+
function isInngestWorkflow(input) {
|
|
1567
|
+
return input instanceof InngestWorkflow;
|
|
1568
|
+
}
|
|
1569
|
+
function isAgent(input) {
|
|
1570
|
+
return input instanceof agent.Agent;
|
|
1571
|
+
}
|
|
1572
|
+
function isToolStep(input) {
|
|
1573
|
+
return input instanceof tools.Tool;
|
|
1574
|
+
}
|
|
1575
|
+
function isStepParams(input) {
|
|
1576
|
+
return input !== null && typeof input === "object" && "id" in input && "execute" in input && !(input instanceof agent.Agent) && !(input instanceof tools.Tool) && !(input instanceof InngestWorkflow);
|
|
733
1577
|
}
|
|
734
|
-
function
|
|
1578
|
+
function isProcessor(obj) {
|
|
1579
|
+
return obj !== null && typeof obj === "object" && "id" in obj && typeof obj.id === "string" && !(obj instanceof agent.Agent) && !(obj instanceof tools.Tool) && !(obj instanceof InngestWorkflow) && (typeof obj.processInput === "function" || typeof obj.processInputStep === "function" || typeof obj.processOutputStream === "function" || typeof obj.processOutputResult === "function" || typeof obj.processOutputStep === "function");
|
|
1580
|
+
}
|
|
1581
|
+
function createStep(params, agentOrToolOptions) {
|
|
1582
|
+
if (isInngestWorkflow(params)) {
|
|
1583
|
+
return params;
|
|
1584
|
+
}
|
|
735
1585
|
if (isAgent(params)) {
|
|
736
|
-
return
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1586
|
+
return createStepFromAgent(params, agentOrToolOptions);
|
|
1587
|
+
}
|
|
1588
|
+
if (isToolStep(params)) {
|
|
1589
|
+
return createStepFromTool(params, agentOrToolOptions);
|
|
1590
|
+
}
|
|
1591
|
+
if (isStepParams(params)) {
|
|
1592
|
+
return createStepFromParams(params);
|
|
1593
|
+
}
|
|
1594
|
+
if (isProcessor(params)) {
|
|
1595
|
+
return createStepFromProcessor(params);
|
|
1596
|
+
}
|
|
1597
|
+
throw new Error("Invalid input: expected StepParams, Agent, ToolStep, Processor, or InngestWorkflow");
|
|
1598
|
+
}
|
|
1599
|
+
function createStepFromParams(params) {
|
|
1600
|
+
return {
|
|
1601
|
+
id: params.id,
|
|
1602
|
+
description: params.description,
|
|
1603
|
+
inputSchema: schema.toStandardSchema(params.inputSchema),
|
|
1604
|
+
stateSchema: params.stateSchema ? schema.toStandardSchema(params.stateSchema) : void 0,
|
|
1605
|
+
outputSchema: schema.toStandardSchema(params.outputSchema),
|
|
1606
|
+
resumeSchema: params.resumeSchema ? schema.toStandardSchema(params.resumeSchema) : void 0,
|
|
1607
|
+
suspendSchema: params.suspendSchema ? schema.toStandardSchema(params.suspendSchema) : void 0,
|
|
1608
|
+
scorers: params.scorers,
|
|
1609
|
+
retries: params.retries,
|
|
1610
|
+
execute: params.execute.bind(params)
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function createStepFromAgent(params, agentOrToolOptions) {
|
|
1614
|
+
const options = agentOrToolOptions ?? {};
|
|
1615
|
+
const outputSchema = options?.structuredOutput?.schema ?? zod.z.object({ text: zod.z.string() });
|
|
1616
|
+
const { retries, scorers, ...agentOptions } = options ?? {};
|
|
1617
|
+
return {
|
|
1618
|
+
id: params.name,
|
|
1619
|
+
description: params.getDescription(),
|
|
1620
|
+
inputSchema: schema.toStandardSchema(
|
|
1621
|
+
zod.z.object({
|
|
740
1622
|
prompt: zod.z.string()
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
1623
|
+
})
|
|
1624
|
+
),
|
|
1625
|
+
outputSchema: schema.toStandardSchema(outputSchema),
|
|
1626
|
+
retries,
|
|
1627
|
+
scorers,
|
|
1628
|
+
execute: async ({
|
|
1629
|
+
inputData,
|
|
1630
|
+
runId,
|
|
1631
|
+
[_constants.PUBSUB_SYMBOL]: pubsub,
|
|
1632
|
+
[_constants.STREAM_FORMAT_SYMBOL]: streamFormat,
|
|
1633
|
+
requestContext,
|
|
1634
|
+
tracingContext,
|
|
1635
|
+
abortSignal,
|
|
1636
|
+
abort,
|
|
1637
|
+
writer
|
|
1638
|
+
}) => {
|
|
1639
|
+
let streamPromise = {};
|
|
1640
|
+
streamPromise.promise = new Promise((resolve, reject) => {
|
|
1641
|
+
streamPromise.resolve = resolve;
|
|
1642
|
+
streamPromise.reject = reject;
|
|
1643
|
+
});
|
|
1644
|
+
let structuredResult = null;
|
|
1645
|
+
const toolData = {
|
|
1646
|
+
name: params.name,
|
|
1647
|
+
args: inputData
|
|
1648
|
+
};
|
|
1649
|
+
let stream;
|
|
1650
|
+
if ((await params.getModel()).specificationVersion === "v1") {
|
|
1651
|
+
const { fullStream } = await params.streamLegacy(inputData.prompt, {
|
|
1652
|
+
...agentOptions ?? {},
|
|
1653
|
+
requestContext,
|
|
1654
|
+
tracingContext,
|
|
1655
|
+
onFinish: (result) => {
|
|
1656
|
+
const resultWithObject = result;
|
|
1657
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1658
|
+
structuredResult = resultWithObject.object;
|
|
1659
|
+
}
|
|
1660
|
+
streamPromise.resolve(result.text);
|
|
1661
|
+
void agentOptions?.onFinish?.(result);
|
|
1662
|
+
},
|
|
1663
|
+
abortSignal
|
|
761
1664
|
});
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
requestContext,
|
|
773
|
-
tracingContext,
|
|
774
|
-
onFinish: (result) => {
|
|
775
|
-
streamPromise.resolve(result.text);
|
|
776
|
-
void agentOptions?.onFinish?.(result);
|
|
777
|
-
},
|
|
778
|
-
abortSignal
|
|
779
|
-
});
|
|
780
|
-
stream = fullStream;
|
|
781
|
-
} else {
|
|
782
|
-
const modelOutput = await params.stream(inputData.prompt, {
|
|
783
|
-
...agentOptions ?? {},
|
|
784
|
-
requestContext,
|
|
785
|
-
tracingContext,
|
|
786
|
-
onFinish: (result) => {
|
|
787
|
-
streamPromise.resolve(result.text);
|
|
788
|
-
void agentOptions?.onFinish?.(result);
|
|
789
|
-
},
|
|
790
|
-
abortSignal
|
|
791
|
-
});
|
|
792
|
-
stream = modelOutput.fullStream;
|
|
793
|
-
}
|
|
794
|
-
if (streamFormat === "legacy") {
|
|
795
|
-
await emitter.emit("watch", {
|
|
796
|
-
type: "tool-call-streaming-start",
|
|
797
|
-
...toolData ?? {}
|
|
798
|
-
});
|
|
799
|
-
for await (const chunk of stream) {
|
|
800
|
-
if (chunk.type === "text-delta") {
|
|
801
|
-
await emitter.emit("watch", {
|
|
802
|
-
type: "tool-call-delta",
|
|
803
|
-
...toolData ?? {},
|
|
804
|
-
argsTextDelta: chunk.textDelta
|
|
805
|
-
});
|
|
1665
|
+
stream = fullStream;
|
|
1666
|
+
} else {
|
|
1667
|
+
const modelOutput = await params.stream(inputData.prompt, {
|
|
1668
|
+
...agentOptions ?? {},
|
|
1669
|
+
requestContext,
|
|
1670
|
+
tracingContext,
|
|
1671
|
+
onFinish: (result) => {
|
|
1672
|
+
const resultWithObject = result;
|
|
1673
|
+
if (agentOptions?.structuredOutput?.schema && resultWithObject.object) {
|
|
1674
|
+
structuredResult = resultWithObject.object;
|
|
806
1675
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
1676
|
+
streamPromise.resolve(result.text);
|
|
1677
|
+
void agentOptions?.onFinish?.(result);
|
|
1678
|
+
},
|
|
1679
|
+
abortSignal
|
|
1680
|
+
});
|
|
1681
|
+
stream = modelOutput.fullStream;
|
|
1682
|
+
}
|
|
1683
|
+
if (streamFormat === "legacy") {
|
|
1684
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1685
|
+
type: "watch",
|
|
1686
|
+
runId,
|
|
1687
|
+
data: { type: "tool-call-streaming-start", ...toolData ?? {} }
|
|
1688
|
+
});
|
|
1689
|
+
for await (const chunk of stream) {
|
|
1690
|
+
if (chunk.type === "text-delta") {
|
|
1691
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1692
|
+
type: "watch",
|
|
1693
|
+
runId,
|
|
1694
|
+
data: { type: "tool-call-delta", ...toolData ?? {}, argsTextDelta: chunk.textDelta }
|
|
1695
|
+
});
|
|
815
1696
|
}
|
|
816
1697
|
}
|
|
817
|
-
|
|
818
|
-
|
|
1698
|
+
await pubsub.publish(`workflow.events.v2.${runId}`, {
|
|
1699
|
+
type: "watch",
|
|
1700
|
+
runId,
|
|
1701
|
+
data: { type: "tool-call-streaming-finish", ...toolData ?? {} }
|
|
1702
|
+
});
|
|
1703
|
+
} else {
|
|
1704
|
+
for await (const chunk of stream) {
|
|
1705
|
+
await writer.write(chunk);
|
|
819
1706
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
inputData,
|
|
839
|
-
mastra,
|
|
840
|
-
requestContext,
|
|
841
|
-
tracingContext,
|
|
842
|
-
suspend,
|
|
843
|
-
resumeData,
|
|
844
|
-
runId,
|
|
845
|
-
workflowId,
|
|
846
|
-
state,
|
|
847
|
-
setState
|
|
848
|
-
}) => {
|
|
849
|
-
const toolContext = {
|
|
850
|
-
mastra,
|
|
851
|
-
requestContext,
|
|
852
|
-
tracingContext,
|
|
853
|
-
resumeData,
|
|
854
|
-
workflow: {
|
|
855
|
-
runId,
|
|
856
|
-
suspend,
|
|
857
|
-
workflowId,
|
|
858
|
-
state,
|
|
859
|
-
setState
|
|
860
|
-
}
|
|
861
|
-
};
|
|
862
|
-
return params.execute(inputData, toolContext);
|
|
863
|
-
},
|
|
864
|
-
component: "TOOL"
|
|
865
|
-
};
|
|
1707
|
+
}
|
|
1708
|
+
if (abortSignal.aborted) {
|
|
1709
|
+
return abort();
|
|
1710
|
+
}
|
|
1711
|
+
if (structuredResult !== null) {
|
|
1712
|
+
return structuredResult;
|
|
1713
|
+
}
|
|
1714
|
+
return {
|
|
1715
|
+
text: await streamPromise.promise
|
|
1716
|
+
};
|
|
1717
|
+
},
|
|
1718
|
+
component: params.component
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
function createStepFromTool(params, agentOrToolOptions) {
|
|
1722
|
+
const toolOpts = agentOrToolOptions;
|
|
1723
|
+
if (!params.inputSchema || !params.outputSchema) {
|
|
1724
|
+
throw new Error("Tool must have input and output schemas defined");
|
|
866
1725
|
}
|
|
867
1726
|
return {
|
|
868
1727
|
id: params.id,
|
|
@@ -871,890 +1730,528 @@ function createStep(params, agentOptions) {
|
|
|
871
1730
|
outputSchema: params.outputSchema,
|
|
872
1731
|
resumeSchema: params.resumeSchema,
|
|
873
1732
|
suspendSchema: params.suspendSchema,
|
|
874
|
-
|
|
1733
|
+
retries: toolOpts?.retries,
|
|
1734
|
+
scorers: toolOpts?.scorers,
|
|
1735
|
+
execute: async ({
|
|
1736
|
+
inputData,
|
|
1737
|
+
mastra,
|
|
1738
|
+
requestContext,
|
|
1739
|
+
tracingContext,
|
|
1740
|
+
suspend,
|
|
1741
|
+
resumeData,
|
|
1742
|
+
runId,
|
|
1743
|
+
workflowId,
|
|
1744
|
+
state,
|
|
1745
|
+
setState
|
|
1746
|
+
}) => {
|
|
1747
|
+
const toolContext = {
|
|
1748
|
+
mastra,
|
|
1749
|
+
requestContext,
|
|
1750
|
+
tracingContext,
|
|
1751
|
+
workflow: {
|
|
1752
|
+
runId,
|
|
1753
|
+
resumeData,
|
|
1754
|
+
suspend,
|
|
1755
|
+
workflowId,
|
|
1756
|
+
state,
|
|
1757
|
+
setState
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
return params.execute(inputData, toolContext);
|
|
1761
|
+
},
|
|
1762
|
+
component: "TOOL"
|
|
875
1763
|
};
|
|
876
1764
|
}
|
|
877
|
-
function
|
|
1765
|
+
function createStepFromProcessor(processor) {
|
|
1766
|
+
const getProcessorEntityType = (phase) => {
|
|
1767
|
+
switch (phase) {
|
|
1768
|
+
case "input":
|
|
1769
|
+
return observability.EntityType.INPUT_PROCESSOR;
|
|
1770
|
+
case "inputStep":
|
|
1771
|
+
return observability.EntityType.INPUT_STEP_PROCESSOR;
|
|
1772
|
+
case "outputStream":
|
|
1773
|
+
case "outputResult":
|
|
1774
|
+
return observability.EntityType.OUTPUT_PROCESSOR;
|
|
1775
|
+
case "outputStep":
|
|
1776
|
+
return observability.EntityType.OUTPUT_STEP_PROCESSOR;
|
|
1777
|
+
default:
|
|
1778
|
+
return observability.EntityType.OUTPUT_PROCESSOR;
|
|
1779
|
+
}
|
|
1780
|
+
};
|
|
1781
|
+
const getSpanNamePrefix = (phase) => {
|
|
1782
|
+
switch (phase) {
|
|
1783
|
+
case "input":
|
|
1784
|
+
return "input processor";
|
|
1785
|
+
case "inputStep":
|
|
1786
|
+
return "input step processor";
|
|
1787
|
+
case "outputStream":
|
|
1788
|
+
return "output stream processor";
|
|
1789
|
+
case "outputResult":
|
|
1790
|
+
return "output processor";
|
|
1791
|
+
case "outputStep":
|
|
1792
|
+
return "output step processor";
|
|
1793
|
+
default:
|
|
1794
|
+
return "processor";
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
const hasPhaseMethod = (phase) => {
|
|
1798
|
+
switch (phase) {
|
|
1799
|
+
case "input":
|
|
1800
|
+
return !!processor.processInput;
|
|
1801
|
+
case "inputStep":
|
|
1802
|
+
return !!processor.processInputStep;
|
|
1803
|
+
case "outputStream":
|
|
1804
|
+
return !!processor.processOutputStream;
|
|
1805
|
+
case "outputResult":
|
|
1806
|
+
return !!processor.processOutputResult;
|
|
1807
|
+
case "outputStep":
|
|
1808
|
+
return !!processor.processOutputStep;
|
|
1809
|
+
default:
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
};
|
|
878
1813
|
return {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1814
|
+
id: `processor:${processor.id}`,
|
|
1815
|
+
description: processor.name ?? `Processor ${processor.id}`,
|
|
1816
|
+
inputSchema: processors.ProcessorStepSchema,
|
|
1817
|
+
outputSchema: processors.ProcessorStepOutputSchema,
|
|
1818
|
+
execute: async ({ inputData, requestContext, tracingContext }) => {
|
|
1819
|
+
const input = inputData;
|
|
1820
|
+
const {
|
|
1821
|
+
phase,
|
|
1822
|
+
messages,
|
|
1823
|
+
messageList,
|
|
1824
|
+
stepNumber,
|
|
1825
|
+
systemMessages,
|
|
1826
|
+
part,
|
|
1827
|
+
streamParts,
|
|
1828
|
+
state,
|
|
1829
|
+
finishReason,
|
|
1830
|
+
toolCalls,
|
|
1831
|
+
text,
|
|
1832
|
+
retryCount,
|
|
1833
|
+
// inputStep phase fields for model/tools configuration
|
|
1834
|
+
model,
|
|
1835
|
+
tools,
|
|
1836
|
+
toolChoice,
|
|
1837
|
+
activeTools,
|
|
1838
|
+
providerOptions,
|
|
1839
|
+
modelSettings,
|
|
1840
|
+
structuredOutput,
|
|
1841
|
+
steps
|
|
1842
|
+
} = input;
|
|
1843
|
+
const abort = (reason, options) => {
|
|
1844
|
+
throw new agent.TripWire(reason || `Tripwire triggered by ${processor.id}`, options, processor.id);
|
|
899
1845
|
};
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
const wf = new workflows.Workflow({
|
|
903
|
-
id: opts.id,
|
|
904
|
-
inputSchema: workflow.inputSchema,
|
|
905
|
-
outputSchema: workflow.outputSchema,
|
|
906
|
-
steps: workflow.stepDefs,
|
|
907
|
-
mastra: workflow.mastra
|
|
908
|
-
});
|
|
909
|
-
wf.setStepFlow(workflow.stepGraph);
|
|
910
|
-
wf.commit();
|
|
911
|
-
return wf;
|
|
912
|
-
}
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
var InngestExecutionEngine = class extends workflows.DefaultExecutionEngine {
|
|
916
|
-
inngestStep;
|
|
917
|
-
inngestAttempts;
|
|
918
|
-
constructor(mastra, inngestStep, inngestAttempts = 0, options) {
|
|
919
|
-
super({ mastra, options });
|
|
920
|
-
this.inngestStep = inngestStep;
|
|
921
|
-
this.inngestAttempts = inngestAttempts;
|
|
922
|
-
}
|
|
923
|
-
async fmtReturnValue(emitter, stepResults, lastOutput, error) {
|
|
924
|
-
const base = {
|
|
925
|
-
status: lastOutput.status,
|
|
926
|
-
steps: stepResults
|
|
927
|
-
};
|
|
928
|
-
if (lastOutput.status === "success") {
|
|
929
|
-
base.result = lastOutput.output;
|
|
930
|
-
} else if (lastOutput.status === "failed") {
|
|
931
|
-
base.error = error instanceof Error ? error?.stack ?? error.message : lastOutput?.error instanceof Error ? lastOutput.error.message : lastOutput.error ?? error ?? "Unknown error";
|
|
932
|
-
} else if (lastOutput.status === "suspended") {
|
|
933
|
-
const suspendedStepIds = Object.entries(stepResults).flatMap(([stepId, stepResult]) => {
|
|
934
|
-
if (stepResult?.status === "suspended") {
|
|
935
|
-
const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
|
|
936
|
-
return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
|
|
937
|
-
}
|
|
938
|
-
return [];
|
|
939
|
-
});
|
|
940
|
-
base.suspended = suspendedStepIds;
|
|
941
|
-
}
|
|
942
|
-
return base;
|
|
943
|
-
}
|
|
944
|
-
// async executeSleep({ id, duration }: { id: string; duration: number }): Promise<void> {
|
|
945
|
-
// await this.inngestStep.sleep(id, duration);
|
|
946
|
-
// }
|
|
947
|
-
async executeSleep({
|
|
948
|
-
workflowId,
|
|
949
|
-
runId,
|
|
950
|
-
entry,
|
|
951
|
-
prevOutput,
|
|
952
|
-
stepResults,
|
|
953
|
-
emitter,
|
|
954
|
-
abortController,
|
|
955
|
-
requestContext,
|
|
956
|
-
executionContext,
|
|
957
|
-
writableStream,
|
|
958
|
-
tracingContext
|
|
959
|
-
}) {
|
|
960
|
-
let { duration, fn } = entry;
|
|
961
|
-
const sleepSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
962
|
-
type: observability.SpanType.WORKFLOW_SLEEP,
|
|
963
|
-
name: `sleep: ${duration ? `${duration}ms` : "dynamic"}`,
|
|
964
|
-
attributes: {
|
|
965
|
-
durationMs: duration,
|
|
966
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
967
|
-
},
|
|
968
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
969
|
-
});
|
|
970
|
-
if (fn) {
|
|
971
|
-
const stepCallId = crypto.randomUUID();
|
|
972
|
-
duration = await this.inngestStep.run(`workflow.${workflowId}.sleep.${entry.id}`, async () => {
|
|
973
|
-
return await fn(
|
|
974
|
-
workflows.createDeprecationProxy(
|
|
975
|
-
{
|
|
976
|
-
runId,
|
|
977
|
-
workflowId,
|
|
978
|
-
mastra: this.mastra,
|
|
979
|
-
requestContext,
|
|
980
|
-
inputData: prevOutput,
|
|
981
|
-
state: executionContext.state,
|
|
982
|
-
setState: (state) => {
|
|
983
|
-
executionContext.state = state;
|
|
984
|
-
},
|
|
985
|
-
retryCount: -1,
|
|
986
|
-
tracingContext: {
|
|
987
|
-
currentSpan: sleepSpan
|
|
988
|
-
},
|
|
989
|
-
getInitData: () => stepResults?.input,
|
|
990
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
991
|
-
// TODO: this function shouldn't have suspend probably?
|
|
992
|
-
suspend: async (_suspendPayload) => {
|
|
993
|
-
},
|
|
994
|
-
bail: () => {
|
|
995
|
-
},
|
|
996
|
-
abort: () => {
|
|
997
|
-
abortController?.abort();
|
|
998
|
-
},
|
|
999
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1000
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1001
|
-
engine: { step: this.inngestStep },
|
|
1002
|
-
abortSignal: abortController?.signal,
|
|
1003
|
-
writer: new tools.ToolStream(
|
|
1004
|
-
{
|
|
1005
|
-
prefix: "workflow-step",
|
|
1006
|
-
callId: stepCallId,
|
|
1007
|
-
name: "sleep",
|
|
1008
|
-
runId
|
|
1009
|
-
},
|
|
1010
|
-
writableStream
|
|
1011
|
-
)
|
|
1012
|
-
},
|
|
1013
|
-
{
|
|
1014
|
-
paramName: "runCount",
|
|
1015
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1016
|
-
logger: this.logger
|
|
1017
|
-
}
|
|
1018
|
-
)
|
|
1019
|
-
);
|
|
1020
|
-
});
|
|
1021
|
-
sleepSpan?.update({
|
|
1022
|
-
attributes: {
|
|
1023
|
-
durationMs: duration
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
try {
|
|
1028
|
-
await this.inngestStep.sleep(entry.id, !duration || duration < 0 ? 0 : duration);
|
|
1029
|
-
sleepSpan?.end();
|
|
1030
|
-
} catch (e) {
|
|
1031
|
-
sleepSpan?.error({ error: e });
|
|
1032
|
-
throw e;
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
async executeSleepUntil({
|
|
1036
|
-
workflowId,
|
|
1037
|
-
runId,
|
|
1038
|
-
entry,
|
|
1039
|
-
prevOutput,
|
|
1040
|
-
stepResults,
|
|
1041
|
-
emitter,
|
|
1042
|
-
abortController,
|
|
1043
|
-
requestContext,
|
|
1044
|
-
executionContext,
|
|
1045
|
-
writableStream,
|
|
1046
|
-
tracingContext
|
|
1047
|
-
}) {
|
|
1048
|
-
let { date, fn } = entry;
|
|
1049
|
-
const sleepUntilSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1050
|
-
type: observability.SpanType.WORKFLOW_SLEEP,
|
|
1051
|
-
name: `sleepUntil: ${date ? date.toISOString() : "dynamic"}`,
|
|
1052
|
-
attributes: {
|
|
1053
|
-
untilDate: date,
|
|
1054
|
-
durationMs: date ? Math.max(0, date.getTime() - Date.now()) : void 0,
|
|
1055
|
-
sleepType: fn ? "dynamic" : "fixed"
|
|
1056
|
-
},
|
|
1057
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1058
|
-
});
|
|
1059
|
-
if (fn) {
|
|
1060
|
-
date = await this.inngestStep.run(`workflow.${workflowId}.sleepUntil.${entry.id}`, async () => {
|
|
1061
|
-
const stepCallId = crypto.randomUUID();
|
|
1062
|
-
return await fn(
|
|
1063
|
-
workflows.createDeprecationProxy(
|
|
1064
|
-
{
|
|
1065
|
-
runId,
|
|
1066
|
-
workflowId,
|
|
1067
|
-
mastra: this.mastra,
|
|
1068
|
-
requestContext,
|
|
1069
|
-
inputData: prevOutput,
|
|
1070
|
-
state: executionContext.state,
|
|
1071
|
-
setState: (state) => {
|
|
1072
|
-
executionContext.state = state;
|
|
1073
|
-
},
|
|
1074
|
-
retryCount: -1,
|
|
1075
|
-
tracingContext: {
|
|
1076
|
-
currentSpan: sleepUntilSpan
|
|
1077
|
-
},
|
|
1078
|
-
getInitData: () => stepResults?.input,
|
|
1079
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1080
|
-
// TODO: this function shouldn't have suspend probably?
|
|
1081
|
-
suspend: async (_suspendPayload) => {
|
|
1082
|
-
},
|
|
1083
|
-
bail: () => {
|
|
1084
|
-
},
|
|
1085
|
-
abort: () => {
|
|
1086
|
-
abortController?.abort();
|
|
1087
|
-
},
|
|
1088
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1089
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1090
|
-
engine: { step: this.inngestStep },
|
|
1091
|
-
abortSignal: abortController?.signal,
|
|
1092
|
-
writer: new tools.ToolStream(
|
|
1093
|
-
{
|
|
1094
|
-
prefix: "workflow-step",
|
|
1095
|
-
callId: stepCallId,
|
|
1096
|
-
name: "sleep",
|
|
1097
|
-
runId
|
|
1098
|
-
},
|
|
1099
|
-
writableStream
|
|
1100
|
-
)
|
|
1101
|
-
},
|
|
1102
|
-
{
|
|
1103
|
-
paramName: "runCount",
|
|
1104
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1105
|
-
logger: this.logger
|
|
1106
|
-
}
|
|
1107
|
-
)
|
|
1108
|
-
);
|
|
1109
|
-
});
|
|
1110
|
-
if (date && !(date instanceof Date)) {
|
|
1111
|
-
date = new Date(date);
|
|
1846
|
+
if (!hasPhaseMethod(phase)) {
|
|
1847
|
+
return input;
|
|
1112
1848
|
}
|
|
1113
|
-
const
|
|
1114
|
-
|
|
1849
|
+
const currentSpan = tracingContext?.currentSpan;
|
|
1850
|
+
const parentSpan = phase === "inputStep" || phase === "outputStep" ? currentSpan?.findParent(observability.SpanType.MODEL_STEP) || currentSpan : currentSpan?.findParent(observability.SpanType.AGENT_RUN) || currentSpan;
|
|
1851
|
+
const processorSpan = phase !== "outputStream" ? parentSpan?.createChildSpan({
|
|
1852
|
+
type: observability.SpanType.PROCESSOR_RUN,
|
|
1853
|
+
name: `${getSpanNamePrefix(phase)}: ${processor.id}`,
|
|
1854
|
+
entityType: getProcessorEntityType(phase),
|
|
1855
|
+
entityId: processor.id,
|
|
1856
|
+
entityName: processor.name ?? processor.id,
|
|
1857
|
+
input: { phase, messageCount: messages?.length },
|
|
1115
1858
|
attributes: {
|
|
1116
|
-
|
|
1859
|
+
processorExecutor: "workflow",
|
|
1860
|
+
// Read processorIndex from processor (set in combineProcessorsIntoWorkflow)
|
|
1861
|
+
processorIndex: processor.processorIndex
|
|
1117
1862
|
}
|
|
1118
|
-
});
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
});
|
|
1160
|
-
const startedAt = await this.inngestStep.run(
|
|
1161
|
-
`workflow.${executionContext.workflowId}.run.${executionContext.runId}.step.${step.id}.running_ev`,
|
|
1162
|
-
async () => {
|
|
1163
|
-
const startedAt2 = Date.now();
|
|
1164
|
-
await emitter.emit("watch", {
|
|
1165
|
-
type: "workflow-step-start",
|
|
1166
|
-
payload: {
|
|
1167
|
-
id: step.id,
|
|
1168
|
-
status: "running",
|
|
1169
|
-
payload: inputData,
|
|
1170
|
-
startedAt: startedAt2
|
|
1863
|
+
}) : void 0;
|
|
1864
|
+
const processorTracingContext = processorSpan ? { currentSpan: processorSpan } : tracingContext;
|
|
1865
|
+
const baseContext = {
|
|
1866
|
+
abort,
|
|
1867
|
+
retryCount: retryCount ?? 0,
|
|
1868
|
+
requestContext,
|
|
1869
|
+
tracingContext: processorTracingContext
|
|
1870
|
+
};
|
|
1871
|
+
const passThrough = {
|
|
1872
|
+
phase,
|
|
1873
|
+
// Auto-create MessageList from messages if not provided
|
|
1874
|
+
// This enables running processor workflows from the UI where messageList can't be serialized
|
|
1875
|
+
messageList: messageList ?? (Array.isArray(messages) ? new agent.MessageList().add(messages, "input").addSystem(systemMessages ?? []) : void 0),
|
|
1876
|
+
stepNumber,
|
|
1877
|
+
systemMessages,
|
|
1878
|
+
streamParts,
|
|
1879
|
+
state,
|
|
1880
|
+
finishReason,
|
|
1881
|
+
toolCalls,
|
|
1882
|
+
text,
|
|
1883
|
+
retryCount,
|
|
1884
|
+
// inputStep phase fields for model/tools configuration
|
|
1885
|
+
model,
|
|
1886
|
+
tools,
|
|
1887
|
+
toolChoice,
|
|
1888
|
+
activeTools,
|
|
1889
|
+
providerOptions,
|
|
1890
|
+
modelSettings,
|
|
1891
|
+
structuredOutput,
|
|
1892
|
+
steps
|
|
1893
|
+
};
|
|
1894
|
+
const executePhaseWithSpan = async (fn) => {
|
|
1895
|
+
try {
|
|
1896
|
+
const result = await fn();
|
|
1897
|
+
processorSpan?.end({ output: result });
|
|
1898
|
+
return result;
|
|
1899
|
+
} catch (error) {
|
|
1900
|
+
if (error instanceof agent.TripWire) {
|
|
1901
|
+
processorSpan?.end({ output: { tripwire: error.message } });
|
|
1902
|
+
} else {
|
|
1903
|
+
processorSpan?.error({ error, endSpan: true });
|
|
1171
1904
|
}
|
|
1172
|
-
|
|
1173
|
-
return startedAt2;
|
|
1174
|
-
}
|
|
1175
|
-
);
|
|
1176
|
-
if (step instanceof InngestWorkflow) {
|
|
1177
|
-
const isResume = !!resume?.steps?.length;
|
|
1178
|
-
let result;
|
|
1179
|
-
let runId;
|
|
1180
|
-
const isTimeTravel = !!(timeTravel && timeTravel.steps?.length > 1 && timeTravel.steps[0] === step.id);
|
|
1181
|
-
try {
|
|
1182
|
-
if (isResume) {
|
|
1183
|
-
runId = stepResults[resume?.steps?.[0] ?? ""]?.suspendPayload?.__workflow_meta?.runId ?? crypto.randomUUID();
|
|
1184
|
-
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1185
|
-
workflowName: step.id,
|
|
1186
|
-
runId
|
|
1187
|
-
});
|
|
1188
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1189
|
-
function: step.getFunction(),
|
|
1190
|
-
data: {
|
|
1191
|
-
inputData,
|
|
1192
|
-
initialState: executionContext.state ?? snapshot?.value ?? {},
|
|
1193
|
-
runId,
|
|
1194
|
-
resume: {
|
|
1195
|
-
runId,
|
|
1196
|
-
steps: resume.steps.slice(1),
|
|
1197
|
-
stepResults: snapshot?.context,
|
|
1198
|
-
resumePayload: resume.resumePayload,
|
|
1199
|
-
resumePath: resume.steps?.[1] ? snapshot?.suspendedPaths?.[resume.steps?.[1]] : void 0
|
|
1200
|
-
},
|
|
1201
|
-
outputOptions: { includeState: true }
|
|
1202
|
-
}
|
|
1203
|
-
});
|
|
1204
|
-
result = invokeResp.result;
|
|
1205
|
-
runId = invokeResp.runId;
|
|
1206
|
-
executionContext.state = invokeResp.result.state;
|
|
1207
|
-
} else if (isTimeTravel) {
|
|
1208
|
-
const snapshot = await this.mastra?.getStorage()?.loadWorkflowSnapshot({
|
|
1209
|
-
workflowName: step.id,
|
|
1210
|
-
runId: executionContext.runId
|
|
1211
|
-
}) ?? { context: {} };
|
|
1212
|
-
const timeTravelParams = workflows.createTimeTravelExecutionParams({
|
|
1213
|
-
steps: timeTravel.steps.slice(1),
|
|
1214
|
-
inputData: timeTravel.inputData,
|
|
1215
|
-
resumeData: timeTravel.resumeData,
|
|
1216
|
-
context: timeTravel.nestedStepResults?.[step.id] ?? {},
|
|
1217
|
-
nestedStepsContext: timeTravel.nestedStepResults ?? {},
|
|
1218
|
-
snapshot,
|
|
1219
|
-
graph: step.buildExecutionGraph()
|
|
1220
|
-
});
|
|
1221
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1222
|
-
function: step.getFunction(),
|
|
1223
|
-
data: {
|
|
1224
|
-
timeTravel: timeTravelParams,
|
|
1225
|
-
initialState: executionContext.state ?? {},
|
|
1226
|
-
runId: executionContext.runId,
|
|
1227
|
-
outputOptions: { includeState: true }
|
|
1228
|
-
}
|
|
1229
|
-
});
|
|
1230
|
-
result = invokeResp.result;
|
|
1231
|
-
runId = invokeResp.runId;
|
|
1232
|
-
executionContext.state = invokeResp.result.state;
|
|
1233
|
-
} else {
|
|
1234
|
-
const invokeResp = await this.inngestStep.invoke(`workflow.${executionContext.workflowId}.step.${step.id}`, {
|
|
1235
|
-
function: step.getFunction(),
|
|
1236
|
-
data: {
|
|
1237
|
-
inputData,
|
|
1238
|
-
initialState: executionContext.state ?? {},
|
|
1239
|
-
outputOptions: { includeState: true }
|
|
1240
|
-
}
|
|
1241
|
-
});
|
|
1242
|
-
result = invokeResp.result;
|
|
1243
|
-
runId = invokeResp.runId;
|
|
1244
|
-
executionContext.state = invokeResp.result.state;
|
|
1245
|
-
}
|
|
1246
|
-
} catch (e) {
|
|
1247
|
-
const errorCause = e?.cause;
|
|
1248
|
-
if (errorCause && typeof errorCause === "object") {
|
|
1249
|
-
result = errorCause;
|
|
1250
|
-
runId = errorCause.runId || crypto.randomUUID();
|
|
1251
|
-
} else {
|
|
1252
|
-
runId = crypto.randomUUID();
|
|
1253
|
-
result = {
|
|
1254
|
-
status: "failed",
|
|
1255
|
-
error: e instanceof Error ? e : new Error(String(e)),
|
|
1256
|
-
steps: {},
|
|
1257
|
-
input: inputData
|
|
1258
|
-
};
|
|
1905
|
+
throw error;
|
|
1259
1906
|
}
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1907
|
+
};
|
|
1908
|
+
return executePhaseWithSpan(async () => {
|
|
1909
|
+
switch (phase) {
|
|
1910
|
+
case "input": {
|
|
1911
|
+
if (processor.processInput) {
|
|
1912
|
+
if (!passThrough.messageList) {
|
|
1913
|
+
throw new error.MastraError({
|
|
1914
|
+
category: error.ErrorCategory.USER,
|
|
1915
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
1916
|
+
id: "PROCESSOR_MISSING_MESSAGE_LIST",
|
|
1917
|
+
text: `Processor ${processor.id} requires messageList or messages for processInput phase`
|
|
1918
|
+
});
|
|
1272
1919
|
}
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
for (const [stepName, stepResult] of suspendedSteps) {
|
|
1281
|
-
const suspendPath = [stepName, ...stepResult?.suspendPayload?.__workflow_meta?.path ?? []];
|
|
1282
|
-
executionContext.suspendedPaths[step.id] = executionContext.executionPath;
|
|
1283
|
-
await emitter.emit("watch", {
|
|
1284
|
-
type: "workflow-step-suspended",
|
|
1285
|
-
payload: {
|
|
1286
|
-
id: step.id,
|
|
1287
|
-
status: "suspended"
|
|
1288
|
-
}
|
|
1920
|
+
const idsBeforeProcessing = messages.map((m) => m.id);
|
|
1921
|
+
const check = passThrough.messageList.makeMessageSourceChecker();
|
|
1922
|
+
const result = await processor.processInput({
|
|
1923
|
+
...baseContext,
|
|
1924
|
+
messages,
|
|
1925
|
+
messageList: passThrough.messageList,
|
|
1926
|
+
systemMessages: systemMessages ?? []
|
|
1289
1927
|
});
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}
|
|
1928
|
+
if (result instanceof agent.MessageList) {
|
|
1929
|
+
if (result !== passThrough.messageList) {
|
|
1930
|
+
throw new error.MastraError({
|
|
1931
|
+
category: error.ErrorCategory.USER,
|
|
1932
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
1933
|
+
id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
|
|
1934
|
+
text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
|
|
1935
|
+
});
|
|
1299
1936
|
}
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1937
|
+
return {
|
|
1938
|
+
...passThrough,
|
|
1939
|
+
messages: result.get.all.db(),
|
|
1940
|
+
systemMessages: result.getAllSystemMessages()
|
|
1941
|
+
};
|
|
1942
|
+
} else if (Array.isArray(result)) {
|
|
1943
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
1944
|
+
result,
|
|
1945
|
+
passThrough.messageList,
|
|
1946
|
+
idsBeforeProcessing,
|
|
1947
|
+
check,
|
|
1948
|
+
"input"
|
|
1949
|
+
);
|
|
1950
|
+
return { ...passThrough, messages: result };
|
|
1951
|
+
} else if (result && "messages" in result && "systemMessages" in result) {
|
|
1952
|
+
const typedResult = result;
|
|
1953
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
1954
|
+
typedResult.messages,
|
|
1955
|
+
passThrough.messageList,
|
|
1956
|
+
idsBeforeProcessing,
|
|
1957
|
+
check,
|
|
1958
|
+
"input"
|
|
1959
|
+
);
|
|
1960
|
+
passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
|
|
1961
|
+
return {
|
|
1962
|
+
...passThrough,
|
|
1963
|
+
messages: typedResult.messages,
|
|
1964
|
+
systemMessages: typedResult.systemMessages
|
|
1965
|
+
};
|
|
1307
1966
|
}
|
|
1308
|
-
|
|
1309
|
-
}
|
|
1310
|
-
await emitter.emit("watch", {
|
|
1311
|
-
type: "workflow-step-result",
|
|
1312
|
-
payload: {
|
|
1313
|
-
id: step.id,
|
|
1314
|
-
status: "success",
|
|
1315
|
-
output: result?.result
|
|
1967
|
+
return { ...passThrough, messages };
|
|
1316
1968
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1969
|
+
return { ...passThrough, messages };
|
|
1970
|
+
}
|
|
1971
|
+
case "inputStep": {
|
|
1972
|
+
if (processor.processInputStep) {
|
|
1973
|
+
if (!passThrough.messageList) {
|
|
1974
|
+
throw new error.MastraError({
|
|
1975
|
+
category: error.ErrorCategory.USER,
|
|
1976
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
1977
|
+
id: "PROCESSOR_MISSING_MESSAGE_LIST",
|
|
1978
|
+
text: `Processor ${processor.id} requires messageList or messages for processInputStep phase`
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
const idsBeforeProcessing = messages.map((m) => m.id);
|
|
1982
|
+
const check = passThrough.messageList.makeMessageSourceChecker();
|
|
1983
|
+
const result = await processor.processInputStep({
|
|
1984
|
+
...baseContext,
|
|
1985
|
+
messages,
|
|
1986
|
+
messageList: passThrough.messageList,
|
|
1987
|
+
stepNumber: stepNumber ?? 0,
|
|
1988
|
+
systemMessages: systemMessages ?? [],
|
|
1989
|
+
// Pass model/tools configuration fields - types match ProcessInputStepArgs
|
|
1990
|
+
model,
|
|
1991
|
+
tools,
|
|
1992
|
+
toolChoice,
|
|
1993
|
+
activeTools,
|
|
1994
|
+
providerOptions,
|
|
1995
|
+
modelSettings,
|
|
1996
|
+
structuredOutput,
|
|
1997
|
+
steps: steps ?? []
|
|
1998
|
+
});
|
|
1999
|
+
const validatedResult = await processors.ProcessorRunner.validateAndFormatProcessInputStepResult(result, {
|
|
2000
|
+
messageList: passThrough.messageList,
|
|
2001
|
+
processor,
|
|
2002
|
+
stepNumber: stepNumber ?? 0
|
|
2003
|
+
});
|
|
2004
|
+
if (validatedResult.messages) {
|
|
2005
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
2006
|
+
validatedResult.messages,
|
|
2007
|
+
passThrough.messageList,
|
|
2008
|
+
idsBeforeProcessing,
|
|
2009
|
+
check
|
|
2010
|
+
);
|
|
2011
|
+
}
|
|
2012
|
+
if (validatedResult.systemMessages) {
|
|
2013
|
+
passThrough.messageList.replaceAllSystemMessages(validatedResult.systemMessages);
|
|
2014
|
+
}
|
|
2015
|
+
return { ...passThrough, messages, ...validatedResult };
|
|
1323
2016
|
}
|
|
1324
|
-
|
|
1325
|
-
return { executionContext, result: { status: "success", output: result?.result } };
|
|
1326
|
-
}
|
|
1327
|
-
);
|
|
1328
|
-
Object.assign(executionContext, res.executionContext);
|
|
1329
|
-
return {
|
|
1330
|
-
...res.result,
|
|
1331
|
-
startedAt,
|
|
1332
|
-
endedAt: Date.now(),
|
|
1333
|
-
payload: inputData,
|
|
1334
|
-
resumedAt: resume?.steps[0] === step.id ? startedAt : void 0,
|
|
1335
|
-
resumePayload: resume?.steps[0] === step.id ? resume?.resumePayload : void 0
|
|
1336
|
-
};
|
|
1337
|
-
}
|
|
1338
|
-
const stepCallId = crypto.randomUUID();
|
|
1339
|
-
let stepRes;
|
|
1340
|
-
try {
|
|
1341
|
-
stepRes = await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}`, async () => {
|
|
1342
|
-
let execResults;
|
|
1343
|
-
let suspended;
|
|
1344
|
-
let bailed;
|
|
1345
|
-
const { resumeData: timeTravelResumeData, validationError: timeTravelResumeValidationError } = await workflows.validateStepResumeData({
|
|
1346
|
-
resumeData: timeTravel?.stepResults[step.id]?.status === "suspended" ? timeTravel?.resumeData : void 0,
|
|
1347
|
-
step
|
|
1348
|
-
});
|
|
1349
|
-
let resumeDataToUse;
|
|
1350
|
-
if (timeTravelResumeData && !timeTravelResumeValidationError) {
|
|
1351
|
-
resumeDataToUse = timeTravelResumeData;
|
|
1352
|
-
} else if (timeTravelResumeData && timeTravelResumeValidationError) {
|
|
1353
|
-
this.logger.warn("Time travel resume data validation failed", {
|
|
1354
|
-
stepId: step.id,
|
|
1355
|
-
error: timeTravelResumeValidationError.message
|
|
1356
|
-
});
|
|
1357
|
-
} else if (resume?.steps[0] === step.id) {
|
|
1358
|
-
resumeDataToUse = resume?.resumePayload;
|
|
1359
|
-
}
|
|
1360
|
-
try {
|
|
1361
|
-
if (validationError) {
|
|
1362
|
-
throw validationError;
|
|
2017
|
+
return { ...passThrough, messages };
|
|
1363
2018
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
2019
|
+
case "outputStream": {
|
|
2020
|
+
if (processor.processOutputStream) {
|
|
2021
|
+
const spanKey = `__outputStreamSpan_${processor.id}`;
|
|
2022
|
+
const mutableState = state ?? {};
|
|
2023
|
+
let processorSpan2 = mutableState[spanKey];
|
|
2024
|
+
if (!processorSpan2 && parentSpan) {
|
|
2025
|
+
processorSpan2 = parentSpan.createChildSpan({
|
|
2026
|
+
type: observability.SpanType.PROCESSOR_RUN,
|
|
2027
|
+
name: `output stream processor: ${processor.id}`,
|
|
2028
|
+
entityType: observability.EntityType.OUTPUT_PROCESSOR,
|
|
2029
|
+
entityId: processor.id,
|
|
2030
|
+
entityName: processor.name ?? processor.id,
|
|
2031
|
+
input: { phase, streamParts: [] },
|
|
2032
|
+
attributes: {
|
|
2033
|
+
processorExecutor: "workflow",
|
|
2034
|
+
processorIndex: processor.processorIndex
|
|
2035
|
+
}
|
|
2036
|
+
});
|
|
2037
|
+
mutableState[spanKey] = processorSpan2;
|
|
2038
|
+
}
|
|
2039
|
+
if (processorSpan2) {
|
|
2040
|
+
processorSpan2.input = {
|
|
2041
|
+
phase,
|
|
2042
|
+
streamParts: streamParts ?? [],
|
|
2043
|
+
totalChunks: (streamParts ?? []).length
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
const processorTracingContext2 = processorSpan2 ? { currentSpan: processorSpan2 } : baseContext.tracingContext;
|
|
2047
|
+
let result;
|
|
2048
|
+
try {
|
|
2049
|
+
result = await processor.processOutputStream({
|
|
2050
|
+
...baseContext,
|
|
2051
|
+
tracingContext: processorTracingContext2,
|
|
2052
|
+
part,
|
|
2053
|
+
streamParts: streamParts ?? [],
|
|
2054
|
+
state: mutableState,
|
|
2055
|
+
messageList: passThrough.messageList
|
|
2056
|
+
// Optional for stream processing
|
|
2057
|
+
});
|
|
2058
|
+
if (part && part.type === "finish") {
|
|
2059
|
+
processorSpan2?.end({ output: result });
|
|
2060
|
+
delete mutableState[spanKey];
|
|
2061
|
+
}
|
|
2062
|
+
} catch (error) {
|
|
2063
|
+
if (error instanceof agent.TripWire) {
|
|
2064
|
+
processorSpan2?.end({ output: { tripwire: error.message } });
|
|
2065
|
+
} else {
|
|
2066
|
+
processorSpan2?.error({ error, endSpan: true });
|
|
1400
2067
|
}
|
|
2068
|
+
delete mutableState[spanKey];
|
|
2069
|
+
throw error;
|
|
1401
2070
|
}
|
|
1402
|
-
|
|
1403
|
-
},
|
|
1404
|
-
bail: (result2) => {
|
|
1405
|
-
bailed = { payload: result2 };
|
|
1406
|
-
},
|
|
1407
|
-
abort: () => {
|
|
1408
|
-
abortController?.abort();
|
|
1409
|
-
},
|
|
1410
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1411
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1412
|
-
engine: {
|
|
1413
|
-
step: this.inngestStep
|
|
1414
|
-
},
|
|
1415
|
-
abortSignal: abortController.signal
|
|
1416
|
-
});
|
|
1417
|
-
const endedAt = Date.now();
|
|
1418
|
-
execResults = {
|
|
1419
|
-
status: "success",
|
|
1420
|
-
output: result,
|
|
1421
|
-
startedAt,
|
|
1422
|
-
endedAt,
|
|
1423
|
-
payload: inputData,
|
|
1424
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1425
|
-
resumePayload: resumeDataToUse
|
|
1426
|
-
};
|
|
1427
|
-
} catch (e) {
|
|
1428
|
-
const stepFailure = {
|
|
1429
|
-
status: "failed",
|
|
1430
|
-
payload: inputData,
|
|
1431
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1432
|
-
endedAt: Date.now(),
|
|
1433
|
-
startedAt,
|
|
1434
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1435
|
-
resumePayload: resumeDataToUse
|
|
1436
|
-
};
|
|
1437
|
-
execResults = stepFailure;
|
|
1438
|
-
const fallbackErrorMessage = `Step ${step.id} failed`;
|
|
1439
|
-
stepSpan?.error({ error: new Error(execResults.error ?? fallbackErrorMessage) });
|
|
1440
|
-
throw new inngest.RetryAfterError(execResults.error ?? fallbackErrorMessage, executionContext.retryConfig.delay, {
|
|
1441
|
-
cause: execResults
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1444
|
-
if (suspended) {
|
|
1445
|
-
execResults = {
|
|
1446
|
-
status: "suspended",
|
|
1447
|
-
suspendPayload: suspended.payload,
|
|
1448
|
-
...execResults.output ? { suspendOutput: execResults.output } : {},
|
|
1449
|
-
payload: inputData,
|
|
1450
|
-
suspendedAt: Date.now(),
|
|
1451
|
-
startedAt,
|
|
1452
|
-
resumedAt: resumeDataToUse ? startedAt : void 0,
|
|
1453
|
-
resumePayload: resumeDataToUse
|
|
1454
|
-
};
|
|
1455
|
-
} else if (bailed) {
|
|
1456
|
-
execResults = {
|
|
1457
|
-
status: "bailed",
|
|
1458
|
-
output: bailed.payload,
|
|
1459
|
-
payload: inputData,
|
|
1460
|
-
endedAt: Date.now(),
|
|
1461
|
-
startedAt
|
|
1462
|
-
};
|
|
1463
|
-
}
|
|
1464
|
-
if (execResults.status === "suspended") {
|
|
1465
|
-
await emitter.emit("watch", {
|
|
1466
|
-
type: "workflow-step-suspended",
|
|
1467
|
-
payload: {
|
|
1468
|
-
id: step.id,
|
|
1469
|
-
...execResults
|
|
1470
|
-
}
|
|
1471
|
-
});
|
|
1472
|
-
} else {
|
|
1473
|
-
await emitter.emit("watch", {
|
|
1474
|
-
type: "workflow-step-result",
|
|
1475
|
-
payload: {
|
|
1476
|
-
id: step.id,
|
|
1477
|
-
...execResults
|
|
1478
|
-
}
|
|
1479
|
-
});
|
|
1480
|
-
await emitter.emit("watch", {
|
|
1481
|
-
type: "workflow-step-finish",
|
|
1482
|
-
payload: {
|
|
1483
|
-
id: step.id,
|
|
1484
|
-
metadata: {}
|
|
2071
|
+
return { ...passThrough, state: mutableState, part: result };
|
|
1485
2072
|
}
|
|
1486
|
-
|
|
1487
|
-
}
|
|
1488
|
-
stepSpan?.end({ output: execResults });
|
|
1489
|
-
return { result: execResults, executionContext, stepResults };
|
|
1490
|
-
});
|
|
1491
|
-
} catch (e) {
|
|
1492
|
-
const stepFailure = e instanceof Error ? e?.cause : {
|
|
1493
|
-
status: "failed",
|
|
1494
|
-
error: e instanceof Error ? e.message : String(e),
|
|
1495
|
-
payload: inputData,
|
|
1496
|
-
startedAt,
|
|
1497
|
-
endedAt: Date.now()
|
|
1498
|
-
};
|
|
1499
|
-
stepRes = {
|
|
1500
|
-
result: stepFailure,
|
|
1501
|
-
executionContext,
|
|
1502
|
-
stepResults: {
|
|
1503
|
-
...stepResults,
|
|
1504
|
-
[step.id]: stepFailure
|
|
1505
|
-
}
|
|
1506
|
-
};
|
|
1507
|
-
}
|
|
1508
|
-
if (disableScorers !== false && stepRes.result.status === "success") {
|
|
1509
|
-
await this.inngestStep.run(`workflow.${executionContext.workflowId}.step.${step.id}.score`, async () => {
|
|
1510
|
-
if (step.scorers) {
|
|
1511
|
-
await this.runScorers({
|
|
1512
|
-
scorers: step.scorers,
|
|
1513
|
-
runId: executionContext.runId,
|
|
1514
|
-
input: inputData,
|
|
1515
|
-
output: stepRes.result,
|
|
1516
|
-
workflowId: executionContext.workflowId,
|
|
1517
|
-
stepId: step.id,
|
|
1518
|
-
requestContext,
|
|
1519
|
-
disableScorers,
|
|
1520
|
-
tracingContext: { currentSpan: stepSpan }
|
|
1521
|
-
});
|
|
1522
|
-
}
|
|
1523
|
-
});
|
|
1524
|
-
}
|
|
1525
|
-
Object.assign(executionContext.suspendedPaths, stepRes.executionContext.suspendedPaths);
|
|
1526
|
-
executionContext.state = stepRes.executionContext.state;
|
|
1527
|
-
return stepRes.result;
|
|
1528
|
-
}
|
|
1529
|
-
async persistStepUpdate({
|
|
1530
|
-
workflowId,
|
|
1531
|
-
runId,
|
|
1532
|
-
stepResults,
|
|
1533
|
-
resourceId,
|
|
1534
|
-
executionContext,
|
|
1535
|
-
serializedStepGraph,
|
|
1536
|
-
workflowStatus,
|
|
1537
|
-
result,
|
|
1538
|
-
error
|
|
1539
|
-
}) {
|
|
1540
|
-
await this.inngestStep.run(
|
|
1541
|
-
`workflow.${workflowId}.run.${runId}.path.${JSON.stringify(executionContext.executionPath)}.stepUpdate`,
|
|
1542
|
-
async () => {
|
|
1543
|
-
const shouldPersistSnapshot = this.options.shouldPersistSnapshot({ stepResults, workflowStatus });
|
|
1544
|
-
if (!shouldPersistSnapshot) {
|
|
1545
|
-
return;
|
|
1546
|
-
}
|
|
1547
|
-
await this.mastra?.getStorage()?.persistWorkflowSnapshot({
|
|
1548
|
-
workflowName: workflowId,
|
|
1549
|
-
runId,
|
|
1550
|
-
resourceId,
|
|
1551
|
-
snapshot: {
|
|
1552
|
-
runId,
|
|
1553
|
-
status: workflowStatus,
|
|
1554
|
-
value: executionContext.state,
|
|
1555
|
-
context: stepResults,
|
|
1556
|
-
activePaths: executionContext.executionPath,
|
|
1557
|
-
activeStepsPath: executionContext.activeStepsPath,
|
|
1558
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1559
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1560
|
-
waitingPaths: {},
|
|
1561
|
-
serializedStepGraph,
|
|
1562
|
-
result,
|
|
1563
|
-
error,
|
|
1564
|
-
timestamp: Date.now()
|
|
2073
|
+
return { ...passThrough, part };
|
|
1565
2074
|
}
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
stepResults,
|
|
1576
|
-
timeTravel,
|
|
1577
|
-
resume,
|
|
1578
|
-
executionContext,
|
|
1579
|
-
emitter,
|
|
1580
|
-
abortController,
|
|
1581
|
-
requestContext,
|
|
1582
|
-
writableStream,
|
|
1583
|
-
disableScorers,
|
|
1584
|
-
tracingContext
|
|
1585
|
-
}) {
|
|
1586
|
-
const conditionalSpan = tracingContext?.currentSpan?.createChildSpan({
|
|
1587
|
-
type: observability.SpanType.WORKFLOW_CONDITIONAL,
|
|
1588
|
-
name: `conditional: '${entry.conditions.length} conditions'`,
|
|
1589
|
-
input: prevOutput,
|
|
1590
|
-
attributes: {
|
|
1591
|
-
conditionCount: entry.conditions.length
|
|
1592
|
-
},
|
|
1593
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1594
|
-
});
|
|
1595
|
-
let execResults;
|
|
1596
|
-
const truthyIndexes = (await Promise.all(
|
|
1597
|
-
entry.conditions.map(
|
|
1598
|
-
(cond, index) => this.inngestStep.run(`workflow.${workflowId}.conditional.${index}`, async () => {
|
|
1599
|
-
const evalSpan = conditionalSpan?.createChildSpan({
|
|
1600
|
-
type: observability.SpanType.WORKFLOW_CONDITIONAL_EVAL,
|
|
1601
|
-
name: `condition: '${index}'`,
|
|
1602
|
-
input: prevOutput,
|
|
1603
|
-
attributes: {
|
|
1604
|
-
conditionIndex: index
|
|
1605
|
-
},
|
|
1606
|
-
tracingPolicy: this.options?.tracingPolicy
|
|
1607
|
-
});
|
|
1608
|
-
try {
|
|
1609
|
-
const result = await cond(
|
|
1610
|
-
workflows.createDeprecationProxy(
|
|
1611
|
-
{
|
|
1612
|
-
runId,
|
|
1613
|
-
workflowId,
|
|
1614
|
-
mastra: this.mastra,
|
|
1615
|
-
requestContext,
|
|
1616
|
-
retryCount: -1,
|
|
1617
|
-
inputData: prevOutput,
|
|
1618
|
-
state: executionContext.state,
|
|
1619
|
-
setState: (state) => {
|
|
1620
|
-
executionContext.state = state;
|
|
1621
|
-
},
|
|
1622
|
-
tracingContext: {
|
|
1623
|
-
currentSpan: evalSpan
|
|
1624
|
-
},
|
|
1625
|
-
getInitData: () => stepResults?.input,
|
|
1626
|
-
getStepResult: workflows.getStepResult.bind(this, stepResults),
|
|
1627
|
-
// TODO: this function shouldn't have suspend probably?
|
|
1628
|
-
suspend: async (_suspendPayload) => {
|
|
1629
|
-
},
|
|
1630
|
-
bail: () => {
|
|
1631
|
-
},
|
|
1632
|
-
abort: () => {
|
|
1633
|
-
abortController.abort();
|
|
1634
|
-
},
|
|
1635
|
-
[_constants.EMITTER_SYMBOL]: emitter,
|
|
1636
|
-
[_constants.STREAM_FORMAT_SYMBOL]: executionContext.format,
|
|
1637
|
-
engine: {
|
|
1638
|
-
step: this.inngestStep
|
|
1639
|
-
},
|
|
1640
|
-
abortSignal: abortController.signal,
|
|
1641
|
-
writer: new tools.ToolStream(
|
|
1642
|
-
{
|
|
1643
|
-
prefix: "workflow-step",
|
|
1644
|
-
callId: crypto.randomUUID(),
|
|
1645
|
-
name: "conditional",
|
|
1646
|
-
runId
|
|
1647
|
-
},
|
|
1648
|
-
writableStream
|
|
1649
|
-
)
|
|
1650
|
-
},
|
|
1651
|
-
{
|
|
1652
|
-
paramName: "runCount",
|
|
1653
|
-
deprecationMessage: workflows.runCountDeprecationMessage,
|
|
1654
|
-
logger: this.logger
|
|
1655
|
-
}
|
|
1656
|
-
)
|
|
1657
|
-
);
|
|
1658
|
-
evalSpan?.end({
|
|
1659
|
-
output: result,
|
|
1660
|
-
attributes: {
|
|
1661
|
-
result: !!result
|
|
2075
|
+
case "outputResult": {
|
|
2076
|
+
if (processor.processOutputResult) {
|
|
2077
|
+
if (!passThrough.messageList) {
|
|
2078
|
+
throw new error.MastraError({
|
|
2079
|
+
category: error.ErrorCategory.USER,
|
|
2080
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
2081
|
+
id: "PROCESSOR_MISSING_MESSAGE_LIST",
|
|
2082
|
+
text: `Processor ${processor.id} requires messageList or messages for processOutputResult phase`
|
|
2083
|
+
});
|
|
1662
2084
|
}
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
2085
|
+
const idsBeforeProcessing = messages.map((m) => m.id);
|
|
2086
|
+
const check = passThrough.messageList.makeMessageSourceChecker();
|
|
2087
|
+
const result = await processor.processOutputResult({
|
|
2088
|
+
...baseContext,
|
|
2089
|
+
messages,
|
|
2090
|
+
messageList: passThrough.messageList
|
|
2091
|
+
});
|
|
2092
|
+
if (result instanceof agent.MessageList) {
|
|
2093
|
+
if (result !== passThrough.messageList) {
|
|
2094
|
+
throw new error.MastraError({
|
|
2095
|
+
category: error.ErrorCategory.USER,
|
|
2096
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
2097
|
+
id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
|
|
2098
|
+
text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
return {
|
|
2102
|
+
...passThrough,
|
|
2103
|
+
messages: result.get.all.db(),
|
|
2104
|
+
systemMessages: result.getAllSystemMessages()
|
|
2105
|
+
};
|
|
2106
|
+
} else if (Array.isArray(result)) {
|
|
2107
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
2108
|
+
result,
|
|
2109
|
+
passThrough.messageList,
|
|
2110
|
+
idsBeforeProcessing,
|
|
2111
|
+
check,
|
|
2112
|
+
"response"
|
|
2113
|
+
);
|
|
2114
|
+
return { ...passThrough, messages: result };
|
|
2115
|
+
} else if (result && "messages" in result && "systemMessages" in result) {
|
|
2116
|
+
const typedResult = result;
|
|
2117
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
2118
|
+
typedResult.messages,
|
|
2119
|
+
passThrough.messageList,
|
|
2120
|
+
idsBeforeProcessing,
|
|
2121
|
+
check,
|
|
2122
|
+
"response"
|
|
2123
|
+
);
|
|
2124
|
+
passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
|
|
2125
|
+
return {
|
|
2126
|
+
...passThrough,
|
|
2127
|
+
messages: typedResult.messages,
|
|
2128
|
+
systemMessages: typedResult.systemMessages
|
|
2129
|
+
};
|
|
1670
2130
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
})
|
|
1675
|
-
)
|
|
1676
|
-
)).filter((index) => index !== null);
|
|
1677
|
-
const stepsToRun = entry.steps.filter((_, index) => truthyIndexes.includes(index));
|
|
1678
|
-
conditionalSpan?.update({
|
|
1679
|
-
attributes: {
|
|
1680
|
-
truthyIndexes,
|
|
1681
|
-
selectedSteps: stepsToRun.map((s) => s.type === "step" ? s.step.id : `control-${s.type}`)
|
|
1682
|
-
}
|
|
1683
|
-
});
|
|
1684
|
-
const results = await Promise.all(
|
|
1685
|
-
stepsToRun.map(async (step, index) => {
|
|
1686
|
-
const currStepResult = stepResults[step.step.id];
|
|
1687
|
-
if (currStepResult && currStepResult.status === "success") {
|
|
1688
|
-
return currStepResult;
|
|
1689
|
-
}
|
|
1690
|
-
const result = await this.executeStep({
|
|
1691
|
-
step: step.step,
|
|
1692
|
-
prevOutput,
|
|
1693
|
-
stepResults,
|
|
1694
|
-
resume,
|
|
1695
|
-
timeTravel,
|
|
1696
|
-
executionContext: {
|
|
1697
|
-
workflowId,
|
|
1698
|
-
runId,
|
|
1699
|
-
executionPath: [...executionContext.executionPath, index],
|
|
1700
|
-
activeStepsPath: executionContext.activeStepsPath,
|
|
1701
|
-
suspendedPaths: executionContext.suspendedPaths,
|
|
1702
|
-
resumeLabels: executionContext.resumeLabels,
|
|
1703
|
-
retryConfig: executionContext.retryConfig,
|
|
1704
|
-
state: executionContext.state
|
|
1705
|
-
},
|
|
1706
|
-
emitter,
|
|
1707
|
-
abortController,
|
|
1708
|
-
requestContext,
|
|
1709
|
-
writableStream,
|
|
1710
|
-
disableScorers,
|
|
1711
|
-
tracingContext: {
|
|
1712
|
-
currentSpan: conditionalSpan
|
|
2131
|
+
return { ...passThrough, messages };
|
|
2132
|
+
}
|
|
2133
|
+
return { ...passThrough, messages };
|
|
1713
2134
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
2135
|
+
case "outputStep": {
|
|
2136
|
+
if (processor.processOutputStep) {
|
|
2137
|
+
if (!passThrough.messageList) {
|
|
2138
|
+
throw new error.MastraError({
|
|
2139
|
+
category: error.ErrorCategory.USER,
|
|
2140
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
2141
|
+
id: "PROCESSOR_MISSING_MESSAGE_LIST",
|
|
2142
|
+
text: `Processor ${processor.id} requires messageList or messages for processOutputStep phase`
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
const idsBeforeProcessing = messages.map((m) => m.id);
|
|
2146
|
+
const check = passThrough.messageList.makeMessageSourceChecker();
|
|
2147
|
+
const result = await processor.processOutputStep({
|
|
2148
|
+
...baseContext,
|
|
2149
|
+
messages,
|
|
2150
|
+
messageList: passThrough.messageList,
|
|
2151
|
+
stepNumber: stepNumber ?? 0,
|
|
2152
|
+
finishReason,
|
|
2153
|
+
toolCalls,
|
|
2154
|
+
text,
|
|
2155
|
+
systemMessages: systemMessages ?? [],
|
|
2156
|
+
steps: steps ?? []
|
|
2157
|
+
});
|
|
2158
|
+
if (result instanceof agent.MessageList) {
|
|
2159
|
+
if (result !== passThrough.messageList) {
|
|
2160
|
+
throw new error.MastraError({
|
|
2161
|
+
category: error.ErrorCategory.USER,
|
|
2162
|
+
domain: error.ErrorDomain.MASTRA_WORKFLOW,
|
|
2163
|
+
id: "PROCESSOR_RETURNED_EXTERNAL_MESSAGE_LIST",
|
|
2164
|
+
text: `Processor ${processor.id} returned a MessageList instance other than the one passed in. Use the messageList argument instead.`
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
return {
|
|
2168
|
+
...passThrough,
|
|
2169
|
+
messages: result.get.all.db(),
|
|
2170
|
+
systemMessages: result.getAllSystemMessages()
|
|
2171
|
+
};
|
|
2172
|
+
} else if (Array.isArray(result)) {
|
|
2173
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
2174
|
+
result,
|
|
2175
|
+
passThrough.messageList,
|
|
2176
|
+
idsBeforeProcessing,
|
|
2177
|
+
check,
|
|
2178
|
+
"response"
|
|
2179
|
+
);
|
|
2180
|
+
return { ...passThrough, messages: result };
|
|
2181
|
+
} else if (result && "messages" in result && "systemMessages" in result) {
|
|
2182
|
+
const typedResult = result;
|
|
2183
|
+
processors.ProcessorRunner.applyMessagesToMessageList(
|
|
2184
|
+
typedResult.messages,
|
|
2185
|
+
passThrough.messageList,
|
|
2186
|
+
idsBeforeProcessing,
|
|
2187
|
+
check,
|
|
2188
|
+
"response"
|
|
2189
|
+
);
|
|
2190
|
+
passThrough.messageList.replaceAllSystemMessages(typedResult.systemMessages);
|
|
2191
|
+
return {
|
|
2192
|
+
...passThrough,
|
|
2193
|
+
messages: typedResult.messages,
|
|
2194
|
+
systemMessages: typedResult.systemMessages
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
return { ...passThrough, messages };
|
|
1736
2198
|
}
|
|
2199
|
+
return { ...passThrough, messages };
|
|
1737
2200
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
}
|
|
1742
|
-
if (execResults.status === "failed") {
|
|
1743
|
-
conditionalSpan?.error({
|
|
1744
|
-
error: new Error(execResults.error)
|
|
2201
|
+
default:
|
|
2202
|
+
return { ...passThrough, messages };
|
|
2203
|
+
}
|
|
1745
2204
|
});
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
|
|
2205
|
+
},
|
|
2206
|
+
component: "PROCESSOR"
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2209
|
+
function init(inngest) {
|
|
2210
|
+
return {
|
|
2211
|
+
createWorkflow(params) {
|
|
2212
|
+
return new InngestWorkflow(
|
|
2213
|
+
params,
|
|
2214
|
+
inngest
|
|
2215
|
+
);
|
|
2216
|
+
},
|
|
2217
|
+
createStep,
|
|
2218
|
+
cloneStep(step, opts) {
|
|
2219
|
+
return {
|
|
2220
|
+
id: opts.id,
|
|
2221
|
+
description: step.description,
|
|
2222
|
+
inputSchema: step.inputSchema,
|
|
2223
|
+
outputSchema: step.outputSchema,
|
|
2224
|
+
resumeSchema: step.resumeSchema,
|
|
2225
|
+
suspendSchema: step.suspendSchema,
|
|
2226
|
+
stateSchema: step.stateSchema,
|
|
2227
|
+
execute: step.execute,
|
|
2228
|
+
retries: step.retries,
|
|
2229
|
+
scorers: step.scorers,
|
|
2230
|
+
component: step.component
|
|
2231
|
+
};
|
|
2232
|
+
},
|
|
2233
|
+
cloneWorkflow(workflow, opts) {
|
|
2234
|
+
const wf = new workflows.Workflow({
|
|
2235
|
+
id: opts.id,
|
|
2236
|
+
inputSchema: workflow.inputSchema,
|
|
2237
|
+
outputSchema: workflow.outputSchema,
|
|
2238
|
+
steps: workflow.stepDefs,
|
|
2239
|
+
mastra: workflow.mastra,
|
|
2240
|
+
options: workflow.options
|
|
1749
2241
|
});
|
|
2242
|
+
wf.setStepFlow(workflow.stepGraph);
|
|
2243
|
+
wf.commit();
|
|
2244
|
+
return wf;
|
|
1750
2245
|
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
};
|
|
2246
|
+
};
|
|
2247
|
+
}
|
|
1754
2248
|
|
|
1755
2249
|
exports.InngestExecutionEngine = InngestExecutionEngine;
|
|
2250
|
+
exports.InngestPubSub = InngestPubSub;
|
|
1756
2251
|
exports.InngestRun = InngestRun;
|
|
1757
2252
|
exports.InngestWorkflow = InngestWorkflow;
|
|
2253
|
+
exports._compatibilityCheck = _compatibilityCheck;
|
|
2254
|
+
exports.createServe = createServe;
|
|
1758
2255
|
exports.createStep = createStep;
|
|
1759
2256
|
exports.init = init;
|
|
1760
2257
|
exports.serve = serve;
|