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