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