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