@mastra/core 0.4.2 → 0.4.3-alpha.1
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/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/{base-hk-xmLC1.d.ts → base-JKlKFf5I.d.ts} +42 -13
- package/dist/{chunk-XVS6QFTX.js → chunk-B3M27AMP.js} +931 -672
- package/dist/{chunk-7TG2Y45H.js → chunk-FZMBA5CV.js} +55 -24
- package/dist/{chunk-M626YCHO.js → chunk-HQ55LN2U.js} +1 -1
- package/dist/{chunk-YLCBP7MP.js → chunk-KNVTCZW7.js} +1 -1
- package/dist/{chunk-KM7PRKJ2.js → chunk-NGD2HQYW.js} +1 -1
- package/dist/{chunk-PL6URKH2.js → chunk-R5DDQQJT.js} +1 -1
- package/dist/eval/index.d.ts +1 -1
- package/dist/index.d.ts +5 -6
- package/dist/index.js +6 -6
- package/dist/integration/index.d.ts +4 -5
- package/dist/llm/index.d.ts +2 -2
- package/dist/mastra/index.d.ts +3 -4
- package/dist/mastra/index.js +1 -1
- package/dist/memory/index.d.ts +2 -2
- package/dist/memory/index.js +1 -1
- package/dist/relevance/index.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/libsql/index.d.ts +2 -2
- package/dist/storage/libsql/index.js +1 -1
- package/dist/telemetry/index.d.ts +2 -2
- package/dist/tools/index.d.ts +3 -3
- package/dist/vector/index.d.ts +1 -0
- package/dist/{workflow-BxyFP9Wv.d.ts → workflow-VWNjiLwe.d.ts} +13 -21
- package/dist/workflows/index.d.ts +24 -7
- package/dist/workflows/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { MastraBase } from './chunk-OZ4XVJ6F.js';
|
|
2
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
3
|
import { context, trace } from '@opentelemetry/api';
|
|
4
|
+
import EventEmitter from 'node:events';
|
|
3
5
|
import { get } from 'radash';
|
|
4
6
|
import sift from 'sift';
|
|
5
|
-
import {
|
|
7
|
+
import { createActor, assign, fromPromise, setup } from 'xstate';
|
|
6
8
|
|
|
7
9
|
// src/workflows/utils.ts
|
|
8
10
|
function isErrorEvent(stateEvent) {
|
|
@@ -18,185 +20,144 @@ function getStepResult(result) {
|
|
|
18
20
|
if (result?.status === "success") return result.output;
|
|
19
21
|
return void 0;
|
|
20
22
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#actor = null;
|
|
30
|
-
#runId;
|
|
31
|
-
#retryConfig;
|
|
32
|
-
#mastra;
|
|
33
|
-
// registers stepIds on `after` calls
|
|
34
|
-
#afterStepStack = [];
|
|
35
|
-
#lastStepStack = [];
|
|
36
|
-
#stepGraph = { initial: [] };
|
|
37
|
-
#stepSubscriberGraph = {};
|
|
38
|
-
#steps = {};
|
|
39
|
-
#onStepTransition = /* @__PURE__ */ new Set();
|
|
40
|
-
#executionSpan;
|
|
41
|
-
/**
|
|
42
|
-
* Creates a new Workflow instance
|
|
43
|
-
* @param name - Identifier for the workflow (not necessarily unique)
|
|
44
|
-
* @param logger - Optional logger instance
|
|
45
|
-
*/
|
|
46
|
-
constructor({ name, triggerSchema, retryConfig, mastra }) {
|
|
47
|
-
super({ component: "WORKFLOW", name });
|
|
48
|
-
this.name = name;
|
|
49
|
-
this.#retryConfig = retryConfig;
|
|
50
|
-
this.triggerSchema = triggerSchema;
|
|
51
|
-
this.#runId = crypto.randomUUID();
|
|
52
|
-
this.#mastra = mastra;
|
|
53
|
-
if (mastra?.logger) {
|
|
54
|
-
this.logger = mastra?.logger;
|
|
23
|
+
function getSuspendedPaths({
|
|
24
|
+
value,
|
|
25
|
+
path,
|
|
26
|
+
suspendedPaths
|
|
27
|
+
}) {
|
|
28
|
+
if (typeof value === "string") {
|
|
29
|
+
if (value === "suspended") {
|
|
30
|
+
suspendedPaths.add(path);
|
|
55
31
|
}
|
|
56
|
-
|
|
32
|
+
} else {
|
|
33
|
+
Object.keys(value).forEach(
|
|
34
|
+
(key) => getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
|
|
35
|
+
);
|
|
57
36
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
actors: this.#getDefaultActors()
|
|
70
|
-
}).createMachine({
|
|
71
|
-
id: this.name,
|
|
72
|
-
type: "parallel",
|
|
73
|
-
context: ({ input }) => ({
|
|
74
|
-
...input
|
|
75
|
-
}),
|
|
76
|
-
states: this.#buildStateHierarchy(this.#stepGraph)
|
|
77
|
-
});
|
|
78
|
-
this.#machine = machine;
|
|
79
|
-
return machine;
|
|
37
|
+
}
|
|
38
|
+
function isFinalState(status) {
|
|
39
|
+
return ["completed", "failed"].includes(status);
|
|
40
|
+
}
|
|
41
|
+
function recursivelyCheckForFinalState({
|
|
42
|
+
value,
|
|
43
|
+
suspendedPaths,
|
|
44
|
+
path
|
|
45
|
+
}) {
|
|
46
|
+
if (typeof value === "string") {
|
|
47
|
+
return isFinalState(value) || suspendedPaths.has(path);
|
|
80
48
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
this.#steps[stepKey] = step;
|
|
99
|
-
const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
|
|
100
|
-
const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
|
|
101
|
-
if (parentStepKey && stepGraph) {
|
|
102
|
-
if (!stepGraph.initial.some((step2) => step2.step.id === stepKey)) {
|
|
103
|
-
stepGraph.initial.push(graphEntry);
|
|
49
|
+
return Object.keys(value).every(
|
|
50
|
+
(key) => recursivelyCheckForFinalState({ value: value[key], suspendedPaths, path: path ? `${path}.${key}` : key })
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function getActivePathsAndStatus(value) {
|
|
54
|
+
const paths = [];
|
|
55
|
+
const traverse = (current, path = []) => {
|
|
56
|
+
for (const [key, value2] of Object.entries(current)) {
|
|
57
|
+
const currentPath = [...path, key];
|
|
58
|
+
if (typeof value2 === "string") {
|
|
59
|
+
paths.push({
|
|
60
|
+
stepPath: currentPath,
|
|
61
|
+
stepId: key,
|
|
62
|
+
status: value2
|
|
63
|
+
});
|
|
64
|
+
} else if (typeof value2 === "object" && value2 !== null) {
|
|
65
|
+
traverse(value2, currentPath);
|
|
104
66
|
}
|
|
105
|
-
stepGraph[stepKey] = [];
|
|
106
|
-
} else {
|
|
107
|
-
if (!this.#stepGraph[stepKey]) this.#stepGraph[stepKey] = [];
|
|
108
|
-
this.#stepGraph.initial.push(graphEntry);
|
|
109
67
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
68
|
+
};
|
|
69
|
+
traverse(value);
|
|
70
|
+
return paths;
|
|
71
|
+
}
|
|
72
|
+
function mergeChildValue(startStepId, parent, child) {
|
|
73
|
+
const traverse = (current) => {
|
|
74
|
+
const obj = {};
|
|
75
|
+
for (const [key, value] of Object.entries(current)) {
|
|
76
|
+
if (key === startStepId) {
|
|
77
|
+
obj[key] = { ...child };
|
|
78
|
+
} else if (typeof value === "string") {
|
|
79
|
+
obj[key] = value;
|
|
80
|
+
} else if (typeof value === "object" && value !== null) {
|
|
81
|
+
obj[key] = traverse(value);
|
|
119
82
|
}
|
|
120
83
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
|
|
134
|
-
const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
|
|
135
|
-
if (parentStepKey && stepGraph && stepGraph[lastStepKey]) {
|
|
136
|
-
stepGraph[lastStepKey].push(graphEntry);
|
|
84
|
+
return obj;
|
|
85
|
+
};
|
|
86
|
+
return traverse(parent);
|
|
87
|
+
}
|
|
88
|
+
var updateStepInHierarchy = (value, targetStepId) => {
|
|
89
|
+
const result = {};
|
|
90
|
+
for (const key of Object.keys(value)) {
|
|
91
|
+
const currentValue = value[key];
|
|
92
|
+
if (key === targetStepId) {
|
|
93
|
+
result[key] = "pending";
|
|
94
|
+
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
95
|
+
result[key] = updateStepInHierarchy(currentValue, targetStepId);
|
|
137
96
|
} else {
|
|
138
|
-
|
|
139
|
-
this.#stepGraph[lastStepKey].push(graphEntry);
|
|
97
|
+
result[key] = currentValue;
|
|
140
98
|
}
|
|
141
|
-
return this;
|
|
142
|
-
}
|
|
143
|
-
after(step) {
|
|
144
|
-
const stepKey = this.#makeStepKey(step);
|
|
145
|
-
this.#afterStepStack.push(stepKey);
|
|
146
|
-
if (!this.#stepSubscriberGraph[stepKey]) {
|
|
147
|
-
this.#stepSubscriberGraph[stepKey] = { initial: [] };
|
|
148
|
-
}
|
|
149
|
-
return this;
|
|
150
99
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
100
|
+
return result;
|
|
101
|
+
};
|
|
102
|
+
var Machine = class extends EventEmitter {
|
|
103
|
+
logger;
|
|
104
|
+
#mastra;
|
|
105
|
+
#workflowInstance;
|
|
106
|
+
#executionSpan;
|
|
107
|
+
#stepGraph;
|
|
108
|
+
#machine;
|
|
109
|
+
#runId;
|
|
110
|
+
#startStepId;
|
|
111
|
+
name;
|
|
112
|
+
#actor = null;
|
|
113
|
+
#steps = {};
|
|
114
|
+
#retryConfig;
|
|
115
|
+
constructor({
|
|
116
|
+
logger,
|
|
117
|
+
mastra,
|
|
118
|
+
workflowInstance,
|
|
119
|
+
executionSpan,
|
|
120
|
+
name,
|
|
121
|
+
runId,
|
|
122
|
+
steps,
|
|
123
|
+
stepGraph,
|
|
124
|
+
retryConfig,
|
|
125
|
+
startStepId
|
|
126
|
+
}) {
|
|
127
|
+
super();
|
|
128
|
+
this.#mastra = mastra;
|
|
129
|
+
this.#workflowInstance = workflowInstance;
|
|
130
|
+
this.#executionSpan = executionSpan;
|
|
131
|
+
this.logger = logger;
|
|
159
132
|
this.#runId = runId;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
133
|
+
this.#startStepId = startStepId;
|
|
134
|
+
this.name = name;
|
|
135
|
+
this.#stepGraph = stepGraph;
|
|
136
|
+
this.#steps = steps;
|
|
137
|
+
this.#retryConfig = retryConfig;
|
|
138
|
+
this.initializeMachine();
|
|
139
|
+
}
|
|
140
|
+
get startStepId() {
|
|
141
|
+
return this.#startStepId;
|
|
164
142
|
}
|
|
165
143
|
async execute({
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
stepId
|
|
144
|
+
stepId,
|
|
145
|
+
input,
|
|
146
|
+
snapshot
|
|
170
147
|
} = {}) {
|
|
171
|
-
if (
|
|
172
|
-
this.#runId = runId;
|
|
148
|
+
if (snapshot) {
|
|
173
149
|
this.logger.debug(`Workflow snapshot received`, { runId: this.#runId, snapshot });
|
|
174
150
|
}
|
|
175
|
-
this
|
|
176
|
-
attributes: { componentName: this.name, runId: this.#runId }
|
|
177
|
-
});
|
|
178
|
-
const machineInput = snapshot ? snapshot.context : {
|
|
179
|
-
// Maintain the original step results and their output
|
|
180
|
-
steps: {},
|
|
181
|
-
triggerData: triggerData || {},
|
|
182
|
-
attempts: Object.keys(this.#steps).reduce(
|
|
183
|
-
(acc, stepKey) => {
|
|
184
|
-
acc[stepKey] = this.#steps[stepKey]?.retryConfig?.attempts || this.#retryConfig?.attempts || 3;
|
|
185
|
-
return acc;
|
|
186
|
-
},
|
|
187
|
-
{}
|
|
188
|
-
)
|
|
189
|
-
};
|
|
190
|
-
this.logger.debug(`Machine input prepared`, { runId: this.#runId, machineInput });
|
|
151
|
+
this.logger.debug(`Machine input prepared`, { runId: this.#runId, input });
|
|
191
152
|
const actorSnapshot = snapshot ? {
|
|
192
153
|
...snapshot,
|
|
193
|
-
context:
|
|
154
|
+
context: input
|
|
194
155
|
} : void 0;
|
|
195
156
|
this.logger.debug(`Creating actor with configuration`, {
|
|
196
|
-
|
|
157
|
+
input,
|
|
197
158
|
actorSnapshot,
|
|
198
|
-
|
|
199
|
-
|
|
159
|
+
runId: this.#runId,
|
|
160
|
+
machineStates: this.#machine.config.states
|
|
200
161
|
});
|
|
201
162
|
this.#actor = createActor(this.#machine, {
|
|
202
163
|
inspect: (inspectionEvent) => {
|
|
@@ -206,7 +167,7 @@ var Workflow = class extends MastraBase {
|
|
|
206
167
|
runId: this.#runId
|
|
207
168
|
});
|
|
208
169
|
},
|
|
209
|
-
input
|
|
170
|
+
input,
|
|
210
171
|
snapshot: actorSnapshot
|
|
211
172
|
});
|
|
212
173
|
this.#actor.start();
|
|
@@ -224,25 +185,14 @@ var Workflow = class extends MastraBase {
|
|
|
224
185
|
}
|
|
225
186
|
const suspendedPaths = /* @__PURE__ */ new Set();
|
|
226
187
|
this.#actor.subscribe(async (state) => {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
onTransition({
|
|
230
|
-
runId: this.#runId,
|
|
231
|
-
value: state.value,
|
|
232
|
-
context: state.context,
|
|
233
|
-
activePaths: this.#getActivePathsAndStatus(state.value),
|
|
234
|
-
timestamp: Date.now()
|
|
235
|
-
})?.catch(() => {
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
this.#getSuspendedPaths({
|
|
188
|
+
this.emit("state-update", this.#startStepId, state.value, state.context);
|
|
189
|
+
getSuspendedPaths({
|
|
240
190
|
value: state.value,
|
|
241
191
|
path: "",
|
|
242
192
|
suspendedPaths
|
|
243
193
|
});
|
|
244
194
|
const allStatesValue = state.value;
|
|
245
|
-
const allStatesComplete =
|
|
195
|
+
const allStatesComplete = recursivelyCheckForFinalState({
|
|
246
196
|
value: allStatesValue,
|
|
247
197
|
suspendedPaths,
|
|
248
198
|
path: ""
|
|
@@ -254,86 +204,298 @@ var Workflow = class extends MastraBase {
|
|
|
254
204
|
});
|
|
255
205
|
if (!allStatesComplete) return;
|
|
256
206
|
try {
|
|
257
|
-
await this.#persistWorkflowSnapshot();
|
|
207
|
+
await this.#workflowInstance.persistWorkflowSnapshot();
|
|
258
208
|
this.#cleanup();
|
|
259
209
|
this.#executionSpan?.end();
|
|
260
210
|
resolve({
|
|
261
|
-
|
|
262
|
-
results: state.context.steps,
|
|
263
|
-
runId: this.#runId
|
|
211
|
+
results: state.context.steps
|
|
264
212
|
});
|
|
265
213
|
} catch (error) {
|
|
266
214
|
this.logger.debug("Failed to persist final snapshot", { error });
|
|
267
215
|
this.#cleanup();
|
|
268
216
|
this.#executionSpan?.end();
|
|
269
217
|
resolve({
|
|
270
|
-
|
|
271
|
-
results: state.context.steps,
|
|
272
|
-
runId: this.#runId
|
|
218
|
+
results: state.context.steps
|
|
273
219
|
});
|
|
274
220
|
}
|
|
275
221
|
});
|
|
276
222
|
});
|
|
277
223
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
* @throws Error if validation fails
|
|
283
|
-
*
|
|
284
|
-
* @returns this instance for method chaining
|
|
285
|
-
*/
|
|
286
|
-
commit() {
|
|
287
|
-
this.initializeMachine();
|
|
288
|
-
return this;
|
|
289
|
-
}
|
|
290
|
-
// record all object paths that leads to a suspended state
|
|
291
|
-
#getSuspendedPaths({
|
|
292
|
-
value,
|
|
293
|
-
path,
|
|
294
|
-
suspendedPaths
|
|
295
|
-
}) {
|
|
296
|
-
if (typeof value === "string") {
|
|
297
|
-
if (value === "suspended") {
|
|
298
|
-
suspendedPaths.add(path);
|
|
299
|
-
}
|
|
300
|
-
} else {
|
|
301
|
-
Object.keys(value).forEach(
|
|
302
|
-
(key) => this.#getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
|
|
303
|
-
);
|
|
224
|
+
#cleanup() {
|
|
225
|
+
if (this.#actor) {
|
|
226
|
+
this.#actor.stop();
|
|
227
|
+
this.#actor = null;
|
|
304
228
|
}
|
|
229
|
+
this.removeAllListeners();
|
|
305
230
|
}
|
|
306
|
-
#
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
path
|
|
313
|
-
}) {
|
|
314
|
-
if (typeof value === "string") {
|
|
315
|
-
return this.#isFinalState(value) || suspendedPaths.has(path);
|
|
316
|
-
}
|
|
317
|
-
return Object.keys(value).every(
|
|
318
|
-
(key) => this.#recursivelyCheckForFinalState({ value: value[key], suspendedPaths, path: path ? `${path}.${key}` : key })
|
|
319
|
-
);
|
|
231
|
+
#makeDelayMap() {
|
|
232
|
+
const delayMap = {};
|
|
233
|
+
Object.keys(this.#steps).forEach((stepId) => {
|
|
234
|
+
delayMap[stepId] = this.#steps[stepId]?.retryConfig?.delay || this.#retryConfig?.delay || 1e3;
|
|
235
|
+
});
|
|
236
|
+
return delayMap;
|
|
320
237
|
}
|
|
321
|
-
#
|
|
322
|
-
const nextStep = nextSteps.shift();
|
|
238
|
+
#getDefaultActions() {
|
|
323
239
|
return {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
240
|
+
updateStepResult: assign({
|
|
241
|
+
steps: ({ context, event }) => {
|
|
242
|
+
if (!isTransitionEvent(event)) return context.steps;
|
|
243
|
+
const { stepId, result } = event.output;
|
|
244
|
+
return {
|
|
245
|
+
...context.steps,
|
|
246
|
+
[stepId]: {
|
|
247
|
+
status: "success",
|
|
248
|
+
output: result
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}),
|
|
253
|
+
setStepError: assign({
|
|
254
|
+
steps: ({ context, event }, params) => {
|
|
255
|
+
if (!isErrorEvent(event)) return context.steps;
|
|
256
|
+
const { stepId } = params;
|
|
257
|
+
if (!stepId) return context.steps;
|
|
258
|
+
return {
|
|
259
|
+
...context.steps,
|
|
260
|
+
[stepId]: {
|
|
261
|
+
status: "failed",
|
|
262
|
+
error: event.error.message
|
|
263
|
+
}
|
|
264
|
+
};
|
|
329
265
|
}
|
|
266
|
+
}),
|
|
267
|
+
notifyStepCompletion: async (_, params) => {
|
|
268
|
+
const { stepId } = params;
|
|
269
|
+
this.logger.debug(`Step ${stepId} completed`);
|
|
330
270
|
},
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
271
|
+
snapshotStep: assign({
|
|
272
|
+
_snapshot: ({}, params) => {
|
|
273
|
+
const { stepId } = params;
|
|
274
|
+
return { stepId };
|
|
275
|
+
}
|
|
276
|
+
}),
|
|
277
|
+
persistSnapshot: async ({ context }) => {
|
|
278
|
+
if (context._snapshot) {
|
|
279
|
+
await this.#workflowInstance.persistWorkflowSnapshot();
|
|
280
|
+
}
|
|
281
|
+
return;
|
|
282
|
+
},
|
|
283
|
+
decrementAttemptCount: assign({
|
|
284
|
+
attempts: ({ context, event }, params) => {
|
|
285
|
+
if (!isTransitionEvent(event)) return context.attempts;
|
|
286
|
+
const { stepId } = params;
|
|
287
|
+
const attemptCount = context.attempts[stepId];
|
|
288
|
+
if (attemptCount === void 0) return context.attempts;
|
|
289
|
+
return { ...context.attempts, [stepId]: attemptCount - 1 };
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
#getDefaultActors() {
|
|
295
|
+
return {
|
|
296
|
+
resolverFunction: fromPromise(async ({ input }) => {
|
|
297
|
+
const { stepNode, context } = input;
|
|
298
|
+
const resolvedData = this.#resolveVariables({
|
|
299
|
+
stepConfig: stepNode.config,
|
|
300
|
+
context,
|
|
301
|
+
stepId: stepNode.step.id
|
|
302
|
+
});
|
|
303
|
+
this.logger.debug(`Resolved variables for ${stepNode.step.id}`, {
|
|
304
|
+
resolvedData,
|
|
305
|
+
runId: this.#runId
|
|
306
|
+
});
|
|
307
|
+
const result = await stepNode.config.handler({
|
|
308
|
+
context: resolvedData,
|
|
309
|
+
suspend: async () => {
|
|
310
|
+
await this.#workflowInstance.suspend(stepNode.step.id, this);
|
|
311
|
+
if (this.#actor) {
|
|
312
|
+
context.steps[stepNode.step.id] = {
|
|
313
|
+
status: "suspended"
|
|
314
|
+
};
|
|
315
|
+
this.logger.debug(`Sending SUSPENDED event for step ${stepNode.step.id}`);
|
|
316
|
+
this.#actor?.send({ type: "SUSPENDED", stepId: stepNode.step.id });
|
|
317
|
+
} else {
|
|
318
|
+
this.logger.debug(`Actor not available for step ${stepNode.step.id}`);
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
runId: this.#runId,
|
|
322
|
+
mastra: this.#mastra
|
|
323
|
+
});
|
|
324
|
+
this.logger.debug(`Step ${stepNode.step.id} result`, {
|
|
325
|
+
stepId: stepNode.step.id,
|
|
326
|
+
result,
|
|
327
|
+
runId: this.#runId
|
|
328
|
+
});
|
|
329
|
+
return {
|
|
330
|
+
stepId: stepNode.step.id,
|
|
331
|
+
result
|
|
332
|
+
};
|
|
333
|
+
}),
|
|
334
|
+
conditionCheck: fromPromise(async ({ input }) => {
|
|
335
|
+
const { context, stepNode } = input;
|
|
336
|
+
const stepConfig = stepNode.config;
|
|
337
|
+
const attemptCount = context.attempts[stepNode.step.id];
|
|
338
|
+
this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
|
|
339
|
+
stepId: stepNode.step.id,
|
|
340
|
+
runId: this.#runId
|
|
341
|
+
});
|
|
342
|
+
this.logger.debug(`Attempt count for step ${stepNode.step.id}`, {
|
|
343
|
+
attemptCount,
|
|
344
|
+
attempts: context.attempts,
|
|
345
|
+
runId: this.#runId,
|
|
346
|
+
stepId: stepNode.step.id
|
|
347
|
+
});
|
|
348
|
+
if (!attemptCount || attemptCount < 0) {
|
|
349
|
+
if (stepConfig?.snapshotOnTimeout) {
|
|
350
|
+
return { type: "SUSPENDED", stepId: stepNode.step.id };
|
|
351
|
+
}
|
|
352
|
+
return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
|
|
353
|
+
}
|
|
354
|
+
if (!stepConfig?.when) {
|
|
355
|
+
return { type: "CONDITIONS_MET" };
|
|
356
|
+
}
|
|
357
|
+
this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
|
|
358
|
+
stepId: stepNode.step.id,
|
|
359
|
+
runId: this.#runId
|
|
360
|
+
});
|
|
361
|
+
if (typeof stepConfig?.when === "function") {
|
|
362
|
+
const conditionMet = await stepConfig.when({
|
|
363
|
+
context: {
|
|
364
|
+
...context,
|
|
365
|
+
getStepResult: (stepId) => {
|
|
366
|
+
if (stepId === "trigger") {
|
|
367
|
+
return context.triggerData;
|
|
368
|
+
}
|
|
369
|
+
const result = context.steps[stepId];
|
|
370
|
+
if (result && result.status === "success") {
|
|
371
|
+
return result.output;
|
|
372
|
+
}
|
|
373
|
+
return void 0;
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
mastra: this.#mastra
|
|
377
|
+
});
|
|
378
|
+
if (conditionMet) {
|
|
379
|
+
this.logger.debug(`Condition met for step ${stepNode.step.id}`, {
|
|
380
|
+
stepId: stepNode.step.id,
|
|
381
|
+
runId: this.#runId
|
|
382
|
+
});
|
|
383
|
+
return { type: "CONDITIONS_MET" };
|
|
384
|
+
}
|
|
385
|
+
if (!attemptCount || attemptCount < 0) {
|
|
386
|
+
return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
|
|
387
|
+
}
|
|
388
|
+
return { type: "WAITING", stepId: stepNode.step.id };
|
|
389
|
+
} else {
|
|
390
|
+
const conditionMet = this.#evaluateCondition(stepConfig.when, context);
|
|
391
|
+
if (!conditionMet) {
|
|
392
|
+
return {
|
|
393
|
+
type: "CONDITION_FAILED",
|
|
394
|
+
error: `Step:${stepNode.step.id} condition check failed`
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return { type: "CONDITIONS_MET" };
|
|
399
|
+
}),
|
|
400
|
+
spawnSubscriberFunction: fromPromise(
|
|
401
|
+
async ({
|
|
402
|
+
input
|
|
403
|
+
}) => {
|
|
404
|
+
const { parentStepId, context } = input;
|
|
405
|
+
const result = await this.#workflowInstance.runMachine(parentStepId, context);
|
|
406
|
+
return Promise.resolve({ steps: result?.results });
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
#resolveVariables({
|
|
412
|
+
stepConfig,
|
|
413
|
+
context,
|
|
414
|
+
stepId
|
|
415
|
+
}) {
|
|
416
|
+
this.logger.debug(`Resolving variables for step ${stepId}`, {
|
|
417
|
+
stepId,
|
|
418
|
+
runId: this.#runId
|
|
419
|
+
});
|
|
420
|
+
const resolvedData = {
|
|
421
|
+
...context,
|
|
422
|
+
getStepResult: (stepId2) => {
|
|
423
|
+
if (stepId2 === "trigger") {
|
|
424
|
+
return context.triggerData;
|
|
425
|
+
}
|
|
426
|
+
const result = context.steps[stepId2];
|
|
427
|
+
if (result && result.status === "success") {
|
|
428
|
+
return result.output;
|
|
429
|
+
}
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
for (const [key, variable] of Object.entries(stepConfig.data)) {
|
|
434
|
+
const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id]);
|
|
435
|
+
this.logger.debug(
|
|
436
|
+
`Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id}`,
|
|
437
|
+
{
|
|
438
|
+
sourceData,
|
|
439
|
+
path: variable.path,
|
|
440
|
+
runId: this.#runId
|
|
441
|
+
}
|
|
442
|
+
);
|
|
443
|
+
if (!sourceData && variable.step !== "trigger") {
|
|
444
|
+
resolvedData[key] = void 0;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const value = variable.path === "" || variable.path === "." ? sourceData : get(sourceData, variable.path);
|
|
448
|
+
this.logger.debug(`Resolved variable ${key}`, {
|
|
449
|
+
value,
|
|
450
|
+
runId: this.#runId
|
|
451
|
+
});
|
|
452
|
+
resolvedData[key] = value;
|
|
453
|
+
}
|
|
454
|
+
return resolvedData;
|
|
455
|
+
}
|
|
456
|
+
initializeMachine() {
|
|
457
|
+
const machine = setup({
|
|
458
|
+
types: {},
|
|
459
|
+
delays: this.#makeDelayMap(),
|
|
460
|
+
actions: this.#getDefaultActions(),
|
|
461
|
+
actors: this.#getDefaultActors()
|
|
462
|
+
}).createMachine({
|
|
463
|
+
id: this.name,
|
|
464
|
+
type: "parallel",
|
|
465
|
+
context: ({ input }) => ({
|
|
466
|
+
...input
|
|
467
|
+
}),
|
|
468
|
+
states: this.#buildStateHierarchy(this.#stepGraph)
|
|
469
|
+
});
|
|
470
|
+
this.#machine = machine;
|
|
471
|
+
return machine;
|
|
472
|
+
}
|
|
473
|
+
#buildStateHierarchy(stepGraph) {
|
|
474
|
+
const states = {};
|
|
475
|
+
stepGraph.initial.forEach((stepNode) => {
|
|
476
|
+
const nextSteps = [...stepGraph[stepNode.step.id] || []];
|
|
477
|
+
states[stepNode.step.id] = {
|
|
478
|
+
...this.#buildBaseState(stepNode, nextSteps)
|
|
479
|
+
};
|
|
480
|
+
});
|
|
481
|
+
return states;
|
|
482
|
+
}
|
|
483
|
+
#buildBaseState(stepNode, nextSteps = []) {
|
|
484
|
+
const nextStep = nextSteps.shift();
|
|
485
|
+
return {
|
|
486
|
+
initial: "pending",
|
|
487
|
+
on: {
|
|
488
|
+
RESET_TO_PENDING: {
|
|
489
|
+
target: ".pending"
|
|
490
|
+
// Note the dot to target child state
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
states: {
|
|
494
|
+
pending: {
|
|
495
|
+
entry: () => {
|
|
496
|
+
this.logger.debug(`Step ${stepNode.step.id} pending`, {
|
|
497
|
+
stepId: stepNode.step.id,
|
|
498
|
+
runId: this.#runId
|
|
337
499
|
});
|
|
338
500
|
},
|
|
339
501
|
exit: () => {
|
|
@@ -466,30 +628,6 @@ var Workflow = class extends MastraBase {
|
|
|
466
628
|
})
|
|
467
629
|
})
|
|
468
630
|
]
|
|
469
|
-
// after: {
|
|
470
|
-
// [stepNode.step.id]: {
|
|
471
|
-
// target: 'pending',
|
|
472
|
-
// actions: [
|
|
473
|
-
// assign({
|
|
474
|
-
// attempts: ({ context }: { context: WorkflowContext }) => ({
|
|
475
|
-
// ...context.attempts,
|
|
476
|
-
// [stepNode.step.id]: this.#steps[stepNode.step.id]?.retryConfig?.attempts || 3,
|
|
477
|
-
// }),
|
|
478
|
-
// }),
|
|
479
|
-
// ],
|
|
480
|
-
// }
|
|
481
|
-
// },
|
|
482
|
-
// entry: () => {
|
|
483
|
-
// this.logger.debug(`Step ${stepNode.step.id} suspended ${new Date().toISOString()}`);
|
|
484
|
-
// },
|
|
485
|
-
// exit: () => {
|
|
486
|
-
// this.logger.debug(`Step ${stepNode.step.id} finished suspended ${new Date().toISOString()}`);
|
|
487
|
-
// },
|
|
488
|
-
// after: {
|
|
489
|
-
// [stepNode.step.id]: {
|
|
490
|
-
// target: 'suspended',
|
|
491
|
-
// },
|
|
492
|
-
// },
|
|
493
631
|
},
|
|
494
632
|
executing: {
|
|
495
633
|
entry: () => {
|
|
@@ -600,400 +738,530 @@ var Workflow = class extends MastraBase {
|
|
|
600
738
|
}
|
|
601
739
|
};
|
|
602
740
|
}
|
|
603
|
-
#
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
this
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
return { ...context.attempts, [stepId]: attemptCount - 1 };
|
|
672
|
-
}
|
|
673
|
-
})
|
|
674
|
-
};
|
|
741
|
+
#evaluateCondition(condition, context) {
|
|
742
|
+
let andBranchResult = true;
|
|
743
|
+
let baseResult = true;
|
|
744
|
+
let orBranchResult = true;
|
|
745
|
+
const simpleCondition = Object.entries(condition).find(([key]) => key.includes("."));
|
|
746
|
+
if (simpleCondition) {
|
|
747
|
+
const [key, queryValue] = simpleCondition;
|
|
748
|
+
const [stepId, ...pathParts] = key.split(".");
|
|
749
|
+
const path = pathParts.join(".");
|
|
750
|
+
const sourceData = stepId === "trigger" ? context.triggerData : getStepResult(context.steps[stepId]);
|
|
751
|
+
this.logger.debug(`Got condition data from step ${stepId}`, {
|
|
752
|
+
stepId,
|
|
753
|
+
sourceData,
|
|
754
|
+
runId: this.#runId
|
|
755
|
+
});
|
|
756
|
+
if (!sourceData) {
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
let value = get(sourceData, path);
|
|
760
|
+
if (stepId !== "trigger" && path === "status" && !value) {
|
|
761
|
+
value = "success";
|
|
762
|
+
}
|
|
763
|
+
if (typeof queryValue === "object" && queryValue !== null) {
|
|
764
|
+
baseResult = sift(queryValue)(value);
|
|
765
|
+
} else {
|
|
766
|
+
baseResult = value === queryValue;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if ("ref" in condition) {
|
|
770
|
+
const { ref, query } = condition;
|
|
771
|
+
const sourceData = ref.step === "trigger" ? context.triggerData : getStepResult(context.steps[ref.step.id]);
|
|
772
|
+
this.logger.debug(`Got condition data from ${ref.step === "trigger" ? "trigger" : ref.step.id}`, {
|
|
773
|
+
sourceData,
|
|
774
|
+
runId: this.#runId
|
|
775
|
+
});
|
|
776
|
+
if (!sourceData) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
let value = get(sourceData, ref.path);
|
|
780
|
+
if (ref.step !== "trigger" && ref.path === "status" && !value) {
|
|
781
|
+
value = "success";
|
|
782
|
+
}
|
|
783
|
+
baseResult = sift(query)(value);
|
|
784
|
+
}
|
|
785
|
+
if ("and" in condition) {
|
|
786
|
+
andBranchResult = condition.and.every((cond) => this.#evaluateCondition(cond, context));
|
|
787
|
+
this.logger.debug(`Evaluated AND condition`, {
|
|
788
|
+
andBranchResult,
|
|
789
|
+
runId: this.#runId
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
if ("or" in condition) {
|
|
793
|
+
orBranchResult = condition.or.some((cond) => this.#evaluateCondition(cond, context));
|
|
794
|
+
this.logger.debug(`Evaluated OR condition`, {
|
|
795
|
+
orBranchResult,
|
|
796
|
+
runId: this.#runId
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
const finalResult = baseResult && andBranchResult && orBranchResult;
|
|
800
|
+
this.logger.debug(`Evaluated condition`, {
|
|
801
|
+
finalResult,
|
|
802
|
+
runId: this.#runId
|
|
803
|
+
});
|
|
804
|
+
return finalResult;
|
|
805
|
+
}
|
|
806
|
+
getSnapshot() {
|
|
807
|
+
const snapshot = this.#actor?.getSnapshot();
|
|
808
|
+
return snapshot;
|
|
675
809
|
}
|
|
676
|
-
|
|
810
|
+
};
|
|
811
|
+
|
|
812
|
+
// src/workflows/workflow-instance.ts
|
|
813
|
+
var WorkflowInstance = class {
|
|
814
|
+
name;
|
|
815
|
+
#mastra;
|
|
816
|
+
#machines = {};
|
|
817
|
+
logger;
|
|
818
|
+
#steps = {};
|
|
819
|
+
#stepGraph;
|
|
820
|
+
#stepSubscriberGraph = {};
|
|
821
|
+
#retryConfig;
|
|
822
|
+
#runId;
|
|
823
|
+
#state = null;
|
|
824
|
+
#executionSpan;
|
|
825
|
+
#onStepTransition = /* @__PURE__ */ new Set();
|
|
826
|
+
#onFinish;
|
|
827
|
+
// indexed by stepId
|
|
828
|
+
#suspendedMachines = {};
|
|
829
|
+
constructor({
|
|
830
|
+
name,
|
|
831
|
+
logger,
|
|
832
|
+
steps,
|
|
833
|
+
runId,
|
|
834
|
+
retryConfig,
|
|
835
|
+
mastra,
|
|
836
|
+
stepGraph,
|
|
837
|
+
stepSubscriberGraph,
|
|
838
|
+
onStepTransition,
|
|
839
|
+
onFinish
|
|
840
|
+
}) {
|
|
841
|
+
this.name = name;
|
|
842
|
+
this.logger = logger;
|
|
843
|
+
this.#steps = steps;
|
|
844
|
+
this.#stepGraph = stepGraph;
|
|
845
|
+
this.#stepSubscriberGraph = stepSubscriberGraph;
|
|
846
|
+
this.#retryConfig = retryConfig;
|
|
847
|
+
this.#mastra = mastra;
|
|
848
|
+
this.#runId = runId ?? crypto.randomUUID();
|
|
849
|
+
this.#onStepTransition = onStepTransition;
|
|
850
|
+
this.#onFinish = onFinish;
|
|
851
|
+
}
|
|
852
|
+
setState(state) {
|
|
853
|
+
this.#state = state;
|
|
854
|
+
}
|
|
855
|
+
get runId() {
|
|
856
|
+
return this.#runId;
|
|
857
|
+
}
|
|
858
|
+
get executionSpan() {
|
|
859
|
+
return this.#executionSpan;
|
|
860
|
+
}
|
|
861
|
+
async start({ triggerData } = {}) {
|
|
862
|
+
const results = await this.execute({ triggerData });
|
|
863
|
+
if (this.#onFinish) {
|
|
864
|
+
this.#onFinish();
|
|
865
|
+
}
|
|
677
866
|
return {
|
|
678
|
-
|
|
679
|
-
|
|
867
|
+
...results,
|
|
868
|
+
runId: this.runId
|
|
680
869
|
};
|
|
681
870
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
this
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (!attemptCount || attemptCount < 0) {
|
|
737
|
-
if (stepConfig?.snapshotOnTimeout) {
|
|
738
|
-
return { type: "SUSPENDED", stepId: stepNode.step.id };
|
|
739
|
-
}
|
|
740
|
-
return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
|
|
741
|
-
}
|
|
742
|
-
if (!stepConfig?.when) {
|
|
743
|
-
return { type: "CONDITIONS_MET" };
|
|
744
|
-
}
|
|
745
|
-
this.logger.debug(`Checking conditions for step ${stepNode.step.id}`, {
|
|
746
|
-
stepId: stepNode.step.id,
|
|
747
|
-
runId: this.#runId
|
|
748
|
-
});
|
|
749
|
-
if (typeof stepConfig?.when === "function") {
|
|
750
|
-
const conditionMet = await stepConfig.when({
|
|
751
|
-
context: {
|
|
752
|
-
...context,
|
|
753
|
-
getStepResult: (stepId) => {
|
|
754
|
-
if (stepId === "trigger") {
|
|
755
|
-
return context.triggerData;
|
|
756
|
-
}
|
|
757
|
-
const result = context.steps[stepId];
|
|
758
|
-
if (result && result.status === "success") {
|
|
759
|
-
return result.output;
|
|
760
|
-
}
|
|
761
|
-
return void 0;
|
|
762
|
-
}
|
|
763
|
-
},
|
|
764
|
-
...this.#getInjectables()
|
|
765
|
-
});
|
|
766
|
-
if (conditionMet) {
|
|
767
|
-
this.logger.debug(`Condition met for step ${stepNode.step.id}`, {
|
|
768
|
-
stepId: stepNode.step.id,
|
|
769
|
-
runId: this.#runId
|
|
770
|
-
});
|
|
771
|
-
return { type: "CONDITIONS_MET" };
|
|
772
|
-
}
|
|
773
|
-
if (!attemptCount || attemptCount < 0) {
|
|
774
|
-
return { type: "CONDITION_FAILED", error: `Step:${stepNode.step.id} condition check failed` };
|
|
775
|
-
}
|
|
776
|
-
return { type: "WAITING", stepId: stepNode.step.id };
|
|
777
|
-
} else {
|
|
778
|
-
const conditionMet = this.#evaluateCondition(stepConfig.when, context);
|
|
779
|
-
if (!conditionMet) {
|
|
780
|
-
return {
|
|
781
|
-
type: "CONDITION_FAILED",
|
|
782
|
-
error: `Step:${stepNode.step.id} condition check failed`
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
return { type: "CONDITIONS_MET" };
|
|
787
|
-
}),
|
|
788
|
-
spawnSubscriberFunction: fromPromise(
|
|
789
|
-
async ({
|
|
790
|
-
input
|
|
791
|
-
}) => {
|
|
792
|
-
const { parentStepId, context } = input;
|
|
793
|
-
const stepGraph = this.#stepSubscriberGraph[parentStepId];
|
|
794
|
-
if (!stepGraph) {
|
|
795
|
-
return {
|
|
796
|
-
steps: {}
|
|
797
|
-
};
|
|
798
|
-
}
|
|
799
|
-
const subscriberMachine = setup({
|
|
800
|
-
types: {},
|
|
801
|
-
delays: this.#makeDelayMap(),
|
|
802
|
-
actions: this.#getDefaultActions(),
|
|
803
|
-
actors: this.#getDefaultActors()
|
|
804
|
-
}).createMachine({
|
|
805
|
-
id: `${this.name}-subscriber-${parentStepId}`,
|
|
871
|
+
async execute({
|
|
872
|
+
triggerData,
|
|
873
|
+
snapshot,
|
|
874
|
+
stepId
|
|
875
|
+
} = {}) {
|
|
876
|
+
this.#executionSpan = this.#mastra?.telemetry?.tracer.startSpan(`workflow.${this.name}.execute`, {
|
|
877
|
+
attributes: { componentName: this.name, runId: this.runId }
|
|
878
|
+
});
|
|
879
|
+
let machineInput = {
|
|
880
|
+
// Maintain the original step results and their output
|
|
881
|
+
steps: {},
|
|
882
|
+
triggerData: triggerData || {},
|
|
883
|
+
attempts: Object.keys(this.#steps).reduce(
|
|
884
|
+
(acc, stepKey) => {
|
|
885
|
+
acc[stepKey] = this.#steps[stepKey]?.retryConfig?.attempts || this.#retryConfig?.attempts || 3;
|
|
886
|
+
return acc;
|
|
887
|
+
},
|
|
888
|
+
{}
|
|
889
|
+
)
|
|
890
|
+
};
|
|
891
|
+
let stepGraph = this.#stepGraph;
|
|
892
|
+
let startStepId = "trigger";
|
|
893
|
+
if (snapshot) {
|
|
894
|
+
const runState = snapshot;
|
|
895
|
+
machineInput = runState.context;
|
|
896
|
+
if (stepId && runState?.suspendedSteps?.[stepId]) {
|
|
897
|
+
startStepId = runState.suspendedSteps[stepId];
|
|
898
|
+
stepGraph = this.#stepSubscriberGraph[startStepId] ?? this.#stepGraph;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
const defaultMachine = new Machine({
|
|
902
|
+
logger: this.logger,
|
|
903
|
+
mastra: this.#mastra,
|
|
904
|
+
workflowInstance: this,
|
|
905
|
+
name: this.name,
|
|
906
|
+
runId: this.runId,
|
|
907
|
+
steps: this.#steps,
|
|
908
|
+
stepGraph,
|
|
909
|
+
executionSpan: this.#executionSpan,
|
|
910
|
+
startStepId
|
|
911
|
+
});
|
|
912
|
+
this.#machines[startStepId] = defaultMachine;
|
|
913
|
+
const stateUpdateHandler = (startStepId2, state, context) => {
|
|
914
|
+
if (startStepId2 === "trigger") {
|
|
915
|
+
this.#state = state;
|
|
916
|
+
} else {
|
|
917
|
+
this.#state = mergeChildValue(startStepId2, this.#state, state);
|
|
918
|
+
}
|
|
919
|
+
const now = Date.now();
|
|
920
|
+
if (this.#onStepTransition) {
|
|
921
|
+
this.#onStepTransition.forEach((onTransition) => {
|
|
922
|
+
void onTransition({
|
|
923
|
+
runId: this.#runId,
|
|
924
|
+
value: this.#state,
|
|
806
925
|
context,
|
|
807
|
-
|
|
808
|
-
|
|
926
|
+
activePaths: getActivePathsAndStatus(this.#state),
|
|
927
|
+
timestamp: now
|
|
809
928
|
});
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
defaultMachine.on("state-update", stateUpdateHandler);
|
|
933
|
+
const { results } = await defaultMachine.execute({ snapshot, stepId, input: machineInput });
|
|
934
|
+
await this.persistWorkflowSnapshot();
|
|
935
|
+
return { results };
|
|
936
|
+
}
|
|
937
|
+
async runMachine(parentStepId, input) {
|
|
938
|
+
if (!this.#stepSubscriberGraph[parentStepId]) {
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
const stateUpdateHandler = (startStepId, state, context) => {
|
|
942
|
+
if (startStepId === "trigger") {
|
|
943
|
+
this.#state = state;
|
|
944
|
+
} else {
|
|
945
|
+
this.#state = mergeChildValue(startStepId, this.#state, state);
|
|
946
|
+
}
|
|
947
|
+
const now = Date.now();
|
|
948
|
+
if (this.#onStepTransition) {
|
|
949
|
+
this.#onStepTransition.forEach((onTransition) => {
|
|
950
|
+
void onTransition({
|
|
951
|
+
runId: this.#runId,
|
|
952
|
+
value: this.#state,
|
|
953
|
+
context,
|
|
954
|
+
activePaths: getActivePathsAndStatus(this.#state),
|
|
955
|
+
timestamp: now
|
|
833
956
|
});
|
|
834
|
-
}
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
};
|
|
960
|
+
const machine = new Machine({
|
|
961
|
+
logger: this.logger,
|
|
962
|
+
mastra: this.#mastra,
|
|
963
|
+
workflowInstance: this,
|
|
964
|
+
name: parentStepId === "trigger" ? this.name : `${this.name}-${parentStepId}`,
|
|
965
|
+
runId: this.runId,
|
|
966
|
+
steps: this.#steps,
|
|
967
|
+
stepGraph: this.#stepSubscriberGraph[parentStepId],
|
|
968
|
+
executionSpan: this.#executionSpan,
|
|
969
|
+
startStepId: parentStepId
|
|
970
|
+
});
|
|
971
|
+
machine.on("state-update", stateUpdateHandler);
|
|
972
|
+
this.#machines[parentStepId] = machine;
|
|
973
|
+
return await machine.execute({ input });
|
|
974
|
+
}
|
|
975
|
+
async suspend(stepId, machine) {
|
|
976
|
+
this.#suspendedMachines[stepId] = machine;
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Persists the workflow state to the database
|
|
980
|
+
*/
|
|
981
|
+
async persistWorkflowSnapshot() {
|
|
982
|
+
const existingSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
983
|
+
workflowName: this.name,
|
|
984
|
+
runId: this.#runId
|
|
985
|
+
});
|
|
986
|
+
const machineSnapshots = {};
|
|
987
|
+
for (const [stepId, machine] of Object.entries(this.#machines)) {
|
|
988
|
+
const machineSnapshot = machine?.getSnapshot();
|
|
989
|
+
if (machineSnapshot) {
|
|
990
|
+
machineSnapshots[stepId] = { ...machineSnapshot };
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
let snapshot = machineSnapshots["trigger"];
|
|
994
|
+
delete machineSnapshots["trigger"];
|
|
995
|
+
const suspendedSteps = Object.entries(this.#suspendedMachines).reduce(
|
|
996
|
+
(acc, [stepId, machine]) => {
|
|
997
|
+
acc[stepId] = machine.startStepId;
|
|
998
|
+
return acc;
|
|
999
|
+
},
|
|
1000
|
+
{}
|
|
1001
|
+
);
|
|
1002
|
+
if (!snapshot && existingSnapshot) {
|
|
1003
|
+
existingSnapshot.childStates = { ...existingSnapshot.childStates, ...machineSnapshots };
|
|
1004
|
+
existingSnapshot.suspendedSteps = { ...existingSnapshot.suspendedSteps, ...suspendedSteps };
|
|
1005
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
1006
|
+
workflowName: this.name,
|
|
1007
|
+
runId: this.#runId,
|
|
1008
|
+
snapshot: existingSnapshot
|
|
1009
|
+
});
|
|
1010
|
+
return;
|
|
1011
|
+
} else if (snapshot && !existingSnapshot) {
|
|
1012
|
+
snapshot.suspendedSteps = suspendedSteps;
|
|
1013
|
+
snapshot.childStates = { ...machineSnapshots };
|
|
1014
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
1015
|
+
workflowName: this.name,
|
|
1016
|
+
runId: this.#runId,
|
|
1017
|
+
snapshot
|
|
1018
|
+
});
|
|
1019
|
+
return;
|
|
1020
|
+
} else if (!snapshot) {
|
|
1021
|
+
this.logger.debug("Snapshot cannot be persisted. No snapshot received.", { runId: this.#runId });
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
snapshot.suspendedSteps = { ...existingSnapshot.suspendedSteps, ...suspendedSteps };
|
|
1025
|
+
if (!existingSnapshot || snapshot === existingSnapshot) {
|
|
1026
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
1027
|
+
workflowName: this.name,
|
|
1028
|
+
runId: this.#runId,
|
|
1029
|
+
snapshot
|
|
1030
|
+
});
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
if (existingSnapshot?.childStates) {
|
|
1034
|
+
snapshot.childStates = { ...existingSnapshot.childStates, ...machineSnapshots };
|
|
1035
|
+
} else {
|
|
1036
|
+
snapshot.childStates = machineSnapshots;
|
|
1037
|
+
}
|
|
1038
|
+
await this.#mastra?.storage?.persistWorkflowSnapshot({
|
|
1039
|
+
workflowName: this.name,
|
|
1040
|
+
runId: this.#runId,
|
|
1041
|
+
snapshot
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
async getState() {
|
|
1045
|
+
const storedSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
1046
|
+
workflowName: this.name,
|
|
1047
|
+
runId: this.runId
|
|
1048
|
+
});
|
|
1049
|
+
const prevSnapshot = storedSnapshot ? {
|
|
1050
|
+
trigger: storedSnapshot,
|
|
1051
|
+
...Object.entries(storedSnapshot?.childStates ?? {}).reduce(
|
|
1052
|
+
(acc, [stepId, snapshot2]) => ({ ...acc, [stepId]: snapshot2 }),
|
|
1053
|
+
{}
|
|
835
1054
|
)
|
|
1055
|
+
} : {};
|
|
1056
|
+
const currentSnapshot = Object.entries(this.#machines).reduce(
|
|
1057
|
+
(acc, [stepId, machine]) => {
|
|
1058
|
+
const snapshot2 = machine.getSnapshot();
|
|
1059
|
+
if (!snapshot2) {
|
|
1060
|
+
return acc;
|
|
1061
|
+
}
|
|
1062
|
+
return {
|
|
1063
|
+
...acc,
|
|
1064
|
+
[stepId]: snapshot2
|
|
1065
|
+
};
|
|
1066
|
+
},
|
|
1067
|
+
{}
|
|
1068
|
+
);
|
|
1069
|
+
Object.assign(prevSnapshot, currentSnapshot);
|
|
1070
|
+
const trigger = prevSnapshot.trigger;
|
|
1071
|
+
delete prevSnapshot.trigger;
|
|
1072
|
+
const snapshot = { ...trigger};
|
|
1073
|
+
const m = getActivePathsAndStatus(prevSnapshot.value);
|
|
1074
|
+
return {
|
|
1075
|
+
runId: this.runId,
|
|
1076
|
+
value: snapshot.value,
|
|
1077
|
+
context: snapshot.context,
|
|
1078
|
+
activePaths: m,
|
|
1079
|
+
timestamp: Date.now()
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// src/workflows/workflow.ts
|
|
1085
|
+
var Workflow = class extends MastraBase {
|
|
1086
|
+
name;
|
|
1087
|
+
triggerSchema;
|
|
1088
|
+
#retryConfig;
|
|
1089
|
+
#mastra;
|
|
1090
|
+
#runs = /* @__PURE__ */ new Map();
|
|
1091
|
+
// registers stepIds on `after` calls
|
|
1092
|
+
#afterStepStack = [];
|
|
1093
|
+
#lastStepStack = [];
|
|
1094
|
+
#stepGraph = { initial: [] };
|
|
1095
|
+
#stepSubscriberGraph = {};
|
|
1096
|
+
#steps = {};
|
|
1097
|
+
#onStepTransition = /* @__PURE__ */ new Set();
|
|
1098
|
+
/**
|
|
1099
|
+
* Creates a new Workflow instance
|
|
1100
|
+
* @param name - Identifier for the workflow (not necessarily unique)
|
|
1101
|
+
* @param logger - Optional logger instance
|
|
1102
|
+
*/
|
|
1103
|
+
constructor({ name, triggerSchema, retryConfig, mastra }) {
|
|
1104
|
+
super({ component: "WORKFLOW", name });
|
|
1105
|
+
this.name = name;
|
|
1106
|
+
this.#retryConfig = retryConfig;
|
|
1107
|
+
this.triggerSchema = triggerSchema;
|
|
1108
|
+
this.#mastra = mastra;
|
|
1109
|
+
if (mastra?.logger) {
|
|
1110
|
+
this.logger = mastra?.logger;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
step(step, config) {
|
|
1114
|
+
const { variables = {} } = config || {};
|
|
1115
|
+
const requiredData = {};
|
|
1116
|
+
for (const [key, variable] of Object.entries(variables)) {
|
|
1117
|
+
if (variable && isVariableReference(variable)) {
|
|
1118
|
+
requiredData[key] = variable;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
const stepKey = this.#makeStepKey(step);
|
|
1122
|
+
const graphEntry = {
|
|
1123
|
+
step,
|
|
1124
|
+
config: {
|
|
1125
|
+
...this.#makeStepDef(stepKey),
|
|
1126
|
+
...config,
|
|
1127
|
+
data: requiredData
|
|
1128
|
+
}
|
|
836
1129
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
1130
|
+
this.#steps[stepKey] = step;
|
|
1131
|
+
const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
|
|
1132
|
+
const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
|
|
1133
|
+
if (parentStepKey && stepGraph) {
|
|
1134
|
+
if (!stepGraph.initial.some((step2) => step2.step.id === stepKey)) {
|
|
1135
|
+
stepGraph.initial.push(graphEntry);
|
|
1136
|
+
}
|
|
1137
|
+
stepGraph[stepKey] = [];
|
|
1138
|
+
} else {
|
|
1139
|
+
if (!this.#stepGraph[stepKey]) this.#stepGraph[stepKey] = [];
|
|
1140
|
+
this.#stepGraph.initial.push(graphEntry);
|
|
848
1141
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1142
|
+
this.#lastStepStack.push(stepKey);
|
|
1143
|
+
return this;
|
|
1144
|
+
}
|
|
1145
|
+
#makeStepKey(step) {
|
|
1146
|
+
return `${step.id}`;
|
|
1147
|
+
}
|
|
1148
|
+
then(step, config) {
|
|
1149
|
+
const { variables = {} } = config || {};
|
|
1150
|
+
const requiredData = {};
|
|
1151
|
+
for (const [key, variable] of Object.entries(variables)) {
|
|
1152
|
+
if (variable && isVariableReference(variable)) {
|
|
1153
|
+
requiredData[key] = variable;
|
|
1154
|
+
}
|
|
852
1155
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
1156
|
+
const lastStepKey = this.#lastStepStack[this.#lastStepStack.length - 1];
|
|
1157
|
+
const stepKey = this.#makeStepKey(step);
|
|
1158
|
+
const graphEntry = {
|
|
1159
|
+
step,
|
|
1160
|
+
config: {
|
|
1161
|
+
...this.#makeStepDef(stepKey),
|
|
1162
|
+
...config,
|
|
1163
|
+
data: requiredData
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
this.#steps[stepKey] = step;
|
|
1167
|
+
if (!lastStepKey) return this;
|
|
1168
|
+
const parentStepKey = this.#afterStepStack[this.#afterStepStack.length - 1];
|
|
1169
|
+
const stepGraph = this.#stepSubscriberGraph[parentStepKey || ""];
|
|
1170
|
+
if (parentStepKey && stepGraph && stepGraph[lastStepKey]) {
|
|
1171
|
+
stepGraph[lastStepKey].push(graphEntry);
|
|
1172
|
+
} else {
|
|
1173
|
+
if (!this.#stepGraph[lastStepKey]) this.#stepGraph[lastStepKey] = [];
|
|
1174
|
+
this.#stepGraph[lastStepKey].push(graphEntry);
|
|
859
1175
|
}
|
|
860
|
-
return this
|
|
1176
|
+
return this;
|
|
861
1177
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1178
|
+
after(step) {
|
|
1179
|
+
const stepKey = this.#makeStepKey(step);
|
|
1180
|
+
this.#afterStepStack.push(stepKey);
|
|
1181
|
+
if (!this.#stepSubscriberGraph[stepKey]) {
|
|
1182
|
+
this.#stepSubscriberGraph[stepKey] = { initial: [] };
|
|
866
1183
|
}
|
|
867
|
-
return this
|
|
1184
|
+
return this;
|
|
868
1185
|
}
|
|
869
1186
|
/**
|
|
870
|
-
*
|
|
871
|
-
* @param
|
|
872
|
-
* @
|
|
873
|
-
* @
|
|
1187
|
+
* Executes the workflow with the given trigger data
|
|
1188
|
+
* @param triggerData - Initial data to start the workflow with
|
|
1189
|
+
* @returns Promise resolving to workflow results or rejecting with error
|
|
1190
|
+
* @throws Error if trigger schema validation fails
|
|
874
1191
|
*/
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
if (stepId2 === "trigger") {
|
|
888
|
-
return context.triggerData;
|
|
889
|
-
}
|
|
890
|
-
const result = context.steps[stepId2];
|
|
891
|
-
if (result && result.status === "success") {
|
|
892
|
-
return result.output;
|
|
893
|
-
}
|
|
894
|
-
return void 0;
|
|
1192
|
+
createRun() {
|
|
1193
|
+
const run = new WorkflowInstance({
|
|
1194
|
+
logger: this.logger,
|
|
1195
|
+
name: this.name,
|
|
1196
|
+
mastra: this.#mastra,
|
|
1197
|
+
retryConfig: this.#retryConfig,
|
|
1198
|
+
steps: this.#steps,
|
|
1199
|
+
stepGraph: this.#stepGraph,
|
|
1200
|
+
stepSubscriberGraph: this.#stepSubscriberGraph,
|
|
1201
|
+
onStepTransition: this.#onStepTransition,
|
|
1202
|
+
onFinish: () => {
|
|
1203
|
+
this.#runs.delete(run.runId);
|
|
895
1204
|
}
|
|
1205
|
+
});
|
|
1206
|
+
this.#runs.set(run.runId, run);
|
|
1207
|
+
return {
|
|
1208
|
+
start: run.start.bind(run),
|
|
1209
|
+
runId: run.runId
|
|
896
1210
|
};
|
|
897
|
-
for (const [key, variable] of Object.entries(stepConfig.data)) {
|
|
898
|
-
const sourceData = variable.step === "trigger" ? context.triggerData : getStepResult(context.steps[variable.step.id]);
|
|
899
|
-
this.logger.debug(
|
|
900
|
-
`Got source data for ${key} variable from ${variable.step === "trigger" ? "trigger" : variable.step.id}`,
|
|
901
|
-
{
|
|
902
|
-
sourceData,
|
|
903
|
-
path: variable.path,
|
|
904
|
-
runId: this.#runId
|
|
905
|
-
}
|
|
906
|
-
);
|
|
907
|
-
if (!sourceData && variable.step !== "trigger") {
|
|
908
|
-
resolvedData[key] = void 0;
|
|
909
|
-
continue;
|
|
910
|
-
}
|
|
911
|
-
const value = variable.path === "" || variable.path === "." ? sourceData : get(sourceData, variable.path);
|
|
912
|
-
this.logger.debug(`Resolved variable ${key}`, {
|
|
913
|
-
value,
|
|
914
|
-
runId: this.#runId
|
|
915
|
-
});
|
|
916
|
-
resolvedData[key] = value;
|
|
917
|
-
}
|
|
918
|
-
return resolvedData;
|
|
919
1211
|
}
|
|
920
1212
|
/**
|
|
921
|
-
*
|
|
1213
|
+
* Rebuilds the machine with the current steps configuration and validates the workflow
|
|
1214
|
+
*
|
|
1215
|
+
* This is the last step of a workflow builder method chain
|
|
1216
|
+
* @throws Error if validation fails
|
|
1217
|
+
*
|
|
1218
|
+
* @returns this instance for method chaining
|
|
922
1219
|
*/
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
sourceData,
|
|
936
|
-
runId: this.#runId
|
|
937
|
-
});
|
|
938
|
-
if (!sourceData) {
|
|
939
|
-
return false;
|
|
940
|
-
}
|
|
941
|
-
let value = get(sourceData, path);
|
|
942
|
-
if (stepId !== "trigger" && path === "status" && !value) {
|
|
943
|
-
value = "success";
|
|
944
|
-
}
|
|
945
|
-
if (typeof queryValue === "object" && queryValue !== null) {
|
|
946
|
-
baseResult = sift(queryValue)(value);
|
|
947
|
-
} else {
|
|
948
|
-
baseResult = value === queryValue;
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
if ("ref" in condition) {
|
|
952
|
-
const { ref, query } = condition;
|
|
953
|
-
const sourceData = ref.step === "trigger" ? context.triggerData : getStepResult(context.steps[ref.step.id]);
|
|
954
|
-
this.logger.debug(`Got condition data from ${ref.step === "trigger" ? "trigger" : ref.step.id}`, {
|
|
955
|
-
sourceData,
|
|
956
|
-
runId: this.#runId
|
|
957
|
-
});
|
|
958
|
-
if (!sourceData) {
|
|
959
|
-
return false;
|
|
960
|
-
}
|
|
961
|
-
let value = get(sourceData, ref.path);
|
|
962
|
-
if (ref.step !== "trigger" && ref.path === "status" && !value) {
|
|
963
|
-
value = "success";
|
|
1220
|
+
commit() {
|
|
1221
|
+
return this;
|
|
1222
|
+
}
|
|
1223
|
+
// record all object paths that leads to a suspended state
|
|
1224
|
+
#getSuspendedPaths({
|
|
1225
|
+
value,
|
|
1226
|
+
path,
|
|
1227
|
+
suspendedPaths
|
|
1228
|
+
}) {
|
|
1229
|
+
if (typeof value === "string") {
|
|
1230
|
+
if (value === "suspended") {
|
|
1231
|
+
suspendedPaths.add(path);
|
|
964
1232
|
}
|
|
965
|
-
|
|
1233
|
+
} else {
|
|
1234
|
+
Object.keys(value).forEach(
|
|
1235
|
+
(key) => this.#getSuspendedPaths({ value: value[key], path: path ? `${path}.${key}` : key, suspendedPaths })
|
|
1236
|
+
);
|
|
966
1237
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
});
|
|
1238
|
+
}
|
|
1239
|
+
async #loadWorkflowSnapshot(runId) {
|
|
1240
|
+
if (!this.#mastra?.storage) {
|
|
1241
|
+
this.logger.debug("Snapshot cannot be loaded. Mastra engine is not initialized", { runId });
|
|
1242
|
+
return;
|
|
973
1243
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
orBranchResult,
|
|
978
|
-
runId: this.#runId
|
|
979
|
-
});
|
|
1244
|
+
const activeRun = this.#runs.get(runId);
|
|
1245
|
+
if (activeRun) {
|
|
1246
|
+
await activeRun.persistWorkflowSnapshot();
|
|
980
1247
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
});
|
|
986
|
-
return finalResult;
|
|
1248
|
+
return this.#mastra.storage.loadWorkflowSnapshot({ runId, workflowName: this.name });
|
|
1249
|
+
}
|
|
1250
|
+
getExecutionSpan(runId) {
|
|
1251
|
+
return this.#runs.get(runId)?.executionSpan;
|
|
987
1252
|
}
|
|
988
1253
|
#makeStepDef(stepId) {
|
|
989
1254
|
const executeStep = (handler2, spanName, attributes) => {
|
|
990
1255
|
return async (data) => {
|
|
991
|
-
return await context.with(
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1256
|
+
return await context.with(
|
|
1257
|
+
trace.setSpan(context.active(), this.getExecutionSpan(attributes?.runId ?? data?.runId)),
|
|
1258
|
+
async () => {
|
|
1259
|
+
return this.#mastra.telemetry.traceMethod(handler2, {
|
|
1260
|
+
spanName,
|
|
1261
|
+
attributes
|
|
1262
|
+
})(data);
|
|
1263
|
+
}
|
|
1264
|
+
);
|
|
997
1265
|
};
|
|
998
1266
|
};
|
|
999
1267
|
const handler = async ({ context, ...rest }) => {
|
|
@@ -1007,15 +1275,15 @@ var Workflow = class extends MastraBase {
|
|
|
1007
1275
|
};
|
|
1008
1276
|
const finalAction = this.#mastra?.telemetry ? executeStep(execute, `workflow.${this.name}.action.${stepId}`, {
|
|
1009
1277
|
componentName: this.name,
|
|
1010
|
-
runId:
|
|
1278
|
+
runId: rest.runId
|
|
1011
1279
|
}) : execute;
|
|
1012
1280
|
return finalAction ? await finalAction({ context: mergedData, ...rest }) : {};
|
|
1013
1281
|
};
|
|
1014
1282
|
const finalHandler = ({ context, ...rest }) => {
|
|
1015
|
-
if (this
|
|
1283
|
+
if (this.getExecutionSpan(rest?.runId)) {
|
|
1016
1284
|
return executeStep(handler, `workflow.${this.name}.step.${stepId}`, {
|
|
1017
1285
|
componentName: this.name,
|
|
1018
|
-
runId:
|
|
1286
|
+
runId: rest?.runId
|
|
1019
1287
|
})({ context, ...rest });
|
|
1020
1288
|
}
|
|
1021
1289
|
return handler({ context, ...rest });
|
|
@@ -1025,26 +1293,6 @@ var Workflow = class extends MastraBase {
|
|
|
1025
1293
|
data: {}
|
|
1026
1294
|
};
|
|
1027
1295
|
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Creates a map of step IDs to their respective delay values
|
|
1030
|
-
* @returns Object mapping step IDs to delay values
|
|
1031
|
-
*/
|
|
1032
|
-
#makeDelayMap() {
|
|
1033
|
-
const delayMap = {};
|
|
1034
|
-
Object.keys(this.#steps).forEach((stepId) => {
|
|
1035
|
-
delayMap[stepId] = this.#steps[stepId]?.retryConfig?.delay || this.#retryConfig?.delay || 1e3;
|
|
1036
|
-
});
|
|
1037
|
-
return delayMap;
|
|
1038
|
-
}
|
|
1039
|
-
/**
|
|
1040
|
-
* Cleans up the actor instance
|
|
1041
|
-
*/
|
|
1042
|
-
#cleanup() {
|
|
1043
|
-
if (this.#actor) {
|
|
1044
|
-
this.#actor.stop();
|
|
1045
|
-
this.#actor = null;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
1296
|
#getActivePathsAndStatus(value) {
|
|
1049
1297
|
const paths = [];
|
|
1050
1298
|
const traverse = (current, path = []) => {
|
|
@@ -1065,16 +1313,9 @@ var Workflow = class extends MastraBase {
|
|
|
1065
1313
|
return paths;
|
|
1066
1314
|
}
|
|
1067
1315
|
async getState(runId) {
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
return {
|
|
1072
|
-
runId,
|
|
1073
|
-
value: snapshot.value,
|
|
1074
|
-
context: snapshot.context,
|
|
1075
|
-
activePaths: m,
|
|
1076
|
-
timestamp: Date.now()
|
|
1077
|
-
};
|
|
1316
|
+
const run = this.#runs.get(runId);
|
|
1317
|
+
if (run) {
|
|
1318
|
+
return run.getState();
|
|
1078
1319
|
}
|
|
1079
1320
|
const storedSnapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
|
|
1080
1321
|
runId,
|
|
@@ -1103,6 +1344,14 @@ var Workflow = class extends MastraBase {
|
|
|
1103
1344
|
runId,
|
|
1104
1345
|
stepId,
|
|
1105
1346
|
context: resumeContext
|
|
1347
|
+
}) {
|
|
1348
|
+
await setTimeout(0);
|
|
1349
|
+
return this._resume({ runId, stepId, context: resumeContext });
|
|
1350
|
+
}
|
|
1351
|
+
async _resume({
|
|
1352
|
+
runId,
|
|
1353
|
+
stepId,
|
|
1354
|
+
context: resumeContext
|
|
1106
1355
|
}) {
|
|
1107
1356
|
const snapshot = await this.#loadWorkflowSnapshot(runId);
|
|
1108
1357
|
if (!snapshot) {
|
|
@@ -1115,6 +1364,15 @@ var Workflow = class extends MastraBase {
|
|
|
1115
1364
|
this.logger.debug("Failed to parse workflow snapshot for resume", { error, runId });
|
|
1116
1365
|
throw new Error("Failed to parse workflow snapshot");
|
|
1117
1366
|
}
|
|
1367
|
+
const origSnapshot = parsedSnapshot;
|
|
1368
|
+
const startStepId = parsedSnapshot.suspendedSteps?.[stepId];
|
|
1369
|
+
if (!startStepId) {
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
parsedSnapshot = startStepId === "trigger" ? parsedSnapshot : { ...parsedSnapshot?.childStates?.[startStepId], ...{ suspendedSteps: parsedSnapshot.suspendedSteps } };
|
|
1373
|
+
if (!parsedSnapshot) {
|
|
1374
|
+
throw new Error(`No snapshot found for step: ${stepId} starting at ${startStepId}`);
|
|
1375
|
+
}
|
|
1118
1376
|
if (resumeContext) {
|
|
1119
1377
|
parsedSnapshot.context.steps[stepId] = {
|
|
1120
1378
|
status: "success",
|
|
@@ -1136,20 +1394,6 @@ var Workflow = class extends MastraBase {
|
|
|
1136
1394
|
}
|
|
1137
1395
|
});
|
|
1138
1396
|
}
|
|
1139
|
-
const updateStepInHierarchy = (value, targetStepId) => {
|
|
1140
|
-
const result = {};
|
|
1141
|
-
for (const key of Object.keys(value)) {
|
|
1142
|
-
const currentValue = value[key];
|
|
1143
|
-
if (key === targetStepId) {
|
|
1144
|
-
result[key] = "pending";
|
|
1145
|
-
} else if (typeof currentValue === "object" && currentValue !== null) {
|
|
1146
|
-
result[key] = updateStepInHierarchy(currentValue, targetStepId);
|
|
1147
|
-
} else {
|
|
1148
|
-
result[key] = currentValue;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
return result;
|
|
1152
|
-
};
|
|
1153
1397
|
parsedSnapshot.value = updateStepInHierarchy(parsedSnapshot.value, stepId);
|
|
1154
1398
|
if (parsedSnapshot.context?.attempts) {
|
|
1155
1399
|
parsedSnapshot.context.attempts[stepId] = this.#steps[stepId]?.retryConfig?.attempts || this.#retryConfig?.attempts || 3;
|
|
@@ -1159,9 +1403,24 @@ var Workflow = class extends MastraBase {
|
|
|
1159
1403
|
runId,
|
|
1160
1404
|
stepId
|
|
1161
1405
|
});
|
|
1162
|
-
|
|
1163
|
-
|
|
1406
|
+
const run = this.#runs.get(runId) ?? new WorkflowInstance({
|
|
1407
|
+
logger: this.logger,
|
|
1408
|
+
name: this.name,
|
|
1409
|
+
mastra: this.#mastra,
|
|
1410
|
+
retryConfig: this.#retryConfig,
|
|
1411
|
+
steps: this.#steps,
|
|
1412
|
+
stepGraph: this.#stepGraph,
|
|
1413
|
+
stepSubscriberGraph: this.#stepSubscriberGraph,
|
|
1414
|
+
onStepTransition: this.#onStepTransition,
|
|
1164
1415
|
runId,
|
|
1416
|
+
onFinish: () => {
|
|
1417
|
+
this.#runs.delete(run.runId);
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
run.setState(origSnapshot?.value);
|
|
1421
|
+
this.#runs.set(run.runId, run);
|
|
1422
|
+
return run?.execute({
|
|
1423
|
+
snapshot: parsedSnapshot,
|
|
1165
1424
|
stepId
|
|
1166
1425
|
});
|
|
1167
1426
|
}
|
|
@@ -1217,4 +1476,4 @@ function createStep(opts) {
|
|
|
1217
1476
|
return new Step(opts);
|
|
1218
1477
|
}
|
|
1219
1478
|
|
|
1220
|
-
export { Step, Workflow, createStep, getStepResult, isErrorEvent, isTransitionEvent, isVariableReference };
|
|
1479
|
+
export { Step, Workflow, createStep, getActivePathsAndStatus, getStepResult, getSuspendedPaths, isErrorEvent, isFinalState, isTransitionEvent, isVariableReference, mergeChildValue, recursivelyCheckForFinalState, updateStepInHierarchy };
|