@ai-setting/roy-agent-core 1.4.11 → 1.4.13
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/index.d.ts +7825 -0
- package/dist/index.js +1040 -6526
- package/dist/shared/chunk-0q6s9wm6.js +249 -0
- package/dist/shared/chunk-1aakcfp1.js +15 -0
- package/dist/shared/chunk-1d4rwms4.js +25 -0
- package/dist/shared/chunk-1pf5mfgd.js +82 -0
- package/dist/shared/chunk-1qwabsm0.js +154 -0
- package/dist/shared/chunk-25x2pdtp.js +107 -0
- package/dist/shared/chunk-2b5kbhx3.js +366 -0
- package/dist/shared/chunk-91bas8w5.js +20 -0
- package/dist/shared/chunk-9qzt1v1p.js +10 -0
- package/dist/shared/chunk-a9qmy3sc.js +296 -0
- package/dist/shared/chunk-g6j5n3gv.js +549 -0
- package/dist/shared/chunk-hs7tbmje.js +24 -0
- package/dist/shared/chunk-mf5xqbdh.js +14 -0
- package/dist/shared/chunk-q9j99fsm.js +368 -0
- package/dist/shared/chunk-rncy3rtd.js +3140 -0
- package/dist/shared/chunk-t1rh6jtm.js +205 -0
- package/dist/shared/chunk-wbkh7wat.js +52 -0
- package/dist/shared/chunk-yqmx37vm.js +10 -0
- package/dist/shared/chunk-ze20rksg.js +102 -0
- package/package.json +8 -8
- package/dist/config/index.js +0 -1647
|
@@ -0,0 +1,3140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentComponentAdapter,
|
|
3
|
+
AskUserError,
|
|
4
|
+
createNodeInterruptEvent,
|
|
5
|
+
init_agent_component_adapter,
|
|
6
|
+
init_workflow_hil
|
|
7
|
+
} from "./chunk-0q6s9wm6.js";
|
|
8
|
+
import {
|
|
9
|
+
createLogger,
|
|
10
|
+
getMaxOutput,
|
|
11
|
+
init_logger,
|
|
12
|
+
simplifyFilePath
|
|
13
|
+
} from "./chunk-a9qmy3sc.js";
|
|
14
|
+
import {
|
|
15
|
+
getTracerProvider,
|
|
16
|
+
init_tracer_provider
|
|
17
|
+
} from "./chunk-q9j99fsm.js";
|
|
18
|
+
import {
|
|
19
|
+
__esm,
|
|
20
|
+
__export,
|
|
21
|
+
__legacyDecorateClassTS,
|
|
22
|
+
__require
|
|
23
|
+
} from "./chunk-wbkh7wat.js";
|
|
24
|
+
|
|
25
|
+
// src/env/workflow/engine/event-bus.ts
|
|
26
|
+
class EventBus {
|
|
27
|
+
handlers = new Map;
|
|
28
|
+
wildcardHandlers = new Set;
|
|
29
|
+
constructor() {}
|
|
30
|
+
on(eventType, handler) {
|
|
31
|
+
let handlers = this.handlers.get(eventType);
|
|
32
|
+
if (!handlers) {
|
|
33
|
+
handlers = new Set;
|
|
34
|
+
this.handlers.set(eventType, handlers);
|
|
35
|
+
}
|
|
36
|
+
handlers.add(handler);
|
|
37
|
+
return () => this.off(eventType, handler);
|
|
38
|
+
}
|
|
39
|
+
once(eventType, handler) {
|
|
40
|
+
let executed = false;
|
|
41
|
+
const wrappedHandler = async (event) => {
|
|
42
|
+
if (executed) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
executed = true;
|
|
46
|
+
try {
|
|
47
|
+
await handler(event);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Event handler error:", error);
|
|
50
|
+
}
|
|
51
|
+
this.off(eventType, wrappedHandler);
|
|
52
|
+
};
|
|
53
|
+
return this.on(eventType, wrappedHandler);
|
|
54
|
+
}
|
|
55
|
+
off(eventType, handler) {
|
|
56
|
+
const handlers = this.handlers.get(eventType);
|
|
57
|
+
if (handlers) {
|
|
58
|
+
handlers.delete(handler);
|
|
59
|
+
if (handlers.size === 0) {
|
|
60
|
+
this.handlers.delete(eventType);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
onAny(handler) {
|
|
65
|
+
this.wildcardHandlers.add(handler);
|
|
66
|
+
return () => {
|
|
67
|
+
this.wildcardHandlers.delete(handler);
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async publish(event, waitForHandlers = false) {
|
|
71
|
+
const handlers = this.handlers.get(event.type);
|
|
72
|
+
const handlerPromises = [];
|
|
73
|
+
if (handlers) {
|
|
74
|
+
for (const handler of handlers) {
|
|
75
|
+
const promise = this.executeHandler(handler, event);
|
|
76
|
+
handlerPromises.push(promise);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
for (const handler of this.wildcardHandlers) {
|
|
80
|
+
const promise = this.executeHandler(handler, event);
|
|
81
|
+
handlerPromises.push(promise);
|
|
82
|
+
}
|
|
83
|
+
if (waitForHandlers && handlerPromises.length > 0) {
|
|
84
|
+
await Promise.allSettled(handlerPromises);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async executeHandler(handler, event) {
|
|
88
|
+
try {
|
|
89
|
+
await handler(event);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error("Event handler error:", error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
clear() {
|
|
95
|
+
this.handlers.clear();
|
|
96
|
+
this.wildcardHandlers.clear();
|
|
97
|
+
}
|
|
98
|
+
getStats() {
|
|
99
|
+
let totalHandlers = 0;
|
|
100
|
+
for (const handlers of this.handlers.values()) {
|
|
101
|
+
totalHandlers += handlers.size;
|
|
102
|
+
}
|
|
103
|
+
totalHandlers += this.wildcardHandlers.size;
|
|
104
|
+
return {
|
|
105
|
+
eventTypes: this.handlers.size,
|
|
106
|
+
wildcardHandlers: this.wildcardHandlers.size,
|
|
107
|
+
totalHandlers
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
var init_event_bus = () => {};
|
|
112
|
+
|
|
113
|
+
// src/env/workflow/engine/dag-manager.ts
|
|
114
|
+
class DAGManager {
|
|
115
|
+
workflow;
|
|
116
|
+
nodeMap;
|
|
117
|
+
extendedDefinition = null;
|
|
118
|
+
cachedAnalysis = null;
|
|
119
|
+
constructor(workflow) {
|
|
120
|
+
if (!workflow.nodes || workflow.nodes.length === 0) {
|
|
121
|
+
throw new Error("At least one node is required");
|
|
122
|
+
}
|
|
123
|
+
this.workflow = workflow;
|
|
124
|
+
this.nodeMap = new Map;
|
|
125
|
+
for (const node of workflow.nodes) {
|
|
126
|
+
if (node.id === "") {
|
|
127
|
+
throw new Error("Node ID cannot be empty");
|
|
128
|
+
}
|
|
129
|
+
if (this.nodeMap.has(node.id)) {
|
|
130
|
+
throw new Error(`Duplicate node ID: ${node.id}`);
|
|
131
|
+
}
|
|
132
|
+
this.nodeMap.set(node.id, node);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
getExtendedDefinition() {
|
|
136
|
+
if (this.extendedDefinition) {
|
|
137
|
+
return this.extendedDefinition;
|
|
138
|
+
}
|
|
139
|
+
const analysis = this.analyze();
|
|
140
|
+
this.extendedDefinition = {
|
|
141
|
+
...this.workflow,
|
|
142
|
+
computedEntry: analysis.entryNodes,
|
|
143
|
+
nodeMap: this.nodeMap,
|
|
144
|
+
topologicalOrder: this.getTopologicalOrder()
|
|
145
|
+
};
|
|
146
|
+
return this.extendedDefinition;
|
|
147
|
+
}
|
|
148
|
+
analyze() {
|
|
149
|
+
if (this.cachedAnalysis) {
|
|
150
|
+
return this.cachedAnalysis;
|
|
151
|
+
}
|
|
152
|
+
const dependencies = this.buildDependenciesMap();
|
|
153
|
+
const dependents = this.buildDependentsMap(dependencies);
|
|
154
|
+
const entryNodes = this.findEntryNodes(dependencies);
|
|
155
|
+
const exitNodes = this.findExitNodes(dependents);
|
|
156
|
+
const levels = this.computeLevels(dependencies);
|
|
157
|
+
const criticalPath = this.findCriticalPath(levels, dependencies);
|
|
158
|
+
this.cachedAnalysis = {
|
|
159
|
+
entryNodes,
|
|
160
|
+
exitNodes,
|
|
161
|
+
levels,
|
|
162
|
+
dependencies,
|
|
163
|
+
dependents,
|
|
164
|
+
criticalPath
|
|
165
|
+
};
|
|
166
|
+
return this.cachedAnalysis;
|
|
167
|
+
}
|
|
168
|
+
buildDependenciesMap() {
|
|
169
|
+
const dependencies = new Map;
|
|
170
|
+
for (const node of this.workflow.nodes) {
|
|
171
|
+
const deps = node.depends_on || [];
|
|
172
|
+
dependencies.set(node.id, [...deps]);
|
|
173
|
+
}
|
|
174
|
+
return dependencies;
|
|
175
|
+
}
|
|
176
|
+
buildDependentsMap(dependencies) {
|
|
177
|
+
const dependentsMap = new Map;
|
|
178
|
+
for (const nodeId of dependencies.keys()) {
|
|
179
|
+
dependentsMap.set(nodeId, []);
|
|
180
|
+
}
|
|
181
|
+
for (const [nodeId, deps] of dependencies.entries()) {
|
|
182
|
+
for (const dep of deps) {
|
|
183
|
+
const nodeDependents = dependentsMap.get(dep) || [];
|
|
184
|
+
nodeDependents.push(nodeId);
|
|
185
|
+
dependentsMap.set(dep, nodeDependents);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return dependentsMap;
|
|
189
|
+
}
|
|
190
|
+
findEntryNodes(dependencies) {
|
|
191
|
+
const entryNodes = [];
|
|
192
|
+
for (const [nodeId, deps] of dependencies.entries()) {
|
|
193
|
+
if (deps.length === 0) {
|
|
194
|
+
entryNodes.push(nodeId);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return entryNodes;
|
|
198
|
+
}
|
|
199
|
+
findExitNodes(dependents) {
|
|
200
|
+
const exitNodes = [];
|
|
201
|
+
for (const [nodeId, deps] of dependents.entries()) {
|
|
202
|
+
if (deps.length === 0) {
|
|
203
|
+
exitNodes.push(nodeId);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return exitNodes;
|
|
207
|
+
}
|
|
208
|
+
computeLevels(dependencies) {
|
|
209
|
+
const levels = [];
|
|
210
|
+
const assigned = new Set;
|
|
211
|
+
const nodeLevels = new Map;
|
|
212
|
+
const dependentsMap = this.buildDependentsMap(dependencies);
|
|
213
|
+
const entryNodes = this.findEntryNodes(dependencies);
|
|
214
|
+
const queue = [];
|
|
215
|
+
for (const entry of entryNodes) {
|
|
216
|
+
queue.push({ nodeId: entry, level: 0 });
|
|
217
|
+
nodeLevels.set(entry, 0);
|
|
218
|
+
}
|
|
219
|
+
while (queue.length > 0) {
|
|
220
|
+
const { nodeId, level } = queue.shift();
|
|
221
|
+
if (assigned.has(nodeId)) {
|
|
222
|
+
const currentLevel = nodeLevels.get(nodeId) || 0;
|
|
223
|
+
if (level > currentLevel) {
|
|
224
|
+
nodeLevels.set(nodeId, level);
|
|
225
|
+
}
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
assigned.add(nodeId);
|
|
229
|
+
nodeLevels.set(nodeId, level);
|
|
230
|
+
const dependentsOfNode = dependentsMap.get(nodeId) || [];
|
|
231
|
+
for (const dependent of dependentsOfNode) {
|
|
232
|
+
if (!assigned.has(dependent)) {
|
|
233
|
+
queue.push({ nodeId: dependent, level: level + 1 });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const nodeId of dependencies.keys()) {
|
|
238
|
+
if (!nodeLevels.has(nodeId)) {
|
|
239
|
+
nodeLevels.set(nodeId, 0);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const maxLevel = Math.max(...nodeLevels.values(), 0);
|
|
243
|
+
for (let i = 0;i <= maxLevel; i++) {
|
|
244
|
+
levels.push([]);
|
|
245
|
+
}
|
|
246
|
+
for (const [nodeId, level] of nodeLevels.entries()) {
|
|
247
|
+
levels[level].push(nodeId);
|
|
248
|
+
}
|
|
249
|
+
return levels;
|
|
250
|
+
}
|
|
251
|
+
findCriticalPath(levels, dependencies) {
|
|
252
|
+
if (levels.length === 0) {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
const longestPath = new Map;
|
|
256
|
+
const allNodes = [];
|
|
257
|
+
for (const level of levels) {
|
|
258
|
+
allNodes.push(...level);
|
|
259
|
+
}
|
|
260
|
+
for (const nodeId of allNodes) {
|
|
261
|
+
const deps = dependencies.get(nodeId) || [];
|
|
262
|
+
if (deps.length === 0) {
|
|
263
|
+
longestPath.set(nodeId, { length: 1, path: [nodeId] });
|
|
264
|
+
} else {
|
|
265
|
+
let maxLength2 = 0;
|
|
266
|
+
let maxPath = [];
|
|
267
|
+
for (const dep of deps) {
|
|
268
|
+
const depInfo = longestPath.get(dep);
|
|
269
|
+
if (depInfo && depInfo.length > maxLength2) {
|
|
270
|
+
maxLength2 = depInfo.length;
|
|
271
|
+
maxPath = depInfo.path;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
longestPath.set(nodeId, {
|
|
275
|
+
length: maxLength2 + 1,
|
|
276
|
+
path: [...maxPath, nodeId]
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
let maxLength = 0;
|
|
281
|
+
let criticalPath = [];
|
|
282
|
+
for (const [, info] of longestPath.entries()) {
|
|
283
|
+
if (info.length > maxLength) {
|
|
284
|
+
maxLength = info.length;
|
|
285
|
+
criticalPath = info.path;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return criticalPath;
|
|
289
|
+
}
|
|
290
|
+
getTopologicalOrder() {
|
|
291
|
+
const dependencies = this.buildDependenciesMap();
|
|
292
|
+
const dependents = this.buildDependentsMap(dependencies);
|
|
293
|
+
const inDegree = new Map;
|
|
294
|
+
for (const nodeId of dependencies.keys()) {
|
|
295
|
+
inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
|
|
296
|
+
}
|
|
297
|
+
const queue = [];
|
|
298
|
+
for (const [nodeId, degree] of inDegree.entries()) {
|
|
299
|
+
if (degree === 0) {
|
|
300
|
+
queue.push(nodeId);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
const result = [];
|
|
304
|
+
while (queue.length > 0) {
|
|
305
|
+
const nodeId = queue.shift();
|
|
306
|
+
result.push(nodeId);
|
|
307
|
+
const nodeDependents = dependents.get(nodeId) || [];
|
|
308
|
+
for (const dependent of nodeDependents) {
|
|
309
|
+
const currentDegree = inDegree.get(dependent) || 0;
|
|
310
|
+
inDegree.set(dependent, currentDegree - 1);
|
|
311
|
+
if (currentDegree - 1 === 0) {
|
|
312
|
+
queue.push(dependent);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
getReadyNodes(completedNodes) {
|
|
319
|
+
const dependencies = this.buildDependenciesMap();
|
|
320
|
+
const ready = [];
|
|
321
|
+
for (const nodeId of dependencies.keys()) {
|
|
322
|
+
if (completedNodes.has(nodeId)) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (this.areDependenciesMet(nodeId, completedNodes)) {
|
|
326
|
+
ready.push(nodeId);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return ready;
|
|
330
|
+
}
|
|
331
|
+
areDependenciesMet(nodeId, completedNodes) {
|
|
332
|
+
const node = this.nodeMap.get(nodeId);
|
|
333
|
+
if (!node) {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const dependencies = node.depends_on || [];
|
|
337
|
+
for (const dep of dependencies) {
|
|
338
|
+
if (!completedNodes.has(dep)) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
isCyclic() {
|
|
345
|
+
const dependencies = this.buildDependenciesMap();
|
|
346
|
+
const order = this.getTopologicalOrderInternal(dependencies);
|
|
347
|
+
return order.length !== this.workflow.nodes.length;
|
|
348
|
+
}
|
|
349
|
+
getTopologicalOrderInternal(dependencies) {
|
|
350
|
+
const dependents = this.buildDependentsMap(dependencies);
|
|
351
|
+
const inDegree = new Map;
|
|
352
|
+
for (const nodeId of dependencies.keys()) {
|
|
353
|
+
inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
|
|
354
|
+
}
|
|
355
|
+
const queue = [];
|
|
356
|
+
for (const [nodeId, degree] of inDegree.entries()) {
|
|
357
|
+
if (degree === 0) {
|
|
358
|
+
queue.push(nodeId);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const result = [];
|
|
362
|
+
while (queue.length > 0) {
|
|
363
|
+
const nodeId = queue.shift();
|
|
364
|
+
result.push(nodeId);
|
|
365
|
+
const nodeDependents = dependents.get(nodeId) || [];
|
|
366
|
+
for (const dependent of nodeDependents) {
|
|
367
|
+
const currentDegree = inDegree.get(dependent) || 0;
|
|
368
|
+
inDegree.set(dependent, currentDegree - 1);
|
|
369
|
+
if (currentDegree - 1 === 0) {
|
|
370
|
+
queue.push(dependent);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return result;
|
|
375
|
+
}
|
|
376
|
+
validate() {
|
|
377
|
+
const errors = [];
|
|
378
|
+
const nodeIds = new Set;
|
|
379
|
+
for (const node of this.workflow.nodes) {
|
|
380
|
+
if (node.id === "") {
|
|
381
|
+
errors.push("Node ID cannot be empty");
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
if (nodeIds.has(node.id)) {
|
|
385
|
+
errors.push(`Duplicate node ID: ${node.id}`);
|
|
386
|
+
}
|
|
387
|
+
nodeIds.add(node.id);
|
|
388
|
+
}
|
|
389
|
+
for (const node of this.workflow.nodes) {
|
|
390
|
+
const deps = node.depends_on || [];
|
|
391
|
+
for (const dep of deps) {
|
|
392
|
+
if (!nodeIds.has(dep)) {
|
|
393
|
+
errors.push(`Node '${node.id}' depends on non-existent node '${dep}'`);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (this.isCyclic()) {
|
|
398
|
+
errors.push("Workflow contains a cycle");
|
|
399
|
+
}
|
|
400
|
+
return {
|
|
401
|
+
valid: errors.length === 0,
|
|
402
|
+
errors
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
addNode(node) {
|
|
406
|
+
if (!node.id || node.id.trim() === "") {
|
|
407
|
+
throw new Error("Node ID cannot be empty");
|
|
408
|
+
}
|
|
409
|
+
if (this.nodeMap.has(node.id)) {
|
|
410
|
+
throw new Error(`Node with ID '${node.id}' already exists`);
|
|
411
|
+
}
|
|
412
|
+
const deps = node.depends_on || [];
|
|
413
|
+
for (const dep of deps) {
|
|
414
|
+
if (!this.nodeMap.has(dep)) {
|
|
415
|
+
throw new Error(`Cannot add node '${node.id}': depends on non-existent node '${dep}'`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const originalNodes = [...this.workflow.nodes];
|
|
419
|
+
this.workflow.nodes.push(node);
|
|
420
|
+
if (this.isCyclic()) {
|
|
421
|
+
this.workflow.nodes = originalNodes;
|
|
422
|
+
throw new Error(`Cannot add node '${node.id}': would create a cycle in the workflow`);
|
|
423
|
+
}
|
|
424
|
+
this.nodeMap.set(node.id, node);
|
|
425
|
+
this.cachedAnalysis = null;
|
|
426
|
+
this.extendedDefinition = null;
|
|
427
|
+
}
|
|
428
|
+
removeNode(nodeId) {
|
|
429
|
+
if (!this.nodeMap.has(nodeId)) {
|
|
430
|
+
throw new Error(`Node '${nodeId}' does not exist`);
|
|
431
|
+
}
|
|
432
|
+
const dependents = this.getDependents(nodeId);
|
|
433
|
+
if (dependents.length > 0) {
|
|
434
|
+
throw new Error(`Cannot remove node '${nodeId}': other nodes depend on it: ${dependents.join(", ")}`);
|
|
435
|
+
}
|
|
436
|
+
this.workflow.nodes = this.workflow.nodes.filter((n) => n.id !== nodeId);
|
|
437
|
+
this.nodeMap.delete(nodeId);
|
|
438
|
+
this.cachedAnalysis = null;
|
|
439
|
+
this.extendedDefinition = null;
|
|
440
|
+
}
|
|
441
|
+
getDependents(nodeId) {
|
|
442
|
+
const analysis = this.analyze();
|
|
443
|
+
return analysis.dependents.get(nodeId) || [];
|
|
444
|
+
}
|
|
445
|
+
getDefinition() {
|
|
446
|
+
return this.workflow;
|
|
447
|
+
}
|
|
448
|
+
getNode(nodeId) {
|
|
449
|
+
return this.nodeMap.get(nodeId);
|
|
450
|
+
}
|
|
451
|
+
getNodeIds() {
|
|
452
|
+
return Array.from(this.nodeMap.keys());
|
|
453
|
+
}
|
|
454
|
+
getNodeCount() {
|
|
455
|
+
return this.nodeMap.size;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
var init_dag_manager = () => {};
|
|
459
|
+
|
|
460
|
+
// src/env/workflow/engine/scheduler.ts
|
|
461
|
+
class Scheduler {
|
|
462
|
+
dagManager;
|
|
463
|
+
options;
|
|
464
|
+
pending = new Set;
|
|
465
|
+
ready = new Set;
|
|
466
|
+
running = new Set;
|
|
467
|
+
completed = new Set;
|
|
468
|
+
failed = new Set;
|
|
469
|
+
skipped = new Set;
|
|
470
|
+
constructor(dagManager, options) {
|
|
471
|
+
this.dagManager = dagManager;
|
|
472
|
+
const parallelLimit = options?.parallelLimit;
|
|
473
|
+
this.options = {
|
|
474
|
+
parallelLimit: parallelLimit === undefined ? 1 : parallelLimit
|
|
475
|
+
};
|
|
476
|
+
const analysis = dagManager.analyze();
|
|
477
|
+
for (const nodeId of analysis.dependencies.keys()) {
|
|
478
|
+
this.pending.add(nodeId);
|
|
479
|
+
}
|
|
480
|
+
this.updateReadyNodes(new Set);
|
|
481
|
+
}
|
|
482
|
+
getReadyNodes(completedNodes) {
|
|
483
|
+
const allCompleted = new Set(completedNodes);
|
|
484
|
+
for (const nodeId of this.completed) {
|
|
485
|
+
allCompleted.add(nodeId);
|
|
486
|
+
}
|
|
487
|
+
const readyFromDag = this.dagManager.getReadyNodes(allCompleted);
|
|
488
|
+
const ready = [];
|
|
489
|
+
for (const nodeId of readyFromDag) {
|
|
490
|
+
const isProcessed = this.running.has(nodeId) || this.completed.has(nodeId) || this.failed.has(nodeId) || this.skipped.has(nodeId);
|
|
491
|
+
if (!isProcessed) {
|
|
492
|
+
ready.push(nodeId);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return ready.sort();
|
|
496
|
+
}
|
|
497
|
+
getRunningCount() {
|
|
498
|
+
return this.running.size;
|
|
499
|
+
}
|
|
500
|
+
canStartMore() {
|
|
501
|
+
if (this.options.parallelLimit === null) {
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
if (this.options.parallelLimit <= 0) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
return this.running.size < this.options.parallelLimit;
|
|
508
|
+
}
|
|
509
|
+
markStarted(nodeId) {
|
|
510
|
+
if (!this.running.has(nodeId)) {
|
|
511
|
+
this.running.add(nodeId);
|
|
512
|
+
this.ready.delete(nodeId);
|
|
513
|
+
this.pending.delete(nodeId);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
isRunning(nodeId) {
|
|
517
|
+
return this.running.has(nodeId);
|
|
518
|
+
}
|
|
519
|
+
isCompleted(nodeId) {
|
|
520
|
+
return this.completed.has(nodeId);
|
|
521
|
+
}
|
|
522
|
+
isFailed(nodeId) {
|
|
523
|
+
return this.failed.has(nodeId);
|
|
524
|
+
}
|
|
525
|
+
isPending(nodeId) {
|
|
526
|
+
return this.pending.has(nodeId);
|
|
527
|
+
}
|
|
528
|
+
isReady(nodeId) {
|
|
529
|
+
return this.ready.has(nodeId);
|
|
530
|
+
}
|
|
531
|
+
markCompleted(nodeId) {
|
|
532
|
+
this.running.delete(nodeId);
|
|
533
|
+
this.ready.delete(nodeId);
|
|
534
|
+
this.pending.delete(nodeId);
|
|
535
|
+
this.failed.delete(nodeId);
|
|
536
|
+
this.skipped.delete(nodeId);
|
|
537
|
+
this.completed.add(nodeId);
|
|
538
|
+
}
|
|
539
|
+
markFailed(nodeId) {
|
|
540
|
+
this.running.delete(nodeId);
|
|
541
|
+
this.ready.delete(nodeId);
|
|
542
|
+
this.pending.delete(nodeId);
|
|
543
|
+
this.completed.delete(nodeId);
|
|
544
|
+
this.skipped.delete(nodeId);
|
|
545
|
+
this.failed.add(nodeId);
|
|
546
|
+
}
|
|
547
|
+
markSkipped(nodeId) {
|
|
548
|
+
if (this.running.has(nodeId)) {
|
|
549
|
+
this.running.delete(nodeId);
|
|
550
|
+
}
|
|
551
|
+
if (this.ready.has(nodeId)) {
|
|
552
|
+
this.ready.delete(nodeId);
|
|
553
|
+
}
|
|
554
|
+
if (this.pending.has(nodeId)) {
|
|
555
|
+
this.pending.delete(nodeId);
|
|
556
|
+
}
|
|
557
|
+
this.skipped.add(nodeId);
|
|
558
|
+
}
|
|
559
|
+
reset() {
|
|
560
|
+
this.running.clear();
|
|
561
|
+
this.completed.clear();
|
|
562
|
+
this.failed.clear();
|
|
563
|
+
this.skipped.clear();
|
|
564
|
+
const analysis = this.dagManager.analyze();
|
|
565
|
+
this.pending.clear();
|
|
566
|
+
this.ready.clear();
|
|
567
|
+
for (const nodeId of analysis.dependencies.keys()) {
|
|
568
|
+
this.pending.add(nodeId);
|
|
569
|
+
}
|
|
570
|
+
this.updateReadyNodes(new Set);
|
|
571
|
+
}
|
|
572
|
+
getState() {
|
|
573
|
+
this.updateReadyNodes(new Set);
|
|
574
|
+
return {
|
|
575
|
+
pending: Array.from(this.pending).sort(),
|
|
576
|
+
ready: Array.from(this.ready).sort(),
|
|
577
|
+
running: Array.from(this.running).sort(),
|
|
578
|
+
completed: Array.from(this.completed).sort(),
|
|
579
|
+
failed: Array.from(this.failed).sort(),
|
|
580
|
+
skipped: Array.from(this.skipped).sort()
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
updateReadyNodes(completedNodes) {
|
|
584
|
+
const allCompleted = new Set(completedNodes);
|
|
585
|
+
for (const nodeId of this.completed) {
|
|
586
|
+
allCompleted.add(nodeId);
|
|
587
|
+
}
|
|
588
|
+
const analysis = this.dagManager.analyze();
|
|
589
|
+
const allNodeIds = Array.from(analysis.dependencies.keys());
|
|
590
|
+
this.ready.clear();
|
|
591
|
+
for (const nodeId of allNodeIds) {
|
|
592
|
+
if (this.running.has(nodeId) || this.completed.has(nodeId) || this.failed.has(nodeId) || this.skipped.has(nodeId)) {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
if (this.dagManager.areDependenciesMet(nodeId, allCompleted)) {
|
|
596
|
+
this.ready.add(nodeId);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
getParallelLimit() {
|
|
601
|
+
return this.options.parallelLimit;
|
|
602
|
+
}
|
|
603
|
+
setParallelLimit(limit) {
|
|
604
|
+
this.options.parallelLimit = limit;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
var init_scheduler = () => {};
|
|
608
|
+
|
|
609
|
+
// src/env/workflow/types/event.ts
|
|
610
|
+
import { z } from "zod";
|
|
611
|
+
function createWorkflowEvent(type, runId, data) {
|
|
612
|
+
return {
|
|
613
|
+
type,
|
|
614
|
+
run_id: runId,
|
|
615
|
+
timestamp: Date.now(),
|
|
616
|
+
...data
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
var BaseEventSchema, WorkflowStartedEventSchema, WorkflowPausedEventSchema, WorkflowResumedEventSchema, WorkflowStoppedEventSchema, WorkflowCompletedEventSchema, WorkflowFailedEventSchema, WorkflowOutputEventSchema, NodeScheduledEventSchema, NodeStartedEventSchema, NodeProgressEventSchema, NodeCompletedEventSchema, NodeFailedEventSchema, NodeSkippedEventSchema, NodeDataEventSchema, NodeAddedEventSchema, NodeRemovedEventSchema, ControlPauseEventSchema, ControlResumeEventSchema, ControlStopEventSchema, NodeInterruptEventSchema, WorkflowAskUserEventSchema, WorkflowEventSchema;
|
|
620
|
+
var init_event = __esm(() => {
|
|
621
|
+
BaseEventSchema = z.object({
|
|
622
|
+
type: z.string(),
|
|
623
|
+
run_id: z.string(),
|
|
624
|
+
timestamp: z.number()
|
|
625
|
+
});
|
|
626
|
+
WorkflowStartedEventSchema = BaseEventSchema.extend({
|
|
627
|
+
type: z.literal("workflow.started"),
|
|
628
|
+
workflow_name: z.string(),
|
|
629
|
+
input: z.record(z.string(), z.unknown()).optional()
|
|
630
|
+
});
|
|
631
|
+
WorkflowPausedEventSchema = BaseEventSchema.extend({
|
|
632
|
+
type: z.literal("workflow.paused")
|
|
633
|
+
});
|
|
634
|
+
WorkflowResumedEventSchema = BaseEventSchema.extend({
|
|
635
|
+
type: z.literal("workflow.resumed")
|
|
636
|
+
});
|
|
637
|
+
WorkflowStoppedEventSchema = BaseEventSchema.extend({
|
|
638
|
+
type: z.literal("workflow.stopped"),
|
|
639
|
+
reason: z.string()
|
|
640
|
+
});
|
|
641
|
+
WorkflowCompletedEventSchema = BaseEventSchema.extend({
|
|
642
|
+
type: z.literal("workflow.completed"),
|
|
643
|
+
result: z.record(z.string(), z.unknown()).optional(),
|
|
644
|
+
duration_ms: z.number()
|
|
645
|
+
});
|
|
646
|
+
WorkflowFailedEventSchema = BaseEventSchema.extend({
|
|
647
|
+
type: z.literal("workflow.failed"),
|
|
648
|
+
error: z.object({
|
|
649
|
+
message: z.string(),
|
|
650
|
+
stack: z.string().optional()
|
|
651
|
+
}),
|
|
652
|
+
failed_at: z.string()
|
|
653
|
+
});
|
|
654
|
+
WorkflowOutputEventSchema = BaseEventSchema.extend({
|
|
655
|
+
type: z.literal("workflow.output"),
|
|
656
|
+
output: z.record(z.string(), z.unknown())
|
|
657
|
+
});
|
|
658
|
+
NodeScheduledEventSchema = BaseEventSchema.extend({
|
|
659
|
+
type: z.literal("node.scheduled"),
|
|
660
|
+
node_id: z.string()
|
|
661
|
+
});
|
|
662
|
+
NodeStartedEventSchema = BaseEventSchema.extend({
|
|
663
|
+
type: z.literal("node.started"),
|
|
664
|
+
node_id: z.string(),
|
|
665
|
+
input: z.any(),
|
|
666
|
+
agentSessionId: z.string().optional(),
|
|
667
|
+
userResponse: z.string().optional()
|
|
668
|
+
});
|
|
669
|
+
NodeProgressEventSchema = BaseEventSchema.extend({
|
|
670
|
+
type: z.literal("node.progress"),
|
|
671
|
+
node_id: z.string(),
|
|
672
|
+
progress: z.number(),
|
|
673
|
+
message: z.string().optional()
|
|
674
|
+
});
|
|
675
|
+
NodeCompletedEventSchema = BaseEventSchema.extend({
|
|
676
|
+
type: z.literal("node.completed"),
|
|
677
|
+
node_id: z.string(),
|
|
678
|
+
output: z.any(),
|
|
679
|
+
duration_ms: z.number()
|
|
680
|
+
});
|
|
681
|
+
NodeFailedEventSchema = BaseEventSchema.extend({
|
|
682
|
+
type: z.literal("node.failed"),
|
|
683
|
+
node_id: z.string(),
|
|
684
|
+
error: z.object({
|
|
685
|
+
message: z.string(),
|
|
686
|
+
stack: z.string().optional()
|
|
687
|
+
})
|
|
688
|
+
});
|
|
689
|
+
NodeSkippedEventSchema = BaseEventSchema.extend({
|
|
690
|
+
type: z.literal("node.skipped"),
|
|
691
|
+
node_id: z.string(),
|
|
692
|
+
reason: z.string()
|
|
693
|
+
});
|
|
694
|
+
NodeDataEventSchema = BaseEventSchema.extend({
|
|
695
|
+
type: z.literal("node.data"),
|
|
696
|
+
from_node: z.string(),
|
|
697
|
+
to_node: z.string(),
|
|
698
|
+
data: z.any()
|
|
699
|
+
});
|
|
700
|
+
NodeAddedEventSchema = BaseEventSchema.extend({
|
|
701
|
+
type: z.literal("node.added"),
|
|
702
|
+
node_id: z.string(),
|
|
703
|
+
node: z.any()
|
|
704
|
+
});
|
|
705
|
+
NodeRemovedEventSchema = BaseEventSchema.extend({
|
|
706
|
+
type: z.literal("node.removed"),
|
|
707
|
+
node_id: z.string()
|
|
708
|
+
});
|
|
709
|
+
ControlPauseEventSchema = BaseEventSchema.extend({
|
|
710
|
+
type: z.literal("control.pause")
|
|
711
|
+
});
|
|
712
|
+
ControlResumeEventSchema = BaseEventSchema.extend({
|
|
713
|
+
type: z.literal("control.resume")
|
|
714
|
+
});
|
|
715
|
+
ControlStopEventSchema = BaseEventSchema.extend({
|
|
716
|
+
type: z.literal("control.stop")
|
|
717
|
+
});
|
|
718
|
+
NodeInterruptEventSchema = BaseEventSchema.extend({
|
|
719
|
+
type: z.literal("node.interrupt"),
|
|
720
|
+
node_id: z.string(),
|
|
721
|
+
node_type: z.string(),
|
|
722
|
+
query: z.string()
|
|
723
|
+
});
|
|
724
|
+
WorkflowAskUserEventSchema = BaseEventSchema.extend({
|
|
725
|
+
type: z.literal("workflow.ask-user"),
|
|
726
|
+
session_id: z.string(),
|
|
727
|
+
node_id: z.string(),
|
|
728
|
+
node_type: z.string(),
|
|
729
|
+
query: z.string()
|
|
730
|
+
});
|
|
731
|
+
WorkflowEventSchema = z.union([
|
|
732
|
+
WorkflowStartedEventSchema,
|
|
733
|
+
WorkflowPausedEventSchema,
|
|
734
|
+
WorkflowResumedEventSchema,
|
|
735
|
+
WorkflowStoppedEventSchema,
|
|
736
|
+
WorkflowCompletedEventSchema,
|
|
737
|
+
WorkflowFailedEventSchema,
|
|
738
|
+
WorkflowOutputEventSchema,
|
|
739
|
+
NodeScheduledEventSchema,
|
|
740
|
+
NodeStartedEventSchema,
|
|
741
|
+
NodeProgressEventSchema,
|
|
742
|
+
NodeCompletedEventSchema,
|
|
743
|
+
NodeFailedEventSchema,
|
|
744
|
+
NodeSkippedEventSchema,
|
|
745
|
+
NodeDataEventSchema,
|
|
746
|
+
NodeAddedEventSchema,
|
|
747
|
+
NodeRemovedEventSchema,
|
|
748
|
+
ControlPauseEventSchema,
|
|
749
|
+
ControlResumeEventSchema,
|
|
750
|
+
ControlStopEventSchema,
|
|
751
|
+
NodeInterruptEventSchema,
|
|
752
|
+
WorkflowAskUserEventSchema
|
|
753
|
+
]);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
// src/env/workflow/types/workflow.ts
|
|
757
|
+
import { z as z2 } from "zod";
|
|
758
|
+
var DependsOnSchema, RetryConfigSchema, NodeDefinitionSchema, WorkflowConfigSchema, OutputDefinitionSchema, WorkflowMetadataSchema, WorkflowDefinitionSchema;
|
|
759
|
+
var init_workflow = __esm(() => {
|
|
760
|
+
DependsOnSchema = z2.array(z2.string());
|
|
761
|
+
RetryConfigSchema = z2.object({
|
|
762
|
+
max_attempts: z2.number().min(1).default(1),
|
|
763
|
+
backoff: z2.enum(["fixed", "exponential"]).default("exponential"),
|
|
764
|
+
initial_delay: z2.number().min(0).default(1000)
|
|
765
|
+
});
|
|
766
|
+
NodeDefinitionSchema = z2.object({
|
|
767
|
+
id: z2.string().min(1, "Node ID is required"),
|
|
768
|
+
type: z2.string().min(1, "Node type is required"),
|
|
769
|
+
name: z2.string().optional(),
|
|
770
|
+
config: z2.record(z2.string(), z2.unknown()).optional().default({}),
|
|
771
|
+
depends_on: z2.array(z2.string()).optional(),
|
|
772
|
+
condition: z2.string().optional(),
|
|
773
|
+
retry: RetryConfigSchema.optional(),
|
|
774
|
+
timeout: z2.number().optional()
|
|
775
|
+
});
|
|
776
|
+
WorkflowConfigSchema = z2.object({
|
|
777
|
+
parallel_limit: z2.number().nullable().optional(),
|
|
778
|
+
timeout: z2.number().nullable().optional(),
|
|
779
|
+
retry: RetryConfigSchema.optional(),
|
|
780
|
+
debug: z2.boolean().optional()
|
|
781
|
+
});
|
|
782
|
+
OutputDefinitionSchema = z2.object({
|
|
783
|
+
name: z2.string(),
|
|
784
|
+
source: z2.string(),
|
|
785
|
+
path: z2.string()
|
|
786
|
+
});
|
|
787
|
+
WorkflowMetadataSchema = z2.object({
|
|
788
|
+
author: z2.string().optional(),
|
|
789
|
+
taskId: z2.number().optional(),
|
|
790
|
+
tags: z2.array(z2.string()).optional().default([]),
|
|
791
|
+
created_at: z2.string().optional(),
|
|
792
|
+
updated_at: z2.string().optional()
|
|
793
|
+
});
|
|
794
|
+
WorkflowDefinitionSchema = z2.object({
|
|
795
|
+
name: z2.string().min(1, "Workflow name is required"),
|
|
796
|
+
version: z2.string().default("1.0"),
|
|
797
|
+
description: z2.string().optional(),
|
|
798
|
+
config: WorkflowConfigSchema.optional().default({}),
|
|
799
|
+
nodes: z2.array(NodeDefinitionSchema).min(1, "At least one node is required"),
|
|
800
|
+
entry: z2.union([z2.string(), z2.array(z2.string())]).default("__default_entry__"),
|
|
801
|
+
outputs: z2.array(OutputDefinitionSchema).optional().default([]),
|
|
802
|
+
metadata: WorkflowMetadataSchema.optional().default({})
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// src/env/workflow/types/workflow-message.ts
|
|
807
|
+
import { z as z3 } from "zod";
|
|
808
|
+
var WorkflowMessageRoleSchema;
|
|
809
|
+
var init_workflow_message = __esm(() => {
|
|
810
|
+
init_workflow_hil();
|
|
811
|
+
WorkflowMessageRoleSchema = z3.enum([
|
|
812
|
+
"workflow.node.call",
|
|
813
|
+
"workflow.node.interrupt",
|
|
814
|
+
"workflow.node.result",
|
|
815
|
+
"workflow.node.resume"
|
|
816
|
+
]);
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// src/env/workflow/types/workflow-session.ts
|
|
820
|
+
var init_workflow_session = () => {};
|
|
821
|
+
|
|
822
|
+
// src/env/workflow/types/context.ts
|
|
823
|
+
var init_context = () => {};
|
|
824
|
+
|
|
825
|
+
// src/env/workflow/types/run.ts
|
|
826
|
+
import { z as z4 } from "zod";
|
|
827
|
+
var RunStatusSchema, NodeStatusSchema;
|
|
828
|
+
var init_run = __esm(() => {
|
|
829
|
+
init_workflow_message();
|
|
830
|
+
RunStatusSchema = z4.enum([
|
|
831
|
+
"idle",
|
|
832
|
+
"running",
|
|
833
|
+
"paused",
|
|
834
|
+
"stopped",
|
|
835
|
+
"completed",
|
|
836
|
+
"failed"
|
|
837
|
+
]);
|
|
838
|
+
NodeStatusSchema = z4.enum([
|
|
839
|
+
"pending",
|
|
840
|
+
"scheduled",
|
|
841
|
+
"started",
|
|
842
|
+
"running",
|
|
843
|
+
"completed",
|
|
844
|
+
"failed",
|
|
845
|
+
"skipped"
|
|
846
|
+
]);
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
// src/env/workflow/types/index.ts
|
|
850
|
+
var init_types = __esm(() => {
|
|
851
|
+
init_run();
|
|
852
|
+
init_workflow();
|
|
853
|
+
init_workflow_message();
|
|
854
|
+
init_workflow_session();
|
|
855
|
+
init_context();
|
|
856
|
+
init_workflow_hil();
|
|
857
|
+
init_event();
|
|
858
|
+
init_run();
|
|
859
|
+
});
|
|
860
|
+
|
|
861
|
+
// src/env/log-trace/decorator.ts
|
|
862
|
+
function Traced(options) {
|
|
863
|
+
return function(target, propertyKey, descriptor) {
|
|
864
|
+
const originalFn = descriptor.value;
|
|
865
|
+
const spanName = options?.name || propertyKey;
|
|
866
|
+
descriptor.value = wrapFunction(originalFn, spanName, {
|
|
867
|
+
recordParams: options?.recordParams ?? true,
|
|
868
|
+
recordResult: options?.recordResult ?? false,
|
|
869
|
+
recordError: options?.recordError ?? true,
|
|
870
|
+
log: options?.log ?? false,
|
|
871
|
+
maxLogSize: options?.maxLogSize,
|
|
872
|
+
paramFilter: options?.paramFilter
|
|
873
|
+
});
|
|
874
|
+
return descriptor;
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
function TracedAs(name, options) {
|
|
878
|
+
return Traced({ name, ...options });
|
|
879
|
+
}
|
|
880
|
+
function TracedLightweight(options) {
|
|
881
|
+
return Traced({ recordParams: false, recordResult: false, log: options?.log ?? false, maxLogSize: options?.maxLogSize });
|
|
882
|
+
}
|
|
883
|
+
function wrapFunction(fn, name, options) {
|
|
884
|
+
const shouldLog = options?.log ?? false;
|
|
885
|
+
const getMaxLogSize = () => {
|
|
886
|
+
if (options?.maxLogSize !== undefined) {
|
|
887
|
+
return options.maxLogSize;
|
|
888
|
+
}
|
|
889
|
+
const configMaxOutput = getMaxOutput();
|
|
890
|
+
return configMaxOutput !== undefined ? configMaxOutput : 500;
|
|
891
|
+
};
|
|
892
|
+
const truncate = (obj) => {
|
|
893
|
+
if (obj === undefined)
|
|
894
|
+
return;
|
|
895
|
+
if (obj === null)
|
|
896
|
+
return null;
|
|
897
|
+
const maxLogSize = getMaxLogSize();
|
|
898
|
+
let str;
|
|
899
|
+
try {
|
|
900
|
+
str = typeof obj === "string" ? obj : JSON.stringify(obj, null, 0).replace(/\n/g, "");
|
|
901
|
+
} catch (e) {
|
|
902
|
+
str = `[Object with circular reference: ${e instanceof Error ? e.message : String(e)}]`;
|
|
903
|
+
}
|
|
904
|
+
if (maxLogSize > 0 && str.length > maxLogSize) {
|
|
905
|
+
return str.slice(0, maxLogSize) + " [TRUNCATED]";
|
|
906
|
+
}
|
|
907
|
+
try {
|
|
908
|
+
return JSON.parse(str);
|
|
909
|
+
} catch {
|
|
910
|
+
return str;
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
const truncateString = (obj) => {
|
|
914
|
+
if (obj === undefined)
|
|
915
|
+
return "undefined";
|
|
916
|
+
if (obj === null)
|
|
917
|
+
return "null";
|
|
918
|
+
const maxLogSize = getMaxLogSize();
|
|
919
|
+
let str;
|
|
920
|
+
try {
|
|
921
|
+
str = typeof obj === "string" ? obj : JSON.stringify(obj, null, 0).replace(/\n/g, "");
|
|
922
|
+
} catch (e) {
|
|
923
|
+
str = `[Object with circular reference: ${e instanceof Error ? e.message : String(e)}]`;
|
|
924
|
+
}
|
|
925
|
+
return maxLogSize > 0 && str.length > maxLogSize ? str.slice(0, maxLogSize) + " [TRUNCATED]" : str;
|
|
926
|
+
};
|
|
927
|
+
const TRACE_LOG_PREFIX = "[TRACE]";
|
|
928
|
+
const getCallerLocation = () => {
|
|
929
|
+
const originalLimit = Error.stackTraceLimit;
|
|
930
|
+
Error.stackTraceLimit = 15;
|
|
931
|
+
const err = new Error;
|
|
932
|
+
Error.captureStackTrace(err, getCallerLocation);
|
|
933
|
+
const stack = err.stack?.split(`
|
|
934
|
+
`) || [];
|
|
935
|
+
Error.stackTraceLimit = originalLimit;
|
|
936
|
+
for (let i = 1;i < stack.length; i++) {
|
|
937
|
+
const line = stack[i];
|
|
938
|
+
if (line.includes("decorator.ts") || line.includes("decorator.js") || line.includes("logFn") || line.includes("getCallerLocation"))
|
|
939
|
+
continue;
|
|
940
|
+
const match = line.match(/at\s+.+\s+\((.+):(\d+):\d+\)/) || line.match(/at\s+(.+):(\d+):\d+/);
|
|
941
|
+
if (match) {
|
|
942
|
+
const filePath = match[1];
|
|
943
|
+
if (!filePath || filePath === "native")
|
|
944
|
+
continue;
|
|
945
|
+
const relativePath = simplifyFilePath(filePath);
|
|
946
|
+
return `${relativePath}:${match[2]}`;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return "";
|
|
950
|
+
};
|
|
951
|
+
const logFn = (event2, argsOrData, callerLocation) => {
|
|
952
|
+
if (!shouldLog)
|
|
953
|
+
return;
|
|
954
|
+
const logger = createLogger("traced:" + name);
|
|
955
|
+
const tag = event2 === "enter" ? ">>>" : event2 === "quit" ? "<<<" : "!!!";
|
|
956
|
+
const prefix = `${TRACE_LOG_PREFIX} ${tag} ${name}`;
|
|
957
|
+
const originalFnLocation = callerLocation || getCallerLocation();
|
|
958
|
+
const logMessage = (msg, data) => {
|
|
959
|
+
if (data !== undefined) {
|
|
960
|
+
logger.info(`${prefix} ${msg}: ${truncateString(data)}`, { callerLocation: originalFnLocation });
|
|
961
|
+
} else {
|
|
962
|
+
logger.info(`${prefix} ${msg}`, { callerLocation: originalFnLocation });
|
|
963
|
+
}
|
|
964
|
+
};
|
|
965
|
+
if (event2 === "enter") {
|
|
966
|
+
logMessage("enter", argsOrData);
|
|
967
|
+
} else if (event2 === "quit") {
|
|
968
|
+
logMessage("quit", options?.recordResult ? argsOrData : undefined);
|
|
969
|
+
} else {
|
|
970
|
+
logMessage("error", argsOrData);
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
return function(...args) {
|
|
974
|
+
const tracer = getTracerProvider().getTracer("roy-tracer");
|
|
975
|
+
const attributes = {};
|
|
976
|
+
if (options?.recordParams !== false) {
|
|
977
|
+
if (options?.paramFilter) {
|
|
978
|
+
attributes["params"] = truncate(options.paramFilter(args));
|
|
979
|
+
} else {
|
|
980
|
+
attributes["params"] = truncate(args);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const callerLocation = getCallerLocation();
|
|
984
|
+
logFn("enter", args, callerLocation);
|
|
985
|
+
const span = tracer.startSpan(name, { attributes });
|
|
986
|
+
try {
|
|
987
|
+
const result = fn.call(this, ...args);
|
|
988
|
+
if (result && typeof result === "object" && typeof result.then === "function") {
|
|
989
|
+
return result.then((resolved) => {
|
|
990
|
+
span.setAttribute("result", JSON.stringify(truncate(resolved)));
|
|
991
|
+
span.end(resolved);
|
|
992
|
+
logFn("quit", options?.recordResult ? resolved : undefined, callerLocation);
|
|
993
|
+
return resolved;
|
|
994
|
+
}, (rejected) => {
|
|
995
|
+
span.setAttribute("error", String(rejected));
|
|
996
|
+
span.end(undefined, rejected instanceof Error ? rejected : new Error(String(rejected)));
|
|
997
|
+
logFn("error", rejected.message, callerLocation);
|
|
998
|
+
throw rejected;
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
span.setAttribute("result", JSON.stringify(truncate(result)));
|
|
1002
|
+
span.end(result);
|
|
1003
|
+
logFn("quit", options?.recordResult ? result : undefined, callerLocation);
|
|
1004
|
+
return result;
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
span.setAttribute("error", String(error));
|
|
1007
|
+
span.end(undefined, error instanceof Error ? error : new Error(String(error)));
|
|
1008
|
+
logFn("error", error.message, callerLocation);
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
var init_decorator = __esm(() => {
|
|
1014
|
+
init_tracer_provider();
|
|
1015
|
+
init_logger();
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// src/env/workflow/engine/executor.ts
|
|
1019
|
+
var Executor;
|
|
1020
|
+
var init_executor = __esm(() => {
|
|
1021
|
+
init_event();
|
|
1022
|
+
init_types();
|
|
1023
|
+
init_decorator();
|
|
1024
|
+
Executor = class Executor {
|
|
1025
|
+
nodeRegistry;
|
|
1026
|
+
eventBus;
|
|
1027
|
+
options;
|
|
1028
|
+
sessionComponent;
|
|
1029
|
+
abortControllers = new Map;
|
|
1030
|
+
constructor(nodeRegistry, eventBus, options, sessionComponent) {
|
|
1031
|
+
this.nodeRegistry = nodeRegistry;
|
|
1032
|
+
this.eventBus = eventBus;
|
|
1033
|
+
this.options = options;
|
|
1034
|
+
this.sessionComponent = sessionComponent;
|
|
1035
|
+
}
|
|
1036
|
+
async executeNode(definition, context2) {
|
|
1037
|
+
const nodeId = definition.id;
|
|
1038
|
+
const nodeType = definition.type;
|
|
1039
|
+
const agentSessionId = context2.agentSessionId;
|
|
1040
|
+
await this.eventBus.publish(createWorkflowEvent("node.started", context2.runId, {
|
|
1041
|
+
node_id: nodeId,
|
|
1042
|
+
input: context2.input
|
|
1043
|
+
}));
|
|
1044
|
+
await this.writeNodeCall(context2.sessionId, nodeId, nodeType, context2.input, agentSessionId);
|
|
1045
|
+
const abortController = new AbortController;
|
|
1046
|
+
this.abortControllers.set(nodeId, abortController);
|
|
1047
|
+
const timeout = definition.timeout ?? this.options.globalTimeout ?? undefined;
|
|
1048
|
+
const retryConfig = definition.retry ?? this.options.globalRetry;
|
|
1049
|
+
try {
|
|
1050
|
+
let result;
|
|
1051
|
+
if (retryConfig && retryConfig.max_attempts > 1) {
|
|
1052
|
+
result = await this.executeWithRetry(definition, context2, abortController.signal, timeout);
|
|
1053
|
+
} else {
|
|
1054
|
+
result = await this.executeWithTimeout(definition, context2, abortController.signal, timeout);
|
|
1055
|
+
}
|
|
1056
|
+
if (result.error instanceof AskUserError) {
|
|
1057
|
+
const interruptEvent = createNodeInterruptEvent(context2.runId, nodeId, nodeType, result.error.query, result.error.agentSessionId || agentSessionId);
|
|
1058
|
+
await this.eventBus.publish(interruptEvent);
|
|
1059
|
+
await this.writeNodeInterrupt(context2.sessionId, nodeId, nodeType, result.error.query, result.error.agentSessionId || agentSessionId);
|
|
1060
|
+
throw result.error;
|
|
1061
|
+
}
|
|
1062
|
+
if (result.error) {
|
|
1063
|
+
const errorMessage = result.error instanceof Error ? result.error.message : String(result.error);
|
|
1064
|
+
const errorStack = result.error instanceof Error ? result.error.stack : undefined;
|
|
1065
|
+
await this.eventBus.publish(createWorkflowEvent("node.failed", context2.runId, {
|
|
1066
|
+
node_id: nodeId,
|
|
1067
|
+
error: {
|
|
1068
|
+
message: errorMessage,
|
|
1069
|
+
stack: errorStack
|
|
1070
|
+
}
|
|
1071
|
+
}));
|
|
1072
|
+
await this.writeNodeResult(context2.sessionId, nodeId, nodeType, result.output, errorMessage, result.durationMs ?? 0);
|
|
1073
|
+
} else {
|
|
1074
|
+
await this.eventBus.publish(createWorkflowEvent("node.completed", context2.runId, {
|
|
1075
|
+
node_id: nodeId,
|
|
1076
|
+
output: result.output,
|
|
1077
|
+
duration_ms: result.durationMs ?? 0
|
|
1078
|
+
}));
|
|
1079
|
+
await this.writeNodeResult(context2.sessionId, nodeId, nodeType, result.output, undefined, result.durationMs ?? 0);
|
|
1080
|
+
}
|
|
1081
|
+
return result;
|
|
1082
|
+
} finally {
|
|
1083
|
+
this.abortControllers.delete(nodeId);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
async executeWithTimeout(definition, context2, signal, timeout) {
|
|
1087
|
+
const startTime = Date.now();
|
|
1088
|
+
const nodeContext = {
|
|
1089
|
+
runId: context2.runId,
|
|
1090
|
+
workflowName: context2.workflowName,
|
|
1091
|
+
eventBus: this.eventBus,
|
|
1092
|
+
debug: context2.debug
|
|
1093
|
+
};
|
|
1094
|
+
const node = this.nodeRegistry.createNode(definition, nodeContext);
|
|
1095
|
+
if (timeout) {
|
|
1096
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1097
|
+
const handle = setTimeout(() => {
|
|
1098
|
+
reject(new Error(`Node execution timeout: ${timeout}ms`));
|
|
1099
|
+
}, timeout);
|
|
1100
|
+
signal.addEventListener("abort", () => clearTimeout(handle));
|
|
1101
|
+
});
|
|
1102
|
+
try {
|
|
1103
|
+
const result = await Promise.race([
|
|
1104
|
+
node.execute(context2),
|
|
1105
|
+
timeoutPromise
|
|
1106
|
+
]);
|
|
1107
|
+
return {
|
|
1108
|
+
output: result.output,
|
|
1109
|
+
error: result.error ?? undefined,
|
|
1110
|
+
durationMs: Date.now() - startTime
|
|
1111
|
+
};
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
if (error instanceof AskUserError) {
|
|
1114
|
+
throw error;
|
|
1115
|
+
}
|
|
1116
|
+
return {
|
|
1117
|
+
output: undefined,
|
|
1118
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1119
|
+
durationMs: Date.now() - startTime
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
try {
|
|
1124
|
+
const result = await node.execute(context2);
|
|
1125
|
+
return {
|
|
1126
|
+
output: result.output,
|
|
1127
|
+
durationMs: Date.now() - startTime
|
|
1128
|
+
};
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
if (error instanceof AskUserError) {
|
|
1131
|
+
throw error;
|
|
1132
|
+
}
|
|
1133
|
+
return {
|
|
1134
|
+
output: undefined,
|
|
1135
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1136
|
+
durationMs: Date.now() - startTime
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
async executeWithRetry(definition, context2, signal, timeout) {
|
|
1142
|
+
const retryConfig = definition.retry;
|
|
1143
|
+
let lastError;
|
|
1144
|
+
let delay = retryConfig.initial_delay;
|
|
1145
|
+
for (let attempt = 1;attempt <= retryConfig.max_attempts; attempt++) {
|
|
1146
|
+
if (signal.aborted) {
|
|
1147
|
+
return {
|
|
1148
|
+
output: undefined,
|
|
1149
|
+
error: new Error("Execution aborted"),
|
|
1150
|
+
durationMs: 0
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
const attemptAbort = new AbortController;
|
|
1154
|
+
const combinedSignal = this.combineAbortSignals(signal, attemptAbort.signal);
|
|
1155
|
+
try {
|
|
1156
|
+
const result = await this.executeWithTimeout(definition, context2, combinedSignal, timeout);
|
|
1157
|
+
if (!result.error) {
|
|
1158
|
+
return result;
|
|
1159
|
+
}
|
|
1160
|
+
lastError = result.error instanceof Error ? result.error : new Error(String(result.error));
|
|
1161
|
+
} catch (error) {
|
|
1162
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1163
|
+
}
|
|
1164
|
+
if (attempt < retryConfig.max_attempts) {
|
|
1165
|
+
await this.sleep(delay);
|
|
1166
|
+
if (retryConfig.backoff === "exponential") {
|
|
1167
|
+
delay *= 2;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return {
|
|
1172
|
+
output: undefined,
|
|
1173
|
+
error: lastError ?? new Error("Unknown error after retries"),
|
|
1174
|
+
durationMs: 0
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
cancelNode(nodeId) {
|
|
1178
|
+
const controller = this.abortControllers.get(nodeId);
|
|
1179
|
+
if (controller) {
|
|
1180
|
+
controller.abort();
|
|
1181
|
+
this.abortControllers.delete(nodeId);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
cancelAll() {
|
|
1185
|
+
for (const controller of this.abortControllers.values()) {
|
|
1186
|
+
controller.abort();
|
|
1187
|
+
}
|
|
1188
|
+
this.abortControllers.clear();
|
|
1189
|
+
}
|
|
1190
|
+
combineAbortSignals(signal1, signal2) {
|
|
1191
|
+
const controller = new AbortController;
|
|
1192
|
+
signal1.addEventListener("abort", () => controller.abort());
|
|
1193
|
+
signal2.addEventListener("abort", () => controller.abort());
|
|
1194
|
+
return controller.signal;
|
|
1195
|
+
}
|
|
1196
|
+
sleep(ms) {
|
|
1197
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1198
|
+
}
|
|
1199
|
+
async writeNodeCall(sessionId, nodeId, nodeType, input, agentSessionId) {
|
|
1200
|
+
if (!this.sessionComponent)
|
|
1201
|
+
return;
|
|
1202
|
+
const startTime = Date.now();
|
|
1203
|
+
const part = {
|
|
1204
|
+
type: "workflow-node-call",
|
|
1205
|
+
nodeId,
|
|
1206
|
+
nodeType,
|
|
1207
|
+
input,
|
|
1208
|
+
startTime,
|
|
1209
|
+
...agentSessionId ? { agentSessionId } : {}
|
|
1210
|
+
};
|
|
1211
|
+
const contentSummary = this.summarizeCall(nodeType, nodeId, input);
|
|
1212
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
1213
|
+
role: "workflow.node.call",
|
|
1214
|
+
content: contentSummary,
|
|
1215
|
+
parts: [part],
|
|
1216
|
+
metadata: {
|
|
1217
|
+
_workflowNodeMetadata: true,
|
|
1218
|
+
type: "workflow.node.call",
|
|
1219
|
+
workflowNodeId: nodeId,
|
|
1220
|
+
workflowNodeType: nodeType,
|
|
1221
|
+
...agentSessionId ? { agentSessionId } : {}
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
summarizeCall(nodeType, nodeId, input) {
|
|
1226
|
+
if (input === undefined || input === null) {
|
|
1227
|
+
return `[${nodeType}] ${nodeId} started`;
|
|
1228
|
+
}
|
|
1229
|
+
if (typeof input === "object") {
|
|
1230
|
+
const keys = Object.keys(input);
|
|
1231
|
+
if (keys.length === 0) {
|
|
1232
|
+
return `[${nodeType}] ${nodeId} started`;
|
|
1233
|
+
}
|
|
1234
|
+
const summary = keys.slice(0, 3).map((k) => `${k}: ${JSON.stringify(input[k])}`).join(", ");
|
|
1235
|
+
return `[${nodeType}] ${nodeId}: ${summary}`;
|
|
1236
|
+
}
|
|
1237
|
+
return `[${nodeType}] ${nodeId}: ${String(input)}`;
|
|
1238
|
+
}
|
|
1239
|
+
async writeNodeInterrupt(sessionId, nodeId, nodeType, query, agentSessionId) {
|
|
1240
|
+
if (!this.sessionComponent)
|
|
1241
|
+
return;
|
|
1242
|
+
const timestamp = Date.now();
|
|
1243
|
+
const part = {
|
|
1244
|
+
type: "workflow-node-interrupt",
|
|
1245
|
+
nodeId,
|
|
1246
|
+
nodeType,
|
|
1247
|
+
query,
|
|
1248
|
+
timestamp,
|
|
1249
|
+
...agentSessionId ? { agentSessionId } : {}
|
|
1250
|
+
};
|
|
1251
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
1252
|
+
role: "workflow.node.interrupt",
|
|
1253
|
+
content: query,
|
|
1254
|
+
parts: [part],
|
|
1255
|
+
metadata: {
|
|
1256
|
+
_workflowNodeMetadata: true,
|
|
1257
|
+
type: "workflow.node.interrupt",
|
|
1258
|
+
workflowNodeId: nodeId,
|
|
1259
|
+
workflowNodeType: nodeType,
|
|
1260
|
+
query,
|
|
1261
|
+
agentSessionId
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
async writeNodeResult(sessionId, nodeId, nodeType, output, error, durationMs) {
|
|
1266
|
+
if (!this.sessionComponent)
|
|
1267
|
+
return;
|
|
1268
|
+
const part = {
|
|
1269
|
+
type: "workflow-node-result",
|
|
1270
|
+
nodeId,
|
|
1271
|
+
nodeType,
|
|
1272
|
+
output,
|
|
1273
|
+
error,
|
|
1274
|
+
durationMs
|
|
1275
|
+
};
|
|
1276
|
+
const contentSummary = this.summarizeResult(nodeId, output, error, durationMs);
|
|
1277
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
1278
|
+
role: "workflow.node.result",
|
|
1279
|
+
content: contentSummary,
|
|
1280
|
+
parts: [part],
|
|
1281
|
+
metadata: {
|
|
1282
|
+
_workflowNodeMetadata: true,
|
|
1283
|
+
type: "workflow.node.result",
|
|
1284
|
+
workflowNodeId: nodeId,
|
|
1285
|
+
workflowNodeType: nodeType,
|
|
1286
|
+
success: !error
|
|
1287
|
+
}
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
summarizeResult(nodeId, output, error, durationMs) {
|
|
1291
|
+
if (error) {
|
|
1292
|
+
return `❌ ${nodeId} failed: ${error}`;
|
|
1293
|
+
}
|
|
1294
|
+
if (output === undefined || output === null) {
|
|
1295
|
+
return `✅ ${nodeId} completed (${durationMs}ms)`;
|
|
1296
|
+
}
|
|
1297
|
+
if (typeof output === "object") {
|
|
1298
|
+
const keys = Object.keys(output);
|
|
1299
|
+
if (keys.length === 0) {
|
|
1300
|
+
return `✅ ${nodeId} completed (${durationMs}ms)`;
|
|
1301
|
+
}
|
|
1302
|
+
const summary = keys.slice(0, 3).join(", ");
|
|
1303
|
+
return `✅ ${nodeId}: ${summary} (${durationMs}ms)`;
|
|
1304
|
+
}
|
|
1305
|
+
const strOutput = String(output);
|
|
1306
|
+
const truncated = strOutput.length > 100 ? strOutput.substring(0, 100) + "..." : strOutput;
|
|
1307
|
+
return `✅ ${nodeId}: ${truncated} (${durationMs}ms)`;
|
|
1308
|
+
}
|
|
1309
|
+
async writeNodeResume(sessionId, response) {
|
|
1310
|
+
if (!this.sessionComponent)
|
|
1311
|
+
return;
|
|
1312
|
+
const timestamp = Date.now();
|
|
1313
|
+
const part = {
|
|
1314
|
+
type: "workflow-node-resume",
|
|
1315
|
+
response,
|
|
1316
|
+
timestamp
|
|
1317
|
+
};
|
|
1318
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
1319
|
+
role: "workflow.node.resume",
|
|
1320
|
+
content: response,
|
|
1321
|
+
parts: [part],
|
|
1322
|
+
metadata: {
|
|
1323
|
+
_workflowNodeMetadata: true
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
__legacyDecorateClassTS([
|
|
1329
|
+
TracedAs("workflow.executor.executeNode", { recordParams: true, recordResult: true, log: true })
|
|
1330
|
+
], Executor.prototype, "executeNode", null);
|
|
1331
|
+
__legacyDecorateClassTS([
|
|
1332
|
+
TracedAs("workflow.executor.writeNodeCall", { recordParams: true, recordResult: true, log: true })
|
|
1333
|
+
], Executor.prototype, "writeNodeCall", null);
|
|
1334
|
+
__legacyDecorateClassTS([
|
|
1335
|
+
TracedAs("workflow.executor.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
1336
|
+
], Executor.prototype, "writeNodeInterrupt", null);
|
|
1337
|
+
__legacyDecorateClassTS([
|
|
1338
|
+
TracedAs("workflow.executor.writeNodeResult", { recordParams: true, recordResult: true, log: true })
|
|
1339
|
+
], Executor.prototype, "writeNodeResult", null);
|
|
1340
|
+
__legacyDecorateClassTS([
|
|
1341
|
+
TracedAs("workflow.executor.writeNodeResume", { recordParams: true, recordResult: true, log: true })
|
|
1342
|
+
], Executor.prototype, "writeNodeResume", null);
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
// src/env/workflow/nodes/tool-node.ts
|
|
1346
|
+
class ToolNode {
|
|
1347
|
+
definition;
|
|
1348
|
+
toolRegistry;
|
|
1349
|
+
type = "tool";
|
|
1350
|
+
id;
|
|
1351
|
+
constructor(definition, toolRegistry) {
|
|
1352
|
+
this.definition = definition;
|
|
1353
|
+
this.toolRegistry = toolRegistry;
|
|
1354
|
+
this.id = definition.id;
|
|
1355
|
+
}
|
|
1356
|
+
async execute(context2) {
|
|
1357
|
+
const startTime = Date.now();
|
|
1358
|
+
try {
|
|
1359
|
+
const toolName = this.definition.config?.tool ?? this.definition.config?.toolName;
|
|
1360
|
+
if (!toolName) {
|
|
1361
|
+
throw new Error("Tool name is required. Please specify config.tool or config.toolName in the node definition.");
|
|
1362
|
+
}
|
|
1363
|
+
let tool;
|
|
1364
|
+
if (this.toolRegistry.getTool) {
|
|
1365
|
+
const result = this.toolRegistry.getTool(toolName);
|
|
1366
|
+
if (!result) {
|
|
1367
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
1368
|
+
}
|
|
1369
|
+
if ("tool" in result) {
|
|
1370
|
+
tool = result.tool;
|
|
1371
|
+
} else {
|
|
1372
|
+
tool = result;
|
|
1373
|
+
}
|
|
1374
|
+
} else if (this.toolRegistry.getToolByName) {
|
|
1375
|
+
tool = this.toolRegistry.getToolByName(toolName);
|
|
1376
|
+
}
|
|
1377
|
+
if (!tool) {
|
|
1378
|
+
throw new Error(`Tool not found: ${toolName}`);
|
|
1379
|
+
}
|
|
1380
|
+
let input;
|
|
1381
|
+
if (this.definition.config?.command !== undefined) {
|
|
1382
|
+
const commandTemplate = this.definition.config.command;
|
|
1383
|
+
const resolvedCommand = this.resolveTemplateReferences(commandTemplate, context2.previousOutputs, context2.input);
|
|
1384
|
+
input = { command: resolvedCommand };
|
|
1385
|
+
console.log(`[ToolNode] command input: ${resolvedCommand}`);
|
|
1386
|
+
} else if (this.definition.config?.message !== undefined && Object.keys(this.definition.config).length === 1) {
|
|
1387
|
+
const messageTemplate = this.definition.config.message;
|
|
1388
|
+
const resolvedMessage = this.resolveTemplateReferences(messageTemplate, context2.previousOutputs, context2.input);
|
|
1389
|
+
input = { message: resolvedMessage };
|
|
1390
|
+
console.log(`[ToolNode] message input: ${resolvedMessage}`);
|
|
1391
|
+
} else {
|
|
1392
|
+
input = this.definition.config?.input ?? this.definition.config?.args ?? {};
|
|
1393
|
+
input = this.resolveTemplateReferences(input, context2.previousOutputs, context2.input);
|
|
1394
|
+
}
|
|
1395
|
+
let output;
|
|
1396
|
+
try {
|
|
1397
|
+
const toolContext = {
|
|
1398
|
+
session_id: context2.sessionId || `workflow_${context2.runId}`,
|
|
1399
|
+
message_id: context2.nodeId,
|
|
1400
|
+
metadata: {
|
|
1401
|
+
workflowRunId: context2.runId,
|
|
1402
|
+
workflowName: context2.workflowName,
|
|
1403
|
+
nodeId: context2.nodeId
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
const executePromise = tool.execute(input, toolContext);
|
|
1407
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1408
|
+
setTimeout(() => reject(new Error(`Tool ${toolName} execution timeout after 30s`)), 30000);
|
|
1409
|
+
});
|
|
1410
|
+
output = await Promise.race([executePromise, timeoutPromise]);
|
|
1411
|
+
} catch (err) {
|
|
1412
|
+
console.log(`[ToolNode] Tool ${toolName} doesn't support context, retrying without context...`);
|
|
1413
|
+
output = await tool.execute(input);
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
output,
|
|
1417
|
+
error: undefined,
|
|
1418
|
+
durationMs: Date.now() - startTime
|
|
1419
|
+
};
|
|
1420
|
+
} catch (error) {
|
|
1421
|
+
return {
|
|
1422
|
+
output: undefined,
|
|
1423
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1424
|
+
durationMs: Date.now() - startTime
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
resolveTemplateReferences(input, previousOutputs, workflowInput) {
|
|
1429
|
+
if (typeof input === "string") {
|
|
1430
|
+
const pureTemplate = this.extractPureTemplate(input) || this.extractDollarTemplate(input);
|
|
1431
|
+
if (pureTemplate) {
|
|
1432
|
+
return this.resolvePureTemplate(pureTemplate, previousOutputs, workflowInput);
|
|
1433
|
+
}
|
|
1434
|
+
return this.resolveStringTemplate(input, previousOutputs, workflowInput);
|
|
1435
|
+
}
|
|
1436
|
+
if (Array.isArray(input)) {
|
|
1437
|
+
return input.map((item) => this.resolveTemplateReferences(item, previousOutputs, workflowInput));
|
|
1438
|
+
}
|
|
1439
|
+
if (input !== null && typeof input === "object") {
|
|
1440
|
+
const resolved = {};
|
|
1441
|
+
for (const [key, value] of Object.entries(input)) {
|
|
1442
|
+
resolved[key] = this.resolveTemplateReferences(value, previousOutputs, workflowInput);
|
|
1443
|
+
}
|
|
1444
|
+
return resolved;
|
|
1445
|
+
}
|
|
1446
|
+
return input;
|
|
1447
|
+
}
|
|
1448
|
+
extractPureTemplate(str) {
|
|
1449
|
+
const trimmed = str.trim();
|
|
1450
|
+
if (trimmed.startsWith("{{") && trimmed.endsWith("}}") && trimmed.length > 4) {
|
|
1451
|
+
const content = trimmed.slice(2, -2).trim();
|
|
1452
|
+
if (!content.includes("{{") && !content.includes("}}")) {
|
|
1453
|
+
return content;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
return null;
|
|
1457
|
+
}
|
|
1458
|
+
extractDollarTemplate(str) {
|
|
1459
|
+
const trimmed = str.trim();
|
|
1460
|
+
if (trimmed.startsWith("${") && trimmed.endsWith("}") && trimmed.length > 3) {
|
|
1461
|
+
const content = trimmed.slice(2, -1).trim();
|
|
1462
|
+
if (!content.includes("${") && !content.includes("}")) {
|
|
1463
|
+
return content;
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
resolvePureTemplate(templateContent, previousOutputs, workflowInput) {
|
|
1469
|
+
const trimmed = templateContent.trim();
|
|
1470
|
+
const originalTemplate = `{{${templateContent}}}`;
|
|
1471
|
+
if (trimmed.startsWith("input.")) {
|
|
1472
|
+
const value = this.getNestedValue(workflowInput, trimmed.slice(6));
|
|
1473
|
+
return value !== undefined ? value : originalTemplate;
|
|
1474
|
+
}
|
|
1475
|
+
if (trimmed.startsWith("nodes.")) {
|
|
1476
|
+
const path = trimmed.slice(6);
|
|
1477
|
+
const segments = path.split(".");
|
|
1478
|
+
const nodeId = segments[0];
|
|
1479
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1480
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1481
|
+
return value !== undefined ? value : originalTemplate;
|
|
1482
|
+
}
|
|
1483
|
+
if (trimmed !== "input" && trimmed !== "nodes") {
|
|
1484
|
+
const segments = trimmed.split(".");
|
|
1485
|
+
const nodeId = segments[0];
|
|
1486
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1487
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1488
|
+
return value !== undefined ? value : originalTemplate;
|
|
1489
|
+
}
|
|
1490
|
+
return originalTemplate;
|
|
1491
|
+
}
|
|
1492
|
+
resolveStringTemplate(template, previousOutputs, workflowInput) {
|
|
1493
|
+
let resolved = template;
|
|
1494
|
+
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
1495
|
+
const value = this.getNestedValue(workflowInput, path.trim());
|
|
1496
|
+
return this.stringifyValue(value, match);
|
|
1497
|
+
});
|
|
1498
|
+
resolved = resolved.replace(/\$\{input\.([^}]+)\}/g, (match, path) => {
|
|
1499
|
+
const value = this.getNestedValue(workflowInput, path.trim());
|
|
1500
|
+
return this.stringifyValue(value, match);
|
|
1501
|
+
});
|
|
1502
|
+
resolved = resolved.replace(/\{\{([^:.{}][^}]*?)\}\}/g, (match, path) => {
|
|
1503
|
+
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
1504
|
+
return match;
|
|
1505
|
+
}
|
|
1506
|
+
const segments = path.trim().split(".");
|
|
1507
|
+
const nodeId = segments[0];
|
|
1508
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1509
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1510
|
+
return this.stringifyValue(value, match);
|
|
1511
|
+
});
|
|
1512
|
+
resolved = resolved.replace(/\$\{([^}]+)\}/g, (match, path) => {
|
|
1513
|
+
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
1514
|
+
return match;
|
|
1515
|
+
}
|
|
1516
|
+
const segments = path.trim().split(".");
|
|
1517
|
+
const nodeId = segments[0];
|
|
1518
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1519
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1520
|
+
return this.stringifyValue(value, match);
|
|
1521
|
+
});
|
|
1522
|
+
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
1523
|
+
const segments = path.trim().split(".");
|
|
1524
|
+
const nodeId = segments[0];
|
|
1525
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1526
|
+
const nodeOutput = this.resolvePath(nodeId, undefined, previousOutputs);
|
|
1527
|
+
let extractedValue = this.extractFromWrapper(nodeOutput);
|
|
1528
|
+
if (typeof extractedValue === "string" && restPath === "output") {
|
|
1529
|
+
return this.stringifyValue(extractedValue, match);
|
|
1530
|
+
}
|
|
1531
|
+
if (restPath) {
|
|
1532
|
+
const value = this.getNestedValue(extractedValue, restPath);
|
|
1533
|
+
return this.stringifyValue(value, match);
|
|
1534
|
+
} else {
|
|
1535
|
+
return this.stringifyValue(extractedValue, match);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
return resolved;
|
|
1539
|
+
}
|
|
1540
|
+
resolvePath(nodeId, path, previousOutputs) {
|
|
1541
|
+
let nodeOutput = previousOutputs.get(nodeId);
|
|
1542
|
+
if (nodeOutput === undefined) {
|
|
1543
|
+
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1544
|
+
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1545
|
+
if (normalizedUnderscore !== nodeId) {
|
|
1546
|
+
nodeOutput = previousOutputs.get(normalizedUnderscore);
|
|
1547
|
+
}
|
|
1548
|
+
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1549
|
+
nodeOutput = previousOutputs.get(normalizedHyphen);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
if (nodeOutput === undefined) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
if (path === undefined || path === "") {
|
|
1556
|
+
return nodeOutput;
|
|
1557
|
+
}
|
|
1558
|
+
return this.getNestedValue(nodeOutput, path);
|
|
1559
|
+
}
|
|
1560
|
+
getNestedValue(obj, path) {
|
|
1561
|
+
if (obj === null || obj === undefined) {
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
const segments = path.split(".");
|
|
1565
|
+
let current = obj;
|
|
1566
|
+
for (const segment of segments) {
|
|
1567
|
+
if (current === null || current === undefined) {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
current = current[segment];
|
|
1571
|
+
}
|
|
1572
|
+
return current;
|
|
1573
|
+
}
|
|
1574
|
+
extractFromWrapper(value) {
|
|
1575
|
+
if (value === null || value === undefined) {
|
|
1576
|
+
return value;
|
|
1577
|
+
}
|
|
1578
|
+
if (typeof value !== "object") {
|
|
1579
|
+
return value;
|
|
1580
|
+
}
|
|
1581
|
+
let result;
|
|
1582
|
+
if ("output" in value) {
|
|
1583
|
+
result = value.output;
|
|
1584
|
+
} else if ("result" in value && !("output" in value)) {
|
|
1585
|
+
result = value.result;
|
|
1586
|
+
} else {
|
|
1587
|
+
return value;
|
|
1588
|
+
}
|
|
1589
|
+
if (typeof result === "string") {
|
|
1590
|
+
return result.trimEnd();
|
|
1591
|
+
}
|
|
1592
|
+
return result;
|
|
1593
|
+
}
|
|
1594
|
+
stringifyValue(value, fallback) {
|
|
1595
|
+
if (value === undefined || value === null) {
|
|
1596
|
+
return fallback;
|
|
1597
|
+
}
|
|
1598
|
+
let str;
|
|
1599
|
+
if (typeof value === "object") {
|
|
1600
|
+
str = JSON.stringify(value);
|
|
1601
|
+
} else {
|
|
1602
|
+
str = String(value);
|
|
1603
|
+
}
|
|
1604
|
+
return str.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/"/g, "\\\"").replace(/`/g, "\\`").replace(/\$/g, "\\$");
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
var init_tool_node = () => {};
|
|
1608
|
+
|
|
1609
|
+
// src/env/workflow/nodes/skill-node.ts
|
|
1610
|
+
class SkillNode {
|
|
1611
|
+
definition;
|
|
1612
|
+
skillRegistry;
|
|
1613
|
+
type = "skill";
|
|
1614
|
+
id;
|
|
1615
|
+
constructor(definition, skillRegistry) {
|
|
1616
|
+
this.definition = definition;
|
|
1617
|
+
this.skillRegistry = skillRegistry;
|
|
1618
|
+
this.id = definition.id;
|
|
1619
|
+
}
|
|
1620
|
+
async execute(context2) {
|
|
1621
|
+
const startTime = Date.now();
|
|
1622
|
+
try {
|
|
1623
|
+
const skillName = this.definition.config?.skill;
|
|
1624
|
+
if (!skillName) {
|
|
1625
|
+
throw new Error("Skill name is required. Please specify config.skill in the node definition.");
|
|
1626
|
+
}
|
|
1627
|
+
const skill = this.skillRegistry.getSkill(skillName);
|
|
1628
|
+
if (!skill) {
|
|
1629
|
+
throw new Error(`Skill not found: ${skillName}`);
|
|
1630
|
+
}
|
|
1631
|
+
const input = this.definition.config?.input ?? {};
|
|
1632
|
+
const resolvedInput = this.resolveTemplateReferences(input, context2.previousOutputs, context2.input);
|
|
1633
|
+
const skillContext = {
|
|
1634
|
+
runId: context2.runId,
|
|
1635
|
+
workflowName: context2.workflowName,
|
|
1636
|
+
nodeId: context2.nodeId,
|
|
1637
|
+
debug: context2.debug
|
|
1638
|
+
};
|
|
1639
|
+
const output = await skill.invoke(resolvedInput, skillContext);
|
|
1640
|
+
return {
|
|
1641
|
+
output,
|
|
1642
|
+
error: undefined,
|
|
1643
|
+
durationMs: Date.now() - startTime
|
|
1644
|
+
};
|
|
1645
|
+
} catch (error) {
|
|
1646
|
+
return {
|
|
1647
|
+
output: undefined,
|
|
1648
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
1649
|
+
durationMs: Date.now() - startTime
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
resolveTemplateReferences(input, previousOutputs, workflowInput) {
|
|
1654
|
+
if (typeof input === "string") {
|
|
1655
|
+
const pureTemplate = this.extractPureTemplate(input);
|
|
1656
|
+
if (pureTemplate) {
|
|
1657
|
+
return this.resolvePureTemplate(pureTemplate, previousOutputs, workflowInput);
|
|
1658
|
+
}
|
|
1659
|
+
return this.resolveStringTemplate(input, previousOutputs, workflowInput);
|
|
1660
|
+
}
|
|
1661
|
+
if (Array.isArray(input)) {
|
|
1662
|
+
return input.map((item) => this.resolveTemplateReferences(item, previousOutputs, workflowInput));
|
|
1663
|
+
}
|
|
1664
|
+
if (input !== null && typeof input === "object") {
|
|
1665
|
+
const resolved = {};
|
|
1666
|
+
for (const [key, value] of Object.entries(input)) {
|
|
1667
|
+
resolved[key] = this.resolveTemplateReferences(value, previousOutputs, workflowInput);
|
|
1668
|
+
}
|
|
1669
|
+
return resolved;
|
|
1670
|
+
}
|
|
1671
|
+
return input;
|
|
1672
|
+
}
|
|
1673
|
+
extractPureTemplate(str) {
|
|
1674
|
+
const trimmed = str.trim();
|
|
1675
|
+
if (trimmed.startsWith("{{") && trimmed.endsWith("}}") && trimmed.length > 4) {
|
|
1676
|
+
const content = trimmed.slice(2, -2).trim();
|
|
1677
|
+
if (!content.includes("{{") && !content.includes("}}")) {
|
|
1678
|
+
return content;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return null;
|
|
1682
|
+
}
|
|
1683
|
+
resolvePureTemplate(templateContent, previousOutputs, workflowInput) {
|
|
1684
|
+
const trimmed = templateContent.trim();
|
|
1685
|
+
const originalTemplate = `{{${templateContent}}}`;
|
|
1686
|
+
if (trimmed.startsWith("input.")) {
|
|
1687
|
+
const value = this.getNestedValue(workflowInput, trimmed.slice(6));
|
|
1688
|
+
return value !== undefined ? value : originalTemplate;
|
|
1689
|
+
}
|
|
1690
|
+
if (trimmed.startsWith("nodes.")) {
|
|
1691
|
+
const path = trimmed.slice(6);
|
|
1692
|
+
const segments = path.split(".");
|
|
1693
|
+
const nodeId = segments[0];
|
|
1694
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1695
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1696
|
+
return value !== undefined ? value : originalTemplate;
|
|
1697
|
+
}
|
|
1698
|
+
if (trimmed !== "input" && trimmed !== "nodes") {
|
|
1699
|
+
const segments = trimmed.split(".");
|
|
1700
|
+
const nodeId = segments[0];
|
|
1701
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1702
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1703
|
+
return value !== undefined ? value : originalTemplate;
|
|
1704
|
+
}
|
|
1705
|
+
return originalTemplate;
|
|
1706
|
+
}
|
|
1707
|
+
resolveStringTemplate(template, previousOutputs, workflowInput) {
|
|
1708
|
+
let resolved = template;
|
|
1709
|
+
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
1710
|
+
const value = this.getNestedValue(workflowInput, path.trim());
|
|
1711
|
+
return this.stringifyValue(value, match);
|
|
1712
|
+
});
|
|
1713
|
+
resolved = resolved.replace(/\{\{([^:.{}][^}]*?)\}\}/g, (match, path) => {
|
|
1714
|
+
if (path.trim().startsWith("nodes.") || path.trim().startsWith("input.")) {
|
|
1715
|
+
return match;
|
|
1716
|
+
}
|
|
1717
|
+
const segments = path.trim().split(".");
|
|
1718
|
+
const nodeId = segments[0];
|
|
1719
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1720
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1721
|
+
return this.stringifyValue(value, match);
|
|
1722
|
+
});
|
|
1723
|
+
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
1724
|
+
const segments = path.trim().split(".");
|
|
1725
|
+
const nodeId = segments[0];
|
|
1726
|
+
const restPath = segments.slice(1).join(".") || undefined;
|
|
1727
|
+
const value = this.resolvePath(nodeId, restPath, previousOutputs);
|
|
1728
|
+
return this.stringifyValue(value, match);
|
|
1729
|
+
});
|
|
1730
|
+
return resolved;
|
|
1731
|
+
}
|
|
1732
|
+
resolvePath(nodeId, path, previousOutputs) {
|
|
1733
|
+
let nodeOutput = previousOutputs.get(nodeId);
|
|
1734
|
+
if (nodeOutput === undefined) {
|
|
1735
|
+
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1736
|
+
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1737
|
+
if (normalizedUnderscore !== nodeId) {
|
|
1738
|
+
nodeOutput = previousOutputs.get(normalizedUnderscore);
|
|
1739
|
+
}
|
|
1740
|
+
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1741
|
+
nodeOutput = previousOutputs.get(normalizedHyphen);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
if (nodeOutput === undefined) {
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
let value = this.extractFromWrapper(nodeOutput);
|
|
1748
|
+
if (!path) {
|
|
1749
|
+
return value;
|
|
1750
|
+
}
|
|
1751
|
+
let segments = path.split(".");
|
|
1752
|
+
if (segments.length > 1 && (segments[0] === "output" || segments[0] === "result" || segments[0] === "metadata")) {
|
|
1753
|
+
segments = segments.slice(1);
|
|
1754
|
+
}
|
|
1755
|
+
let current = value;
|
|
1756
|
+
for (const segment of segments) {
|
|
1757
|
+
if (current === null || current === undefined) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
current = current[segment];
|
|
1761
|
+
}
|
|
1762
|
+
return current;
|
|
1763
|
+
}
|
|
1764
|
+
extractFromWrapper(value) {
|
|
1765
|
+
if (value === null || value === undefined) {
|
|
1766
|
+
return value;
|
|
1767
|
+
}
|
|
1768
|
+
if (typeof value !== "object") {
|
|
1769
|
+
return value;
|
|
1770
|
+
}
|
|
1771
|
+
if ("result" in value && "metadata" in value) {
|
|
1772
|
+
return value.result;
|
|
1773
|
+
}
|
|
1774
|
+
if ("output" in value) {
|
|
1775
|
+
return value.output;
|
|
1776
|
+
}
|
|
1777
|
+
return value;
|
|
1778
|
+
}
|
|
1779
|
+
getNestedValue(obj, path) {
|
|
1780
|
+
if (!obj) {
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
if ("input" in obj && path in obj["input"]) {
|
|
1784
|
+
return obj["input"][path];
|
|
1785
|
+
}
|
|
1786
|
+
return path.split(".").reduce((current, key) => {
|
|
1787
|
+
if (current && typeof current === "object") {
|
|
1788
|
+
return current[key];
|
|
1789
|
+
}
|
|
1790
|
+
return;
|
|
1791
|
+
}, obj);
|
|
1792
|
+
}
|
|
1793
|
+
stringifyValue(value, originalTemplate) {
|
|
1794
|
+
if (value === undefined) {
|
|
1795
|
+
return originalTemplate;
|
|
1796
|
+
}
|
|
1797
|
+
if (value === null) {
|
|
1798
|
+
return "null";
|
|
1799
|
+
}
|
|
1800
|
+
if (typeof value === "string") {
|
|
1801
|
+
return value;
|
|
1802
|
+
}
|
|
1803
|
+
return JSON.stringify(value);
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
var init_skill_node = () => {};
|
|
1807
|
+
|
|
1808
|
+
// src/env/workflow/nodes/agent-node.ts
|
|
1809
|
+
var AgentNode;
|
|
1810
|
+
var init_agent_node = __esm(() => {
|
|
1811
|
+
init_workflow_hil();
|
|
1812
|
+
init_decorator();
|
|
1813
|
+
AgentNode = class AgentNode {
|
|
1814
|
+
definition;
|
|
1815
|
+
agentRunner;
|
|
1816
|
+
type = "agent";
|
|
1817
|
+
id;
|
|
1818
|
+
constructor(definition, agentRunner) {
|
|
1819
|
+
this.definition = definition;
|
|
1820
|
+
this.agentRunner = agentRunner;
|
|
1821
|
+
this.id = definition.id;
|
|
1822
|
+
}
|
|
1823
|
+
async execute(context2) {
|
|
1824
|
+
const startTime = Date.now();
|
|
1825
|
+
try {
|
|
1826
|
+
const config = this.definition.config || {};
|
|
1827
|
+
const agentType = config.agent_type || "general";
|
|
1828
|
+
const promptTemplate = config.prompt || "";
|
|
1829
|
+
const options = config.options || {};
|
|
1830
|
+
const resolvedPrompt = this.resolveTemplate(promptTemplate, context2);
|
|
1831
|
+
if (this.agentRunner.registerAgent && this.agentRunner.hasAgent) {
|
|
1832
|
+
if (!this.agentRunner.hasAgent(agentType)) {
|
|
1833
|
+
this.agentRunner.registerAgent(agentType, {
|
|
1834
|
+
type: agentType,
|
|
1835
|
+
systemPrompt: config.system_prompt || `You are a ${agentType} agent.`,
|
|
1836
|
+
model: options.model
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
const userResponse = context2.userResponse;
|
|
1841
|
+
let agentSessionId = context2.agentSessionId;
|
|
1842
|
+
if (!userResponse && context2.sessionComponent && !agentSessionId) {
|
|
1843
|
+
agentSessionId = await this.createAgentSubSession(context2);
|
|
1844
|
+
context2.agentSessionId = agentSessionId;
|
|
1845
|
+
}
|
|
1846
|
+
const agentConfig = {
|
|
1847
|
+
type: agentType,
|
|
1848
|
+
prompt: resolvedPrompt,
|
|
1849
|
+
options: {
|
|
1850
|
+
timeout: options.timeout,
|
|
1851
|
+
model: options.model,
|
|
1852
|
+
allowedTools: ["ask_user"]
|
|
1853
|
+
},
|
|
1854
|
+
workflowHistory: context2.workflowHistory,
|
|
1855
|
+
nodeId: this.definition.id,
|
|
1856
|
+
agentSessionId
|
|
1857
|
+
};
|
|
1858
|
+
const resumeOptions = userResponse ? { userResponse, agentSessionId } : undefined;
|
|
1859
|
+
const result = await this.agentRunner.run(agentConfig, resumeOptions);
|
|
1860
|
+
const duration = Date.now() - startTime;
|
|
1861
|
+
return {
|
|
1862
|
+
output: {
|
|
1863
|
+
result: result.output,
|
|
1864
|
+
metadata: result.metadata,
|
|
1865
|
+
workflowHistory: result.messages
|
|
1866
|
+
},
|
|
1867
|
+
error: undefined,
|
|
1868
|
+
duration
|
|
1869
|
+
};
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
if (error instanceof AskUserError) {
|
|
1872
|
+
const contextAgentSessionId = context2.agentSessionId;
|
|
1873
|
+
if (contextAgentSessionId && !error.agentSessionId) {
|
|
1874
|
+
throw new AskUserError(error.runId, error.sessionId, error.nodeId, error.nodeType, error.query, contextAgentSessionId, error.timestamp);
|
|
1875
|
+
}
|
|
1876
|
+
throw error;
|
|
1877
|
+
}
|
|
1878
|
+
const duration = Date.now() - startTime;
|
|
1879
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1880
|
+
return {
|
|
1881
|
+
output: undefined,
|
|
1882
|
+
error: errorMessage,
|
|
1883
|
+
duration
|
|
1884
|
+
};
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
async createAgentSubSession(context2) {
|
|
1888
|
+
const sessionComponent = context2.sessionComponent;
|
|
1889
|
+
if (!sessionComponent) {
|
|
1890
|
+
return "";
|
|
1891
|
+
}
|
|
1892
|
+
const agentSessionId = `agent_${this.definition.id}_${Date.now()}`;
|
|
1893
|
+
await sessionComponent.create({
|
|
1894
|
+
id: agentSessionId,
|
|
1895
|
+
title: `Agent: ${this.definition.id}`,
|
|
1896
|
+
metadata: {
|
|
1897
|
+
type: "agent",
|
|
1898
|
+
parentSessionId: context2.sessionId,
|
|
1899
|
+
nodeId: this.definition.id,
|
|
1900
|
+
workflowName: context2.workflowName
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
const workflowSession = await sessionComponent.get(context2.sessionId);
|
|
1904
|
+
if (workflowSession) {
|
|
1905
|
+
const metadata = workflowSession.metadata || {};
|
|
1906
|
+
const agentSessions = metadata.agentSessions || [];
|
|
1907
|
+
const existingIndex = agentSessions.findIndex((s) => s.nodeId === this.definition.id);
|
|
1908
|
+
if (existingIndex >= 0) {
|
|
1909
|
+
agentSessions[existingIndex] = {
|
|
1910
|
+
nodeId: this.definition.id,
|
|
1911
|
+
sessionId: agentSessionId,
|
|
1912
|
+
status: "active",
|
|
1913
|
+
createdAt: Date.now()
|
|
1914
|
+
};
|
|
1915
|
+
} else {
|
|
1916
|
+
agentSessions.push({
|
|
1917
|
+
nodeId: this.definition.id,
|
|
1918
|
+
sessionId: agentSessionId,
|
|
1919
|
+
status: "active",
|
|
1920
|
+
createdAt: Date.now()
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
await sessionComponent.update(context2.sessionId, {
|
|
1924
|
+
metadata: {
|
|
1925
|
+
...metadata,
|
|
1926
|
+
agentSessions
|
|
1927
|
+
}
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
return agentSessionId;
|
|
1931
|
+
}
|
|
1932
|
+
resolveTemplate(template, context2) {
|
|
1933
|
+
if (!template) {
|
|
1934
|
+
return "";
|
|
1935
|
+
}
|
|
1936
|
+
let resolved = template;
|
|
1937
|
+
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
1938
|
+
const value = this.getNestedValue(context2.input, path);
|
|
1939
|
+
return this.stringifyValue(value, match);
|
|
1940
|
+
});
|
|
1941
|
+
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
1942
|
+
const segments = path.split(".");
|
|
1943
|
+
const nodeId = segments[0];
|
|
1944
|
+
let nodeOutput = context2.previousOutputs.get(nodeId);
|
|
1945
|
+
if (nodeOutput === undefined) {
|
|
1946
|
+
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1947
|
+
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1948
|
+
if (normalizedUnderscore !== nodeId) {
|
|
1949
|
+
nodeOutput = context2.previousOutputs.get(normalizedUnderscore);
|
|
1950
|
+
}
|
|
1951
|
+
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1952
|
+
nodeOutput = context2.previousOutputs.get(normalizedHyphen);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
if (nodeOutput === undefined) {
|
|
1956
|
+
return match;
|
|
1957
|
+
}
|
|
1958
|
+
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
1959
|
+
if (segments.length === 1) {
|
|
1960
|
+
return this.stringifyValue(nodeOutput, match);
|
|
1961
|
+
}
|
|
1962
|
+
let value = nodeOutput;
|
|
1963
|
+
let startIndex = 1;
|
|
1964
|
+
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
1965
|
+
startIndex = 2;
|
|
1966
|
+
}
|
|
1967
|
+
for (let i = startIndex;i < segments.length; i++) {
|
|
1968
|
+
if (value === null || value === undefined) {
|
|
1969
|
+
return match;
|
|
1970
|
+
}
|
|
1971
|
+
value = value[segments[i]];
|
|
1972
|
+
}
|
|
1973
|
+
return this.stringifyValue(value, match);
|
|
1974
|
+
});
|
|
1975
|
+
resolved = resolved.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
|
|
1976
|
+
if (path.startsWith("input.") || path.startsWith("nodes.")) {
|
|
1977
|
+
return match;
|
|
1978
|
+
}
|
|
1979
|
+
const segments = path.split(".");
|
|
1980
|
+
const nodeId = segments[0];
|
|
1981
|
+
let nodeOutput = context2.previousOutputs.get(nodeId);
|
|
1982
|
+
if (nodeOutput === undefined) {
|
|
1983
|
+
const normalizedUnderscore = nodeId.replace(/-/g, "_");
|
|
1984
|
+
const normalizedHyphen = nodeId.replace(/_/g, "-");
|
|
1985
|
+
if (normalizedUnderscore !== nodeId) {
|
|
1986
|
+
nodeOutput = context2.previousOutputs.get(normalizedUnderscore);
|
|
1987
|
+
}
|
|
1988
|
+
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
1989
|
+
nodeOutput = context2.previousOutputs.get(normalizedHyphen);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
if (nodeOutput === undefined) {
|
|
1993
|
+
return match;
|
|
1994
|
+
}
|
|
1995
|
+
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
1996
|
+
if (segments.length === 1) {
|
|
1997
|
+
return this.stringifyValue(nodeOutput, match);
|
|
1998
|
+
}
|
|
1999
|
+
let value = nodeOutput;
|
|
2000
|
+
let startIndex = 1;
|
|
2001
|
+
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
2002
|
+
startIndex = 2;
|
|
2003
|
+
}
|
|
2004
|
+
for (let i = startIndex;i < segments.length; i++) {
|
|
2005
|
+
if (value === null || value === undefined) {
|
|
2006
|
+
return match;
|
|
2007
|
+
}
|
|
2008
|
+
value = value[segments[i]];
|
|
2009
|
+
}
|
|
2010
|
+
return this.stringifyValue(value, match);
|
|
2011
|
+
});
|
|
2012
|
+
return resolved;
|
|
2013
|
+
}
|
|
2014
|
+
stringifyValue(value, originalTemplate) {
|
|
2015
|
+
if (value === undefined) {
|
|
2016
|
+
return originalTemplate;
|
|
2017
|
+
}
|
|
2018
|
+
if (value === null) {
|
|
2019
|
+
return "null";
|
|
2020
|
+
}
|
|
2021
|
+
if (typeof value === "string") {
|
|
2022
|
+
return value;
|
|
2023
|
+
}
|
|
2024
|
+
return JSON.stringify(value);
|
|
2025
|
+
}
|
|
2026
|
+
extractFromWrapper(value) {
|
|
2027
|
+
if (value === null || value === undefined) {
|
|
2028
|
+
return value;
|
|
2029
|
+
}
|
|
2030
|
+
if (typeof value !== "object") {
|
|
2031
|
+
return value;
|
|
2032
|
+
}
|
|
2033
|
+
if ("result" in value && "metadata" in value) {
|
|
2034
|
+
return value.result;
|
|
2035
|
+
}
|
|
2036
|
+
if ("output" in value) {
|
|
2037
|
+
return value.output;
|
|
2038
|
+
}
|
|
2039
|
+
return value;
|
|
2040
|
+
}
|
|
2041
|
+
getNestedValue(obj, path) {
|
|
2042
|
+
if (!obj) {
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
if ("input" in obj && path in obj["input"]) {
|
|
2046
|
+
return obj["input"][path];
|
|
2047
|
+
}
|
|
2048
|
+
return path.split(".").reduce((current, key) => {
|
|
2049
|
+
if (current && typeof current === "object") {
|
|
2050
|
+
return current[key];
|
|
2051
|
+
}
|
|
2052
|
+
return;
|
|
2053
|
+
}, obj);
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
__legacyDecorateClassTS([
|
|
2057
|
+
TracedAs("agent.node.execute", { recordParams: true, recordResult: true, log: true })
|
|
2058
|
+
], AgentNode.prototype, "execute", null);
|
|
2059
|
+
__legacyDecorateClassTS([
|
|
2060
|
+
TracedAs("agent.node.createAgentSubSession", { recordParams: true, recordResult: true, log: true })
|
|
2061
|
+
], AgentNode.prototype, "createAgentSubSession", null);
|
|
2062
|
+
});
|
|
2063
|
+
|
|
2064
|
+
// src/env/workflow/nodes/workflow-node.ts
|
|
2065
|
+
class WorkflowNode {
|
|
2066
|
+
workflowRunner;
|
|
2067
|
+
type = "workflow";
|
|
2068
|
+
id;
|
|
2069
|
+
config;
|
|
2070
|
+
constructor(definition, workflowRunner) {
|
|
2071
|
+
this.workflowRunner = workflowRunner;
|
|
2072
|
+
this.id = definition.id;
|
|
2073
|
+
this.config = definition.config ?? {};
|
|
2074
|
+
}
|
|
2075
|
+
async execute(context2) {
|
|
2076
|
+
const startTime = Date.now();
|
|
2077
|
+
try {
|
|
2078
|
+
const workflowName = this.config.workflow_name;
|
|
2079
|
+
if (!workflowName) {
|
|
2080
|
+
throw new Error("workflow_name is required in config. Please specify config.workflow_name in the node definition.");
|
|
2081
|
+
}
|
|
2082
|
+
const previousOutputs = context2.previousOutputs ?? this.convertToMap(context2.nodeOutputs ?? {});
|
|
2083
|
+
const resolvedInput = this.resolveInput(this.config.input ?? {}, previousOutputs);
|
|
2084
|
+
const result = await this.workflowRunner.run(workflowName, resolvedInput);
|
|
2085
|
+
const success = result.status === "completed";
|
|
2086
|
+
return {
|
|
2087
|
+
success,
|
|
2088
|
+
output: result.output,
|
|
2089
|
+
error: success ? undefined : result.error,
|
|
2090
|
+
duration: Date.now() - startTime
|
|
2091
|
+
};
|
|
2092
|
+
} catch (error) {
|
|
2093
|
+
return {
|
|
2094
|
+
success: false,
|
|
2095
|
+
output: undefined,
|
|
2096
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
2097
|
+
duration: Date.now() - startTime
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
convertToMap(nodeOutputs) {
|
|
2102
|
+
const map = new Map;
|
|
2103
|
+
for (const [nodeId, result] of Object.entries(nodeOutputs)) {
|
|
2104
|
+
map.set(nodeId, result.output);
|
|
2105
|
+
}
|
|
2106
|
+
return map;
|
|
2107
|
+
}
|
|
2108
|
+
resolveInput(input, previousOutputs) {
|
|
2109
|
+
const resolved = {};
|
|
2110
|
+
for (const [key, value] of Object.entries(input)) {
|
|
2111
|
+
resolved[key] = this.resolveValue(value, previousOutputs);
|
|
2112
|
+
}
|
|
2113
|
+
return resolved;
|
|
2114
|
+
}
|
|
2115
|
+
resolveValue(value, previousOutputs) {
|
|
2116
|
+
if (typeof value === "string") {
|
|
2117
|
+
return this.resolveStringTemplate(value, previousOutputs);
|
|
2118
|
+
}
|
|
2119
|
+
if (Array.isArray(value)) {
|
|
2120
|
+
return value.map((item) => this.resolveValue(item, previousOutputs));
|
|
2121
|
+
}
|
|
2122
|
+
if (value !== null && typeof value === "object") {
|
|
2123
|
+
const resolved = {};
|
|
2124
|
+
for (const [k, v] of Object.entries(value)) {
|
|
2125
|
+
resolved[k] = this.resolveValue(v, previousOutputs);
|
|
2126
|
+
}
|
|
2127
|
+
return resolved;
|
|
2128
|
+
}
|
|
2129
|
+
return value;
|
|
2130
|
+
}
|
|
2131
|
+
resolveStringTemplate(template, previousOutputs) {
|
|
2132
|
+
const templatePattern = /\{\{([^}]+)\}\}/g;
|
|
2133
|
+
return template.replace(templatePattern, (match, path) => {
|
|
2134
|
+
const trimmedPath = path.trim();
|
|
2135
|
+
const value = this.resolvePath(trimmedPath, previousOutputs);
|
|
2136
|
+
if (value !== undefined) {
|
|
2137
|
+
return this.stringifyValue(value, match);
|
|
2138
|
+
}
|
|
2139
|
+
return match;
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
resolvePath(path, previousOutputs) {
|
|
2143
|
+
const segments = path.split(".");
|
|
2144
|
+
if (segments.length === 0) {
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
const nodeId = segments[0];
|
|
2148
|
+
let nodeOutput = previousOutputs.get(nodeId);
|
|
2149
|
+
if (nodeOutput === undefined) {
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
nodeOutput = this.extractFromWrapper(nodeOutput);
|
|
2153
|
+
if (segments.length === 1) {
|
|
2154
|
+
return nodeOutput;
|
|
2155
|
+
}
|
|
2156
|
+
let current = nodeOutput;
|
|
2157
|
+
let startIndex = 1;
|
|
2158
|
+
if (segments.length > 1 && (segments[1] === "output" || segments[1] === "result" || segments[1] === "metadata")) {
|
|
2159
|
+
startIndex = 2;
|
|
2160
|
+
}
|
|
2161
|
+
for (let i = startIndex;i < segments.length; i++) {
|
|
2162
|
+
if (current === null || current === undefined) {
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
current = current[segments[i]];
|
|
2166
|
+
}
|
|
2167
|
+
return current;
|
|
2168
|
+
}
|
|
2169
|
+
extractFromWrapper(value) {
|
|
2170
|
+
if (value === null || value === undefined) {
|
|
2171
|
+
return value;
|
|
2172
|
+
}
|
|
2173
|
+
if (typeof value !== "object") {
|
|
2174
|
+
return value;
|
|
2175
|
+
}
|
|
2176
|
+
if ("result" in value && "metadata" in value) {
|
|
2177
|
+
return value.result;
|
|
2178
|
+
}
|
|
2179
|
+
if ("output" in value) {
|
|
2180
|
+
return value.output;
|
|
2181
|
+
}
|
|
2182
|
+
return value;
|
|
2183
|
+
}
|
|
2184
|
+
stringifyValue(value, originalTemplate) {
|
|
2185
|
+
if (value === undefined) {
|
|
2186
|
+
return originalTemplate;
|
|
2187
|
+
}
|
|
2188
|
+
if (value === null) {
|
|
2189
|
+
return "null";
|
|
2190
|
+
}
|
|
2191
|
+
if (typeof value === "string") {
|
|
2192
|
+
return value;
|
|
2193
|
+
}
|
|
2194
|
+
return JSON.stringify(value);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
var init_workflow_node = () => {};
|
|
2198
|
+
|
|
2199
|
+
// src/env/workflow/nodes/ask-user-node.ts
|
|
2200
|
+
class AskUserNode {
|
|
2201
|
+
type = "ask_user";
|
|
2202
|
+
id;
|
|
2203
|
+
config;
|
|
2204
|
+
constructor(definition) {
|
|
2205
|
+
this.id = definition.id;
|
|
2206
|
+
this.config = definition.config || {};
|
|
2207
|
+
}
|
|
2208
|
+
async execute(context2) {
|
|
2209
|
+
const query = this.config.query || "确认继续吗?";
|
|
2210
|
+
const options = this.config.options;
|
|
2211
|
+
const fullQuery = options ? `${query} (选项: ${options.join(", ")})` : query;
|
|
2212
|
+
await context2.eventBus.publish(createNodeInterruptEvent(context2.runId, this.id, this.type, fullQuery));
|
|
2213
|
+
throw new AskUserError(context2.runId, context2.sessionId, this.id, this.type, query);
|
|
2214
|
+
}
|
|
2215
|
+
validateConfig(_config) {
|
|
2216
|
+
return true;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
var init_ask_user_node = __esm(() => {
|
|
2220
|
+
init_workflow_hil();
|
|
2221
|
+
});
|
|
2222
|
+
|
|
2223
|
+
// src/env/workflow/engine/node-registry.ts
|
|
2224
|
+
class NodeRegistry {
|
|
2225
|
+
factories = new Map;
|
|
2226
|
+
toolRegistry;
|
|
2227
|
+
skillRegistry;
|
|
2228
|
+
agentRunner;
|
|
2229
|
+
workflowRunner;
|
|
2230
|
+
agentComponentAdapter;
|
|
2231
|
+
sessionComponent;
|
|
2232
|
+
constructor(options) {
|
|
2233
|
+
const {
|
|
2234
|
+
toolRegistry,
|
|
2235
|
+
skillRegistry,
|
|
2236
|
+
agentComponent,
|
|
2237
|
+
agentRunner,
|
|
2238
|
+
workflowRunner,
|
|
2239
|
+
sessionComponent
|
|
2240
|
+
} = options ?? {};
|
|
2241
|
+
this.toolRegistry = toolRegistry;
|
|
2242
|
+
this.skillRegistry = skillRegistry;
|
|
2243
|
+
this.workflowRunner = workflowRunner;
|
|
2244
|
+
this.sessionComponent = sessionComponent;
|
|
2245
|
+
if (agentRunner) {
|
|
2246
|
+
this.agentRunner = agentRunner;
|
|
2247
|
+
if (agentRunner.setSessionComponent && sessionComponent) {
|
|
2248
|
+
agentRunner.setSessionComponent(sessionComponent);
|
|
2249
|
+
}
|
|
2250
|
+
} else if (agentComponent) {
|
|
2251
|
+
this.agentComponentAdapter = new AgentComponentAdapter(agentComponent, {}, sessionComponent);
|
|
2252
|
+
this.agentRunner = this.agentComponentAdapter;
|
|
2253
|
+
}
|
|
2254
|
+
this.registerBuiltInTypes();
|
|
2255
|
+
}
|
|
2256
|
+
getAgentAdapter() {
|
|
2257
|
+
return this.agentComponentAdapter;
|
|
2258
|
+
}
|
|
2259
|
+
getAgentRunner() {
|
|
2260
|
+
return this.agentRunner;
|
|
2261
|
+
}
|
|
2262
|
+
getSessionComponent() {
|
|
2263
|
+
return this.sessionComponent;
|
|
2264
|
+
}
|
|
2265
|
+
registerBuiltInTypes() {
|
|
2266
|
+
this.factories.set("tool", (definition) => {
|
|
2267
|
+
if (!this.toolRegistry) {
|
|
2268
|
+
throw new Error("ToolRegistry is required for tool nodes");
|
|
2269
|
+
}
|
|
2270
|
+
return new ToolNode(definition, this.toolRegistry);
|
|
2271
|
+
});
|
|
2272
|
+
this.factories.set("skill", (definition) => {
|
|
2273
|
+
if (!this.skillRegistry) {
|
|
2274
|
+
throw new Error("SkillRegistry is required for skill nodes");
|
|
2275
|
+
}
|
|
2276
|
+
return new SkillNode(definition, this.skillRegistry);
|
|
2277
|
+
});
|
|
2278
|
+
this.factories.set("agent", (definition) => {
|
|
2279
|
+
if (!this.agentRunner) {
|
|
2280
|
+
throw new Error("AgentRunner is required for agent nodes");
|
|
2281
|
+
}
|
|
2282
|
+
return new AgentNode(definition, this.agentRunner);
|
|
2283
|
+
});
|
|
2284
|
+
this.factories.set("workflow", (definition) => {
|
|
2285
|
+
if (!this.workflowRunner) {
|
|
2286
|
+
throw new Error("WorkflowRunner is required for workflow nodes");
|
|
2287
|
+
}
|
|
2288
|
+
return new WorkflowNode(definition, this.workflowRunner);
|
|
2289
|
+
});
|
|
2290
|
+
this.factories.set("ask_user", (definition) => {
|
|
2291
|
+
return new AskUserNode(definition);
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
register(type, factory) {
|
|
2295
|
+
this.factories.set(type, factory);
|
|
2296
|
+
}
|
|
2297
|
+
has(type) {
|
|
2298
|
+
return this.factories.has(type);
|
|
2299
|
+
}
|
|
2300
|
+
list() {
|
|
2301
|
+
return Array.from(this.factories.keys());
|
|
2302
|
+
}
|
|
2303
|
+
createNode(definition, context2) {
|
|
2304
|
+
const factory = this.factories.get(definition.type);
|
|
2305
|
+
if (!factory) {
|
|
2306
|
+
const availableTypes = this.list().join(", ");
|
|
2307
|
+
throw new Error(`Unknown node type: ${definition.type}. Available types: ${availableTypes}`);
|
|
2308
|
+
}
|
|
2309
|
+
return factory(definition, context2);
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
var init_node_registry = __esm(() => {
|
|
2313
|
+
init_tool_node();
|
|
2314
|
+
init_skill_node();
|
|
2315
|
+
init_agent_node();
|
|
2316
|
+
init_agent_component_adapter();
|
|
2317
|
+
init_workflow_node();
|
|
2318
|
+
init_ask_user_node();
|
|
2319
|
+
});
|
|
2320
|
+
|
|
2321
|
+
// src/env/workflow/engine/engine.ts
|
|
2322
|
+
import { EventEmitter } from "events";
|
|
2323
|
+
var logger, WorkflowEngine;
|
|
2324
|
+
var init_engine = __esm(() => {
|
|
2325
|
+
init_event();
|
|
2326
|
+
init_workflow_hil();
|
|
2327
|
+
init_dag_manager();
|
|
2328
|
+
init_event_bus();
|
|
2329
|
+
init_scheduler();
|
|
2330
|
+
init_executor();
|
|
2331
|
+
init_node_registry();
|
|
2332
|
+
init_logger();
|
|
2333
|
+
init_decorator();
|
|
2334
|
+
logger = createLogger("workflow:engine");
|
|
2335
|
+
WorkflowEngine = class WorkflowEngine extends EventEmitter {
|
|
2336
|
+
activeSessions = new Map;
|
|
2337
|
+
sessionIdCounter = 0;
|
|
2338
|
+
sessionComponent;
|
|
2339
|
+
nodeRegistry;
|
|
2340
|
+
workflowRepository;
|
|
2341
|
+
constructor(nodeRegistry, sessionComponent, workflowRepository) {
|
|
2342
|
+
super();
|
|
2343
|
+
this.nodeRegistry = nodeRegistry;
|
|
2344
|
+
this.sessionComponent = sessionComponent;
|
|
2345
|
+
this.workflowRepository = workflowRepository;
|
|
2346
|
+
}
|
|
2347
|
+
static async create(options) {
|
|
2348
|
+
const agentComponent = options.env?.getComponent("agent");
|
|
2349
|
+
const sessionComponent = options.sessionComponent;
|
|
2350
|
+
const nodeRegistry = new NodeRegistry({
|
|
2351
|
+
toolRegistry: options.toolRegistry,
|
|
2352
|
+
skillRegistry: options.skillRegistry,
|
|
2353
|
+
agentComponent,
|
|
2354
|
+
workflowRunner: options.workflowRunner,
|
|
2355
|
+
sessionComponent
|
|
2356
|
+
});
|
|
2357
|
+
return new WorkflowEngine(nodeRegistry, sessionComponent, options.workflowRepository);
|
|
2358
|
+
}
|
|
2359
|
+
generateRunId() {
|
|
2360
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
2361
|
+
return `run_${Date.now()}_${++this.sessionIdCounter}_${random}`;
|
|
2362
|
+
}
|
|
2363
|
+
getRunIdFromSessionId(sessionId) {
|
|
2364
|
+
return sessionId.replace(/^workflow_/, "");
|
|
2365
|
+
}
|
|
2366
|
+
getSessionId(runId) {
|
|
2367
|
+
return `workflow_${runId}`;
|
|
2368
|
+
}
|
|
2369
|
+
async createSession(workflow2, options) {
|
|
2370
|
+
const definition = "definition" in workflow2 ? workflow2.definition : workflow2;
|
|
2371
|
+
const workflowId = "id" in workflow2 ? workflow2.id : `inline_${definition.name}`;
|
|
2372
|
+
const workflowName = definition.name;
|
|
2373
|
+
const runId = this.generateRunId();
|
|
2374
|
+
const sessionId = this.getSessionId(runId);
|
|
2375
|
+
const metadata = {
|
|
2376
|
+
type: "workflow",
|
|
2377
|
+
workflowId,
|
|
2378
|
+
workflowName,
|
|
2379
|
+
workflowVersion: definition.version,
|
|
2380
|
+
status: "running",
|
|
2381
|
+
input: options?.input,
|
|
2382
|
+
agentSessions: []
|
|
2383
|
+
};
|
|
2384
|
+
if (this.sessionComponent) {
|
|
2385
|
+
await this.sessionComponent.create({
|
|
2386
|
+
id: sessionId,
|
|
2387
|
+
title: `Workflow: ${workflowName} (${runId})`,
|
|
2388
|
+
metadata
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2391
|
+
logger.info(`[WorkflowEngine] Created session: ${sessionId}`);
|
|
2392
|
+
return sessionId;
|
|
2393
|
+
}
|
|
2394
|
+
async run(sessionId, options) {
|
|
2395
|
+
let session = this.sessionComponent ? await this.sessionComponent.get(sessionId) : null;
|
|
2396
|
+
let workflowDef = null;
|
|
2397
|
+
let workflowId = "";
|
|
2398
|
+
let workflowName = "";
|
|
2399
|
+
if (session) {
|
|
2400
|
+
const metadata2 = session.metadata;
|
|
2401
|
+
if (metadata2.type === "workflow" && metadata2.workflowId) {
|
|
2402
|
+
workflowDef = this.findDefinitionForWorkflow(metadata2.workflowId);
|
|
2403
|
+
workflowId = metadata2.workflowId;
|
|
2404
|
+
workflowName = metadata2.workflowName;
|
|
2405
|
+
}
|
|
2406
|
+
if (!workflowDef && metadata2.workflowName) {
|
|
2407
|
+
workflowDef = this.findDefinitionForWorkflow(metadata2.workflowName);
|
|
2408
|
+
workflowId = metadata2.workflowName;
|
|
2409
|
+
workflowName = metadata2.workflowName;
|
|
2410
|
+
}
|
|
2411
|
+
} else {
|
|
2412
|
+
if (!options?.workflowId) {
|
|
2413
|
+
throw new Error("workflowId required for new session");
|
|
2414
|
+
}
|
|
2415
|
+
workflowDef = this.findDefinitionForWorkflow(options.workflowId);
|
|
2416
|
+
if (!workflowDef) {
|
|
2417
|
+
throw new Error(`Workflow not found: ${options.workflowId}`);
|
|
2418
|
+
}
|
|
2419
|
+
workflowId = options.workflowId;
|
|
2420
|
+
workflowName = workflowDef.name;
|
|
2421
|
+
if (this.sessionComponent) {
|
|
2422
|
+
const sessionMetadata = {
|
|
2423
|
+
type: "workflow",
|
|
2424
|
+
workflowId,
|
|
2425
|
+
workflowName,
|
|
2426
|
+
workflowVersion: workflowDef.version,
|
|
2427
|
+
status: "running"
|
|
2428
|
+
};
|
|
2429
|
+
await this.sessionComponent.create({
|
|
2430
|
+
id: sessionId,
|
|
2431
|
+
title: `Workflow: ${workflowName}`,
|
|
2432
|
+
metadata: sessionMetadata
|
|
2433
|
+
});
|
|
2434
|
+
session = await this.sessionComponent.get(sessionId);
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
if (!session || !workflowDef) {
|
|
2438
|
+
throw new Error(`Cannot start workflow: session or workflow not found`);
|
|
2439
|
+
}
|
|
2440
|
+
const metadata = session.metadata;
|
|
2441
|
+
if (metadata.status === "completed") {
|
|
2442
|
+
return { runId: this.getRunIdFromSessionId(sessionId), status: "completed" };
|
|
2443
|
+
}
|
|
2444
|
+
if (metadata.status === "failed") {
|
|
2445
|
+
return { runId: this.getRunIdFromSessionId(sessionId), status: "failed" };
|
|
2446
|
+
}
|
|
2447
|
+
const messages = this.sessionComponent ? await this.sessionComponent.getMessages(sessionId) : [];
|
|
2448
|
+
const { inferNextNode } = await import("./chunk-25x2pdtp.js");
|
|
2449
|
+
const entry = workflowDef.entry;
|
|
2450
|
+
const entryNode = Array.isArray(entry) ? entry[0] : entry;
|
|
2451
|
+
const resumePoint = inferNextNode(messages, {
|
|
2452
|
+
entryNode: entryNode !== "__default_entry__" ? entryNode : undefined,
|
|
2453
|
+
edges: undefined
|
|
2454
|
+
});
|
|
2455
|
+
const sessionState = await this.initializeSessionState(sessionId, workflowDef, workflowId, workflowName, options);
|
|
2456
|
+
this.activeSessions.set(sessionId, sessionState);
|
|
2457
|
+
return this.runWithResume(sessionId, resumePoint, options);
|
|
2458
|
+
}
|
|
2459
|
+
async initializeSessionState(sessionId, definition, workflowId, workflowName, options) {
|
|
2460
|
+
const dagManager = new DAGManager(definition);
|
|
2461
|
+
const validation = dagManager.validate();
|
|
2462
|
+
if (!validation.valid) {
|
|
2463
|
+
throw new Error(`Invalid workflow: ${validation.errors.join(", ")}`);
|
|
2464
|
+
}
|
|
2465
|
+
const parallelLimit = options?.parallelLimit ?? definition.config?.parallel_limit ?? null;
|
|
2466
|
+
const scheduler = new Scheduler(dagManager, { parallelLimit });
|
|
2467
|
+
const eventBus = new EventBus;
|
|
2468
|
+
const executorOptions = {
|
|
2469
|
+
globalTimeout: options?.timeout ?? definition.config?.timeout ?? null,
|
|
2470
|
+
globalRetry: definition.config?.retry ?? null,
|
|
2471
|
+
debug: options?.debug ?? definition.config?.debug ?? false
|
|
2472
|
+
};
|
|
2473
|
+
const executor = new Executor(this.nodeRegistry, eventBus, executorOptions, this.sessionComponent);
|
|
2474
|
+
const config = {
|
|
2475
|
+
parallelLimit,
|
|
2476
|
+
timeout: options?.timeout ?? definition.config?.timeout ?? null,
|
|
2477
|
+
debug: options?.debug ?? definition.config?.debug ?? false
|
|
2478
|
+
};
|
|
2479
|
+
const abortController = new AbortController;
|
|
2480
|
+
let resolveCompleted;
|
|
2481
|
+
let rejectCompleted;
|
|
2482
|
+
const completedPromise = new Promise((resolve, reject) => {
|
|
2483
|
+
resolveCompleted = resolve;
|
|
2484
|
+
rejectCompleted = reject;
|
|
2485
|
+
});
|
|
2486
|
+
const sessionState = {
|
|
2487
|
+
sessionId,
|
|
2488
|
+
workflowId,
|
|
2489
|
+
workflowName,
|
|
2490
|
+
status: "running",
|
|
2491
|
+
startedAt: new Date,
|
|
2492
|
+
eventBus,
|
|
2493
|
+
dagManager,
|
|
2494
|
+
scheduler,
|
|
2495
|
+
executor,
|
|
2496
|
+
nodeRegistry: this.nodeRegistry,
|
|
2497
|
+
nodeOutputs: new Map,
|
|
2498
|
+
config,
|
|
2499
|
+
abortController,
|
|
2500
|
+
completedPromise,
|
|
2501
|
+
resolveCompleted,
|
|
2502
|
+
rejectCompleted,
|
|
2503
|
+
workflowHistory: [],
|
|
2504
|
+
agentSessions: new Map
|
|
2505
|
+
};
|
|
2506
|
+
this.setupEventHandlers(sessionState);
|
|
2507
|
+
return sessionState;
|
|
2508
|
+
}
|
|
2509
|
+
async runWithResume(sessionId, resumePoint, options) {
|
|
2510
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
2511
|
+
if (!sessionState) {
|
|
2512
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
2513
|
+
}
|
|
2514
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
2515
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.started", runId, {
|
|
2516
|
+
workflow_name: sessionState.workflowName,
|
|
2517
|
+
input: options?.input
|
|
2518
|
+
}));
|
|
2519
|
+
let pendingNodeId;
|
|
2520
|
+
let agentSessionId;
|
|
2521
|
+
switch (resumePoint.type) {
|
|
2522
|
+
case "entry_node":
|
|
2523
|
+
case "next_nodes":
|
|
2524
|
+
pendingNodeId = undefined;
|
|
2525
|
+
break;
|
|
2526
|
+
case "resume_node":
|
|
2527
|
+
case "ask_user":
|
|
2528
|
+
pendingNodeId = resumePoint.nodeId;
|
|
2529
|
+
agentSessionId = resumePoint.agentSessionId;
|
|
2530
|
+
break;
|
|
2531
|
+
}
|
|
2532
|
+
const userResponse = typeof options?.input === "string" ? options.input : undefined;
|
|
2533
|
+
this.scheduleAndExecute(sessionState, {
|
|
2534
|
+
input: options?.input,
|
|
2535
|
+
pendingNodeId,
|
|
2536
|
+
agentSessionId,
|
|
2537
|
+
userResponse
|
|
2538
|
+
}).catch((error) => {
|
|
2539
|
+
logger.error(`Workflow ${sessionId} scheduling error:`, error);
|
|
2540
|
+
this.failWorkflow(sessionState, error);
|
|
2541
|
+
});
|
|
2542
|
+
if (options?.sync !== false) {
|
|
2543
|
+
return this.waitForCompletion(sessionId, options?.timeout);
|
|
2544
|
+
}
|
|
2545
|
+
return { runId, status: "running" };
|
|
2546
|
+
}
|
|
2547
|
+
async runWorkflow(workflow2, options) {
|
|
2548
|
+
const definition = "definition" in workflow2 ? workflow2.definition : workflow2;
|
|
2549
|
+
const workflowId = "id" in workflow2 ? workflow2.id : `inline_${definition.name}`;
|
|
2550
|
+
const workflowName = definition.name;
|
|
2551
|
+
const sessionId = await this.createSession(workflow2, options);
|
|
2552
|
+
const sessionState = await this.initializeSessionState(sessionId, definition, workflowId, workflowName, options);
|
|
2553
|
+
this.activeSessions.set(sessionId, sessionState);
|
|
2554
|
+
return this.runWithResume(sessionId, { type: "entry_node" }, options);
|
|
2555
|
+
}
|
|
2556
|
+
async pause(sessionId) {
|
|
2557
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
2558
|
+
if (!sessionState) {
|
|
2559
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
2560
|
+
}
|
|
2561
|
+
if (sessionState.status !== "running") {
|
|
2562
|
+
throw new Error(`Session ${sessionId} is not running (current: ${sessionState.status})`);
|
|
2563
|
+
}
|
|
2564
|
+
sessionState.status = "paused";
|
|
2565
|
+
sessionState.abortController.abort();
|
|
2566
|
+
sessionState.executor.cancelAll();
|
|
2567
|
+
if (this.sessionComponent) {
|
|
2568
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
2569
|
+
await this.sessionComponent.update(sessionId, {
|
|
2570
|
+
metadata: { ...metadata, status: "paused" }
|
|
2571
|
+
});
|
|
2572
|
+
}
|
|
2573
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.paused", this.getRunIdFromSessionId(sessionId), {}));
|
|
2574
|
+
logger.info(`[WorkflowEngine] Workflow paused: ${sessionId}`);
|
|
2575
|
+
}
|
|
2576
|
+
async resume(sessionId, options) {
|
|
2577
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
2578
|
+
if (!sessionState) {
|
|
2579
|
+
logger.info(`[WorkflowEngine] Session not in memory, attempting to restore from DB: ${sessionId}`);
|
|
2580
|
+
return this.resumeFromDatabase(sessionId, options);
|
|
2581
|
+
}
|
|
2582
|
+
if (options?.response) {
|
|
2583
|
+
await this.writeNodeResume(sessionId, options.response);
|
|
2584
|
+
}
|
|
2585
|
+
if (sessionState.status === "running") {
|
|
2586
|
+
return { runId: this.getRunIdFromSessionId(sessionId), status: "running" };
|
|
2587
|
+
}
|
|
2588
|
+
if (sessionState.status !== "paused") {
|
|
2589
|
+
throw new Error(`Session ${sessionId} is not paused (current: ${sessionState.status})`);
|
|
2590
|
+
}
|
|
2591
|
+
sessionState.status = "running";
|
|
2592
|
+
sessionState.abortController = new AbortController;
|
|
2593
|
+
if (this.sessionComponent) {
|
|
2594
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
2595
|
+
await this.sessionComponent.update(sessionId, {
|
|
2596
|
+
metadata: { ...metadata, status: "running" }
|
|
2597
|
+
});
|
|
2598
|
+
}
|
|
2599
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.resumed", this.getRunIdFromSessionId(sessionId), {
|
|
2600
|
+
userResponse: options?.response
|
|
2601
|
+
}));
|
|
2602
|
+
const runtimeState = await this.restoreRuntimeState(sessionId);
|
|
2603
|
+
this.scheduleAndExecute(sessionState, {
|
|
2604
|
+
pendingNodeId: runtimeState.pendingNodeId || undefined,
|
|
2605
|
+
agentSessionId: runtimeState.agentSessionId,
|
|
2606
|
+
userResponse: options?.response,
|
|
2607
|
+
restoredOutputs: runtimeState.nodeOutputs
|
|
2608
|
+
});
|
|
2609
|
+
return {
|
|
2610
|
+
runId: this.getRunIdFromSessionId(sessionId),
|
|
2611
|
+
status: "running"
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
async resumeFromDatabase(sessionId, options) {
|
|
2615
|
+
const session = await this.sessionComponent?.get(sessionId);
|
|
2616
|
+
if (!session) {
|
|
2617
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
2618
|
+
}
|
|
2619
|
+
const metadata = session.metadata;
|
|
2620
|
+
if (metadata.type !== "workflow") {
|
|
2621
|
+
throw new Error(`Session is not a workflow session: ${sessionId}`);
|
|
2622
|
+
}
|
|
2623
|
+
if (metadata.status !== "paused") {
|
|
2624
|
+
throw new Error(`Workflow is not paused: ${sessionId}, status: ${metadata.status}`);
|
|
2625
|
+
}
|
|
2626
|
+
const runtimeState = await this.restoreRuntimeState(sessionId);
|
|
2627
|
+
if (!runtimeState.pendingNodeId) {
|
|
2628
|
+
throw new Error(`No pending node found in session: ${sessionId}`);
|
|
2629
|
+
}
|
|
2630
|
+
if (options?.response) {
|
|
2631
|
+
await this.writeNodeResume(sessionId, options.response);
|
|
2632
|
+
}
|
|
2633
|
+
if (this.sessionComponent) {
|
|
2634
|
+
await this.sessionComponent.update(sessionId, {
|
|
2635
|
+
metadata: { ...metadata, status: "running" }
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
logger.info(`[WorkflowEngine] Resumed from database: ${sessionId}, pendingNode: ${runtimeState.pendingNodeId}`);
|
|
2639
|
+
throw new Error(`Cannot resume from database without workflow definition. Session ${sessionId} is paused at node "${runtimeState.pendingNodeId}". Please ensure the workflow is registered before resuming.`);
|
|
2640
|
+
}
|
|
2641
|
+
async restoreRuntimeState(sessionId) {
|
|
2642
|
+
const messages = this.sessionComponent ? await this.sessionComponent.getMessages(sessionId) : [];
|
|
2643
|
+
const nodeOutputs = new Map;
|
|
2644
|
+
let lastCallNodeId = null;
|
|
2645
|
+
let lastInterruptMessage = null;
|
|
2646
|
+
let agentSessionId;
|
|
2647
|
+
for (const msg of messages) {
|
|
2648
|
+
const msgMetadata = msg.metadata;
|
|
2649
|
+
if (msgMetadata?.type === "workflow.node.call") {
|
|
2650
|
+
lastCallNodeId = msgMetadata.workflowNodeId;
|
|
2651
|
+
} else if (msgMetadata?.type === "workflow.node.result") {
|
|
2652
|
+
if (lastCallNodeId) {
|
|
2653
|
+
try {
|
|
2654
|
+
nodeOutputs.set(lastCallNodeId, JSON.parse(msg.content));
|
|
2655
|
+
} catch {
|
|
2656
|
+
nodeOutputs.set(lastCallNodeId, msg.content);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
lastCallNodeId = null;
|
|
2660
|
+
} else if (msgMetadata?.type === "workflow.node.interrupt") {
|
|
2661
|
+
lastInterruptMessage = msg;
|
|
2662
|
+
lastCallNodeId = msgMetadata.workflowNodeId;
|
|
2663
|
+
agentSessionId = msgMetadata.agentSessionId;
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
return {
|
|
2667
|
+
nodeOutputs,
|
|
2668
|
+
pendingNodeId: lastCallNodeId,
|
|
2669
|
+
waitingForUser: !!lastInterruptMessage,
|
|
2670
|
+
agentSessionId,
|
|
2671
|
+
lastInterruptMessage
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
async writeNodeResume(sessionId, response) {
|
|
2675
|
+
if (this.sessionComponent) {
|
|
2676
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
2677
|
+
role: "workflow.node.resume",
|
|
2678
|
+
content: response,
|
|
2679
|
+
metadata: {
|
|
2680
|
+
type: "workflow.node.resume",
|
|
2681
|
+
response,
|
|
2682
|
+
timestamp: Date.now()
|
|
2683
|
+
}
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
async stop(sessionId, reason) {
|
|
2688
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
2689
|
+
if (!sessionState) {
|
|
2690
|
+
if (this.sessionComponent) {
|
|
2691
|
+
await this.sessionComponent.update(sessionId, {
|
|
2692
|
+
metadata: { status: "stopped" }
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
sessionState.status = "stopped";
|
|
2698
|
+
sessionState.abortController.abort();
|
|
2699
|
+
sessionState.executor.cancelAll();
|
|
2700
|
+
if (this.sessionComponent) {
|
|
2701
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
2702
|
+
await this.sessionComponent.update(sessionId, {
|
|
2703
|
+
metadata: { ...metadata, status: "stopped" }
|
|
2704
|
+
});
|
|
2705
|
+
}
|
|
2706
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.stopped", this.getRunIdFromSessionId(sessionId), {
|
|
2707
|
+
reason: reason ?? "User requested stop"
|
|
2708
|
+
}));
|
|
2709
|
+
this.cleanupSession(sessionState);
|
|
2710
|
+
}
|
|
2711
|
+
getSessionStatus(sessionId) {
|
|
2712
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
2713
|
+
return sessionState?.status ?? null;
|
|
2714
|
+
}
|
|
2715
|
+
isSessionActive(sessionId) {
|
|
2716
|
+
return this.activeSessions.has(sessionId);
|
|
2717
|
+
}
|
|
2718
|
+
setupEventHandlers(sessionState) {
|
|
2719
|
+
const { sessionId, eventBus, scheduler } = sessionState;
|
|
2720
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
2721
|
+
eventBus.on("node.completed", async (event2) => {
|
|
2722
|
+
if (event2.type !== "node.completed")
|
|
2723
|
+
return;
|
|
2724
|
+
sessionState.nodeOutputs.set(event2.node_id, event2.output);
|
|
2725
|
+
scheduler.markCompleted(event2.node_id);
|
|
2726
|
+
if (event2.output && typeof event2.output === "object" && "workflowHistory" in event2.output) {
|
|
2727
|
+
const messages = event2.output.workflowHistory;
|
|
2728
|
+
if (Array.isArray(messages)) {
|
|
2729
|
+
sessionState.workflowHistory.push(...messages);
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
this.checkAndFinalize(sessionState);
|
|
2733
|
+
});
|
|
2734
|
+
eventBus.on("node.failed", async (event2) => {
|
|
2735
|
+
if (event2.type !== "node.failed")
|
|
2736
|
+
return;
|
|
2737
|
+
scheduler.markFailed(event2.node_id);
|
|
2738
|
+
await this.failWorkflow(sessionState, new Error(event2.error.message));
|
|
2739
|
+
});
|
|
2740
|
+
eventBus.on("node.interrupt", async (event2) => {
|
|
2741
|
+
if (event2.type !== "node.interrupt")
|
|
2742
|
+
return;
|
|
2743
|
+
logger.info(`Workflow paused at node "${event2.node_id}" - ask_user pending`);
|
|
2744
|
+
sessionState.status = "paused";
|
|
2745
|
+
sessionState.abortController.abort();
|
|
2746
|
+
if (this.sessionComponent) {
|
|
2747
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
2748
|
+
await this.sessionComponent.update(sessionId, {
|
|
2749
|
+
metadata: { ...metadata, status: "paused" }
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
await eventBus.publish(createWorkflowEvent("workflow.paused", runId, {
|
|
2753
|
+
pendingNodeId: event2.node_id,
|
|
2754
|
+
query: event2.query
|
|
2755
|
+
}));
|
|
2756
|
+
await this.writeNodeInterrupt(sessionId, event2.node_id, event2.node_type, event2.query, event2.agent_session_id);
|
|
2757
|
+
sessionState.resolveCompleted({
|
|
2758
|
+
runId,
|
|
2759
|
+
status: "paused",
|
|
2760
|
+
pendingNodeId: event2.node_id,
|
|
2761
|
+
query: event2.query,
|
|
2762
|
+
agentSessionId: event2.agent_session_id
|
|
2763
|
+
});
|
|
2764
|
+
});
|
|
2765
|
+
}
|
|
2766
|
+
async writeNodeInterrupt(sessionId, nodeId, nodeType, query, agentSessionId) {
|
|
2767
|
+
if (this.sessionComponent) {
|
|
2768
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
2769
|
+
role: "workflow.node.interrupt",
|
|
2770
|
+
content: query,
|
|
2771
|
+
metadata: {
|
|
2772
|
+
type: "workflow.node.interrupt",
|
|
2773
|
+
workflowNodeId: nodeId,
|
|
2774
|
+
workflowNodeType: nodeType,
|
|
2775
|
+
query,
|
|
2776
|
+
agentSessionId,
|
|
2777
|
+
timestamp: Date.now()
|
|
2778
|
+
}
|
|
2779
|
+
});
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
async scheduleAndExecute(sessionState, options) {
|
|
2783
|
+
const { scheduler, executor, eventBus, abortController, nodeOutputs } = sessionState;
|
|
2784
|
+
const { input: globalInput, pendingNodeId, agentSessionId, userResponse, restoredOutputs } = options || {};
|
|
2785
|
+
if (restoredOutputs) {
|
|
2786
|
+
for (const [nodeId, output] of restoredOutputs) {
|
|
2787
|
+
nodeOutputs.set(nodeId, output);
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
const scheduleAvailableNodes = async () => {
|
|
2791
|
+
const state = scheduler.getState();
|
|
2792
|
+
const completedNodes = new Set(state.completed);
|
|
2793
|
+
const readyNodes = scheduler.getReadyNodes(completedNodes);
|
|
2794
|
+
const canStart = scheduler.canStartMore();
|
|
2795
|
+
if (readyNodes.length === 0 || !canStart) {
|
|
2796
|
+
return false;
|
|
2797
|
+
}
|
|
2798
|
+
let scheduled = 0;
|
|
2799
|
+
for (const nodeId of readyNodes) {
|
|
2800
|
+
if (!scheduler.canStartMore())
|
|
2801
|
+
break;
|
|
2802
|
+
if (scheduled >= (sessionState.config.parallelLimit ?? Infinity))
|
|
2803
|
+
break;
|
|
2804
|
+
await this.startNode(sessionState, nodeId, globalInput);
|
|
2805
|
+
scheduled++;
|
|
2806
|
+
}
|
|
2807
|
+
return true;
|
|
2808
|
+
};
|
|
2809
|
+
if (pendingNodeId) {
|
|
2810
|
+
await this.resumeNode(sessionState, pendingNodeId, {
|
|
2811
|
+
agentSessionId,
|
|
2812
|
+
userResponse
|
|
2813
|
+
});
|
|
2814
|
+
} else {
|
|
2815
|
+
await scheduleAvailableNodes();
|
|
2816
|
+
}
|
|
2817
|
+
while (sessionState.status === "running" && !abortController.signal.aborted) {
|
|
2818
|
+
const state = scheduler.getState();
|
|
2819
|
+
if (state.pending.length === 0 && state.running.length === 0) {
|
|
2820
|
+
break;
|
|
2821
|
+
}
|
|
2822
|
+
try {
|
|
2823
|
+
await this.waitForNextNodeEvent(sessionState, abortController.signal);
|
|
2824
|
+
} catch {
|
|
2825
|
+
break;
|
|
2826
|
+
}
|
|
2827
|
+
await scheduleAvailableNodes();
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
waitForNextNodeEvent(sessionState, signal) {
|
|
2831
|
+
return new Promise((resolve) => {
|
|
2832
|
+
const timeoutId = setTimeout(() => {
|
|
2833
|
+
cleanup();
|
|
2834
|
+
resolve();
|
|
2835
|
+
}, 100);
|
|
2836
|
+
const cleanup = () => {
|
|
2837
|
+
clearTimeout(timeoutId);
|
|
2838
|
+
sessionState.eventBus.off("node.completed", onCompleted);
|
|
2839
|
+
sessionState.eventBus.off("node.failed", onFailed);
|
|
2840
|
+
};
|
|
2841
|
+
const onCompleted = (event2) => {
|
|
2842
|
+
if (event2.type === "node.completed") {
|
|
2843
|
+
cleanup();
|
|
2844
|
+
resolve();
|
|
2845
|
+
}
|
|
2846
|
+
};
|
|
2847
|
+
const onFailed = (event2) => {
|
|
2848
|
+
if (event2.type === "node.failed") {
|
|
2849
|
+
cleanup();
|
|
2850
|
+
resolve();
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2853
|
+
sessionState.eventBus.on("node.completed", onCompleted);
|
|
2854
|
+
sessionState.eventBus.on("node.failed", onFailed);
|
|
2855
|
+
if (signal.aborted) {
|
|
2856
|
+
cleanup();
|
|
2857
|
+
resolve();
|
|
2858
|
+
}
|
|
2859
|
+
});
|
|
2860
|
+
}
|
|
2861
|
+
async startNode(sessionState, nodeId, input) {
|
|
2862
|
+
const { scheduler, executor, eventBus, dagManager } = sessionState;
|
|
2863
|
+
const sessionId = sessionState.sessionId;
|
|
2864
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
2865
|
+
scheduler.markStarted(nodeId);
|
|
2866
|
+
await eventBus.publish(createWorkflowEvent("node.scheduled", runId, {
|
|
2867
|
+
node_id: nodeId
|
|
2868
|
+
}));
|
|
2869
|
+
const nodeDef = dagManager.getNode(nodeId);
|
|
2870
|
+
if (!nodeDef) {
|
|
2871
|
+
scheduler.markFailed(nodeId);
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
await this.writeNodeCall(sessionId, nodeId, nodeDef.type, input);
|
|
2875
|
+
const context2 = this.createExecutionContext(sessionState, nodeId, input);
|
|
2876
|
+
executor.executeNode(nodeDef, context2).catch(async (error) => {
|
|
2877
|
+
if (error instanceof AskUserError) {
|
|
2878
|
+
await eventBus.publish(createNodeInterruptEvent(runId, nodeId, nodeDef.type, error.query, error.agentSessionId));
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
scheduler.markFailed(nodeId);
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
async writeNodeCall(sessionId, nodeId, nodeType, input) {
|
|
2885
|
+
if (this.sessionComponent) {
|
|
2886
|
+
await this.sessionComponent.addMessage(sessionId, {
|
|
2887
|
+
role: "workflow.node.call",
|
|
2888
|
+
content: JSON.stringify({ input }),
|
|
2889
|
+
metadata: {
|
|
2890
|
+
type: "workflow.node.call",
|
|
2891
|
+
workflowNodeId: nodeId,
|
|
2892
|
+
workflowNodeType: nodeType,
|
|
2893
|
+
timestamp: Date.now()
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
async resumeNode(sessionState, nodeId, options) {
|
|
2899
|
+
const { scheduler, executor, eventBus, dagManager } = sessionState;
|
|
2900
|
+
const sessionId = sessionState.sessionId;
|
|
2901
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
2902
|
+
scheduler.markStarted(nodeId);
|
|
2903
|
+
await eventBus.publish(createWorkflowEvent("node.started", runId, {
|
|
2904
|
+
node_id: nodeId,
|
|
2905
|
+
agentSessionId: options?.agentSessionId,
|
|
2906
|
+
userResponse: options?.userResponse
|
|
2907
|
+
}));
|
|
2908
|
+
const nodeDef = dagManager.getNode(nodeId);
|
|
2909
|
+
if (!nodeDef) {
|
|
2910
|
+
scheduler.markFailed(nodeId);
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
const context2 = this.createExecutionContext(sessionState, nodeId, undefined);
|
|
2914
|
+
if (options?.agentSessionId || options?.userResponse) {
|
|
2915
|
+
context2.agentSessionId = options.agentSessionId;
|
|
2916
|
+
context2.userResponse = options.userResponse;
|
|
2917
|
+
}
|
|
2918
|
+
executor.executeNode(nodeDef, context2).catch((error) => {
|
|
2919
|
+
if (error instanceof AskUserError) {
|
|
2920
|
+
const event2 = createNodeInterruptEvent(runId, nodeId, nodeDef.type, error.query, error.agentSessionId);
|
|
2921
|
+
eventBus.publish(event2);
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
scheduler.markFailed(nodeId);
|
|
2925
|
+
});
|
|
2926
|
+
}
|
|
2927
|
+
createExecutionContext(sessionState, nodeId, globalInput) {
|
|
2928
|
+
const nodeDef = sessionState.dagManager.getNode(nodeId);
|
|
2929
|
+
const runId = this.getRunIdFromSessionId(sessionState.sessionId);
|
|
2930
|
+
const deps = nodeDef.depends_on || [];
|
|
2931
|
+
const input = {};
|
|
2932
|
+
for (const depId of deps) {
|
|
2933
|
+
const depOutput = sessionState.nodeOutputs.get(depId);
|
|
2934
|
+
if (depOutput !== undefined) {
|
|
2935
|
+
input[depId] = depOutput;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
const analysis = sessionState.dagManager.analyze();
|
|
2939
|
+
if (analysis.entryNodes.includes(nodeId) && globalInput) {
|
|
2940
|
+
Object.assign(input, globalInput);
|
|
2941
|
+
}
|
|
2942
|
+
const askUser = (query) => {
|
|
2943
|
+
throw new AskUserError(runId, sessionState.sessionId, nodeId, nodeDef.type, query);
|
|
2944
|
+
};
|
|
2945
|
+
return {
|
|
2946
|
+
runId,
|
|
2947
|
+
sessionId: sessionState.sessionId,
|
|
2948
|
+
workflowName: sessionState.workflowName,
|
|
2949
|
+
nodeId,
|
|
2950
|
+
input,
|
|
2951
|
+
previousOutputs: sessionState.nodeOutputs,
|
|
2952
|
+
config: nodeDef.config ?? {},
|
|
2953
|
+
debug: sessionState.config.debug,
|
|
2954
|
+
eventBus: sessionState.eventBus,
|
|
2955
|
+
nodeOutputs: sessionState.nodeOutputs,
|
|
2956
|
+
workflowHistory: sessionState.workflowHistory,
|
|
2957
|
+
sessionComponent: this.sessionComponent,
|
|
2958
|
+
askUser
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
checkAndFinalize(sessionState) {
|
|
2962
|
+
const state = sessionState.scheduler.getState();
|
|
2963
|
+
if (state.pending.length === 0 && state.running.length === 0 && state.ready.length === 0) {
|
|
2964
|
+
if (state.failed.length > 0) {
|
|
2965
|
+
this.failWorkflow(sessionState, new Error(`Nodes failed: ${state.failed.join(", ")}`));
|
|
2966
|
+
} else {
|
|
2967
|
+
this.completeWorkflow(sessionState);
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
async completeWorkflow(sessionState) {
|
|
2972
|
+
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
2973
|
+
const sessionId = sessionState.sessionId;
|
|
2974
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
2975
|
+
const output = {};
|
|
2976
|
+
for (const [nodeId, nodeOutput] of sessionState.nodeOutputs) {
|
|
2977
|
+
output[nodeId] = nodeOutput;
|
|
2978
|
+
}
|
|
2979
|
+
if (this.sessionComponent) {
|
|
2980
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
2981
|
+
await this.sessionComponent.update(sessionId, {
|
|
2982
|
+
metadata: { ...metadata, status: "completed" }
|
|
2983
|
+
});
|
|
2984
|
+
}
|
|
2985
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.completed", runId, {
|
|
2986
|
+
result: output,
|
|
2987
|
+
duration_ms: durationMs
|
|
2988
|
+
}), true);
|
|
2989
|
+
sessionState.resolveCompleted({
|
|
2990
|
+
runId,
|
|
2991
|
+
status: "completed",
|
|
2992
|
+
output,
|
|
2993
|
+
durationMs
|
|
2994
|
+
});
|
|
2995
|
+
this.cleanupSession(sessionState);
|
|
2996
|
+
}
|
|
2997
|
+
async failWorkflow(sessionState, error) {
|
|
2998
|
+
const durationMs = Date.now() - sessionState.startedAt.getTime();
|
|
2999
|
+
const sessionId = sessionState.sessionId;
|
|
3000
|
+
const runId = this.getRunIdFromSessionId(sessionId);
|
|
3001
|
+
sessionState.executor.cancelAll();
|
|
3002
|
+
if (this.sessionComponent) {
|
|
3003
|
+
const metadata = await this.getSessionMetadata(sessionId);
|
|
3004
|
+
await this.sessionComponent.update(sessionId, {
|
|
3005
|
+
metadata: { ...metadata, status: "failed" }
|
|
3006
|
+
});
|
|
3007
|
+
}
|
|
3008
|
+
await sessionState.eventBus.publish(createWorkflowEvent("workflow.failed", runId, {
|
|
3009
|
+
error: { message: error.message, stack: error.stack },
|
|
3010
|
+
failed_at: new Date().toISOString()
|
|
3011
|
+
}), true);
|
|
3012
|
+
sessionState.resolveCompleted({
|
|
3013
|
+
runId,
|
|
3014
|
+
status: "failed",
|
|
3015
|
+
error: error.message,
|
|
3016
|
+
durationMs
|
|
3017
|
+
});
|
|
3018
|
+
this.cleanupSession(sessionState);
|
|
3019
|
+
}
|
|
3020
|
+
cleanupSession(sessionState) {
|
|
3021
|
+
sessionState.eventBus.clear();
|
|
3022
|
+
this.activeSessions.delete(sessionState.sessionId);
|
|
3023
|
+
}
|
|
3024
|
+
async waitForCompletion(sessionId, timeout) {
|
|
3025
|
+
const sessionState = this.activeSessions.get(sessionId);
|
|
3026
|
+
if (!sessionState) {
|
|
3027
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
3028
|
+
}
|
|
3029
|
+
const timeoutMs = timeout ?? 300000;
|
|
3030
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
3031
|
+
setTimeout(() => {
|
|
3032
|
+
reject(new Error(`Workflow execution timeout: ${timeoutMs}ms`));
|
|
3033
|
+
}, timeoutMs);
|
|
3034
|
+
});
|
|
3035
|
+
return Promise.race([
|
|
3036
|
+
sessionState.completedPromise,
|
|
3037
|
+
timeoutPromise
|
|
3038
|
+
]);
|
|
3039
|
+
}
|
|
3040
|
+
async getSessionMetadata(sessionId) {
|
|
3041
|
+
if (!this.sessionComponent) {
|
|
3042
|
+
return { type: "workflow", workflowId: "", workflowName: "", status: "running" };
|
|
3043
|
+
}
|
|
3044
|
+
const session = await this.sessionComponent.get(sessionId);
|
|
3045
|
+
return session?.metadata || { type: "workflow", workflowId: "", workflowName: "", status: "running" };
|
|
3046
|
+
}
|
|
3047
|
+
findDefinitionForWorkflow(workflowIdOrName) {
|
|
3048
|
+
if (!this.workflowRepository) {
|
|
3049
|
+
return null;
|
|
3050
|
+
}
|
|
3051
|
+
let workflow2 = this.workflowRepository.getById(workflowIdOrName);
|
|
3052
|
+
if (workflow2)
|
|
3053
|
+
return workflow2.definition;
|
|
3054
|
+
workflow2 = this.workflowRepository.getByName(workflowIdOrName);
|
|
3055
|
+
if (workflow2)
|
|
3056
|
+
return workflow2.definition;
|
|
3057
|
+
return null;
|
|
3058
|
+
}
|
|
3059
|
+
};
|
|
3060
|
+
__legacyDecorateClassTS([
|
|
3061
|
+
TracedAs("workflow.engine.createSession", { recordParams: true, recordResult: true, log: true })
|
|
3062
|
+
], WorkflowEngine.prototype, "createSession", null);
|
|
3063
|
+
__legacyDecorateClassTS([
|
|
3064
|
+
TracedAs("workflow.engine.run", { recordParams: true, recordResult: true, log: true })
|
|
3065
|
+
], WorkflowEngine.prototype, "run", null);
|
|
3066
|
+
__legacyDecorateClassTS([
|
|
3067
|
+
TracedAs("workflow.engine.runWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
3068
|
+
], WorkflowEngine.prototype, "runWorkflow", null);
|
|
3069
|
+
__legacyDecorateClassTS([
|
|
3070
|
+
TracedAs("workflow.engine.pause", { recordParams: true, recordResult: true, log: true })
|
|
3071
|
+
], WorkflowEngine.prototype, "pause", null);
|
|
3072
|
+
__legacyDecorateClassTS([
|
|
3073
|
+
TracedAs("workflow.engine.resume", { recordParams: true, recordResult: true, log: true })
|
|
3074
|
+
], WorkflowEngine.prototype, "resume", null);
|
|
3075
|
+
__legacyDecorateClassTS([
|
|
3076
|
+
TracedAs("workflow.engine.resumeFromDatabase", { recordParams: true, recordResult: true, log: true })
|
|
3077
|
+
], WorkflowEngine.prototype, "resumeFromDatabase", null);
|
|
3078
|
+
__legacyDecorateClassTS([
|
|
3079
|
+
TracedAs("workflow.engine.restoreRuntimeState", { recordParams: true, recordResult: true, log: true })
|
|
3080
|
+
], WorkflowEngine.prototype, "restoreRuntimeState", null);
|
|
3081
|
+
__legacyDecorateClassTS([
|
|
3082
|
+
TracedAs("workflow.engine.writeNodeResume", { recordParams: true, recordResult: true, log: true })
|
|
3083
|
+
], WorkflowEngine.prototype, "writeNodeResume", null);
|
|
3084
|
+
__legacyDecorateClassTS([
|
|
3085
|
+
TracedAs("workflow.engine.stop", { recordParams: true, recordResult: true, log: true })
|
|
3086
|
+
], WorkflowEngine.prototype, "stop", null);
|
|
3087
|
+
__legacyDecorateClassTS([
|
|
3088
|
+
TracedAs("workflow.engine.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true }),
|
|
3089
|
+
TracedAs("workflow.engine.writeNodeInterrupt", { recordParams: true, recordResult: true, log: true })
|
|
3090
|
+
], WorkflowEngine.prototype, "writeNodeInterrupt", null);
|
|
3091
|
+
__legacyDecorateClassTS([
|
|
3092
|
+
TracedAs("workflow.engine.scheduleAndExecute", { recordParams: true, recordResult: true, log: true }),
|
|
3093
|
+
TracedAs("workflow.engine.scheduleAndExecute", { recordParams: true, recordResult: true, log: true })
|
|
3094
|
+
], WorkflowEngine.prototype, "scheduleAndExecute", null);
|
|
3095
|
+
__legacyDecorateClassTS([
|
|
3096
|
+
TracedAs("workflow.engine.waitForNextNodeEvent", { recordParams: true, recordResult: true, log: true })
|
|
3097
|
+
], WorkflowEngine.prototype, "waitForNextNodeEvent", null);
|
|
3098
|
+
__legacyDecorateClassTS([
|
|
3099
|
+
TracedAs("workflow.engine.startNode", { recordParams: true, recordResult: true, log: true }),
|
|
3100
|
+
TracedAs("workflow.engine.startNode", { recordParams: true, recordResult: true, log: true })
|
|
3101
|
+
], WorkflowEngine.prototype, "startNode", null);
|
|
3102
|
+
__legacyDecorateClassTS([
|
|
3103
|
+
TracedAs("workflow.engine.writeNodeCall", { recordParams: true, recordResult: true, log: true }),
|
|
3104
|
+
TracedAs("workflow.engine.writeNodeCall", { recordParams: true, recordResult: true, log: true })
|
|
3105
|
+
], WorkflowEngine.prototype, "writeNodeCall", null);
|
|
3106
|
+
__legacyDecorateClassTS([
|
|
3107
|
+
TracedAs("workflow.engine.resumeNode", { recordParams: true, recordResult: true, log: true }),
|
|
3108
|
+
TracedAs("workflow.engine.resumeNode", { recordParams: true, recordResult: true, log: true })
|
|
3109
|
+
], WorkflowEngine.prototype, "resumeNode", null);
|
|
3110
|
+
__legacyDecorateClassTS([
|
|
3111
|
+
TracedAs("workflow.engine.checkAndFinalize", { recordParams: true, recordResult: true, log: true })
|
|
3112
|
+
], WorkflowEngine.prototype, "checkAndFinalize", null);
|
|
3113
|
+
__legacyDecorateClassTS([
|
|
3114
|
+
TracedAs("workflow.engine.completeWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
3115
|
+
], WorkflowEngine.prototype, "completeWorkflow", null);
|
|
3116
|
+
__legacyDecorateClassTS([
|
|
3117
|
+
TracedAs("workflow.engine.failWorkflow", { recordParams: true, recordResult: true, log: true })
|
|
3118
|
+
], WorkflowEngine.prototype, "failWorkflow", null);
|
|
3119
|
+
});
|
|
3120
|
+
|
|
3121
|
+
// src/env/workflow/engine/index.ts
|
|
3122
|
+
var exports_engine = {};
|
|
3123
|
+
__export(exports_engine, {
|
|
3124
|
+
WorkflowEngine: () => WorkflowEngine,
|
|
3125
|
+
Scheduler: () => Scheduler,
|
|
3126
|
+
NodeRegistry: () => NodeRegistry,
|
|
3127
|
+
Executor: () => Executor,
|
|
3128
|
+
EventBus: () => EventBus,
|
|
3129
|
+
DAGManager: () => DAGManager
|
|
3130
|
+
});
|
|
3131
|
+
var init_engine2 = __esm(() => {
|
|
3132
|
+
init_event_bus();
|
|
3133
|
+
init_dag_manager();
|
|
3134
|
+
init_scheduler();
|
|
3135
|
+
init_executor();
|
|
3136
|
+
init_engine();
|
|
3137
|
+
init_node_registry();
|
|
3138
|
+
});
|
|
3139
|
+
|
|
3140
|
+
export { Traced, TracedAs, TracedLightweight, wrapFunction, init_decorator, EventBus, DAGManager, Scheduler, Executor, NodeRegistry, WorkflowEngine, exports_engine, init_engine2 as init_engine };
|