@ai.ntellect/core 0.4.0 → 0.5.0
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/README.FR.md +624 -18
- package/README.md +127 -72
- package/agent/index.ts +57 -149
- package/agent/workflow/conditions.ts +16 -0
- package/agent/workflow/handlers/interpreter.handler.ts +48 -0
- package/agent/workflow/handlers/memory.handler.ts +106 -0
- package/agent/workflow/handlers/orchestrator.handler.ts +23 -0
- package/agent/workflow/handlers/queue.handler.ts +34 -0
- package/agent/workflow/handlers/scheduler.handler.ts +61 -0
- package/agent/workflow/index.ts +62 -0
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.js +3 -3
- package/{agent/tools → examples/actions}/get-rss.ts +8 -1
- package/examples/index.ts +10 -15
- package/index.html +42 -0
- package/llm/dynamic-condition/example.ts +36 -0
- package/llm/dynamic-condition/index.ts +108 -0
- package/llm/interpreter/context.ts +5 -12
- package/llm/interpreter/index.ts +20 -16
- package/llm/memory-manager/context.ts +4 -6
- package/llm/memory-manager/index.ts +32 -80
- package/llm/orchestrator/context.ts +5 -8
- package/llm/orchestrator/index.ts +62 -102
- package/llm/orchestrator/types.ts +2 -2
- package/package.json +3 -1
- package/script.js +167 -0
- package/services/{scheduler.ts → agenda.ts} +20 -35
- package/services/cache.ts +298 -0
- package/services/queue.ts +3 -3
- package/services/workflow.ts +491 -0
- package/t.ts +21 -129
- package/tsconfig.json +2 -1
- package/types.ts +91 -12
- package/utils/generate-object.ts +24 -12
- package/utils/inject-actions.ts +3 -3
- package/utils/state-manager.ts +25 -0
- package/bull.ts +0 -5
- package/services/redis-cache.ts +0 -128
- package/t.spec +0 -38
package/README.FR.md
CHANGED
@@ -14,11 +14,15 @@ Ce framework est conçu pour exécuter des workflows complexes à l'aide d'une o
|
|
14
14
|
## Table des matières
|
15
15
|
|
16
16
|
1. [Composants d'architecture](#composants-darchitecture)
|
17
|
-
|
17
|
+
|
18
|
+
- [Workflow](#workflow)
|
18
19
|
- [Orchestrateur](#orchestrateur)
|
19
20
|
- [Gestionnaire de file d'attente](#gestionnaire-de-file-dattente)
|
20
21
|
- [Interpréteur](#interpréteur)
|
21
22
|
- [Système de mémoire](#système-de-mémoire)
|
23
|
+
- [Listeners](#listeners)
|
24
|
+
- [Schedulers](#schedulers)
|
25
|
+
|
22
26
|
2. [Définir et exécuter des actions](#définir-et-exécuter-des-actions)
|
23
27
|
3. [Gestion de l'état et récursivité](#gestion-de-letat-et-recursivité)
|
24
28
|
4. [Installation et configuration](#installation-et-configuration)
|
@@ -29,32 +33,581 @@ Ce framework est conçu pour exécuter des workflows complexes à l'aide d'une o
|
|
29
33
|
|
30
34
|
## Composants d'architecture
|
31
35
|
|
32
|
-
|
36
|
+
import { configDotenv } from "dotenv";
|
37
|
+
import EventEmitter from "events";
|
38
|
+
import {
|
39
|
+
GraphDefinition,
|
40
|
+
mergeState,
|
41
|
+
Node,
|
42
|
+
Persistence,
|
43
|
+
RealTimeNotifier,
|
44
|
+
SharedState,
|
45
|
+
} from "../types";
|
46
|
+
import { WorkflowExecutor } from "./workflow-executor";
|
47
|
+
|
48
|
+
configDotenv();
|
49
|
+
|
50
|
+
/\*\*
|
51
|
+
|
52
|
+
- Represents a directed graph structure capable of executing nodes in sequence or parallel.
|
53
|
+
- The graph can handle state management, event emissions, and conditional execution paths.
|
54
|
+
-
|
55
|
+
- @template T - The type of data stored in the graph's context
|
56
|
+
_/
|
57
|
+
export class Workflow<T> {
|
58
|
+
/\*\* Stores global context data accessible to all nodes _/
|
59
|
+
public globalContext: Map<string, any>;
|
60
|
+
|
61
|
+
/\*_ Event emitter for handling graph-wide events _/
|
62
|
+
private eventEmitter: EventEmitter;
|
63
|
+
|
64
|
+
/\*_ Map of all nodes in the graph _/
|
65
|
+
public nodes: Map<string, Node<T>>;
|
66
|
+
|
67
|
+
/\*_ Set of nodes that have been executed _/
|
68
|
+
public executedNodes: Set<string>;
|
69
|
+
|
70
|
+
/\*_ Name identifier for the graph _/
|
71
|
+
public name: string;
|
72
|
+
|
73
|
+
/\*_ Optional persistence layer for saving graph state _/
|
74
|
+
private persistence: Persistence<T> | null;
|
75
|
+
|
76
|
+
/\*_ Optional notifier for real-time updates _/
|
77
|
+
private notifier: RealTimeNotifier | null;
|
78
|
+
|
79
|
+
/\*\*
|
80
|
+
|
81
|
+
- Creates a new Graph instance.
|
82
|
+
-
|
83
|
+
- @param {GraphDefinition<T>} [definition] - Initial graph structure and configuration
|
84
|
+
- @param {Object} [config] - Additional configuration options
|
85
|
+
- @param {boolean} [config.autoDetectCycles] - Whether to check for cycles during initialization
|
86
|
+
- @throws {Error} If cycles are detected when autoDetectCycles is true
|
87
|
+
\*/
|
88
|
+
constructor(
|
89
|
+
definition?: GraphDefinition<T>,
|
90
|
+
config?: { autoDetectCycles?: boolean }
|
91
|
+
) {
|
92
|
+
this.name = definition?.name || "anonymous";
|
93
|
+
this.eventEmitter = new EventEmitter();
|
94
|
+
this.globalContext = new Map();
|
95
|
+
this.nodes = new Map();
|
96
|
+
this.executedNodes = new Set();
|
97
|
+
this.persistence = null;
|
98
|
+
this.notifier = null;
|
99
|
+
|
100
|
+
|
101
|
+
if (definition) {
|
102
|
+
this.loadFromDefinition(definition);
|
103
|
+
}
|
104
|
+
|
105
|
+
if (config?.autoDetectCycles && this.checkForCycles()) {
|
106
|
+
throw new Error("Cycle detected in the graph");
|
107
|
+
}
|
108
|
+
|
109
|
+
}
|
110
|
+
|
111
|
+
/\*\*
|
112
|
+
|
113
|
+
- Adds a value to the global context.
|
114
|
+
- @param {string} key - The key to store the value under
|
115
|
+
- @param {any} value - The value to store
|
116
|
+
\*/
|
117
|
+
addToContext(key: string, value: any): void {
|
118
|
+
this.globalContext.set(key, value);
|
119
|
+
}
|
120
|
+
|
121
|
+
/\*\*
|
122
|
+
|
123
|
+
- Retrieves a value from the global context.
|
124
|
+
- @param {string} key - The key to retrieve
|
125
|
+
- @returns {any} The stored value, or undefined if not found
|
126
|
+
\*/
|
127
|
+
getContext(key: string): any {
|
128
|
+
return this.globalContext.get(key);
|
129
|
+
}
|
130
|
+
|
131
|
+
/\*\*
|
132
|
+
|
133
|
+
- Removes a value from the global context.
|
134
|
+
- @param {string} key - The key to remove
|
135
|
+
\*/
|
136
|
+
removeFromContext(key: string): void {
|
137
|
+
this.globalContext.delete(key);
|
138
|
+
}
|
139
|
+
|
140
|
+
/\*\*
|
141
|
+
|
142
|
+
- Sets the persistence layer for the graph.
|
143
|
+
- @param {Persistence<T>} persistence - The persistence implementation
|
144
|
+
\*/
|
145
|
+
setPersistence(persistence: Persistence<T>): void {
|
146
|
+
this.persistence = persistence;
|
147
|
+
}
|
148
|
+
|
149
|
+
/\*\*
|
150
|
+
|
151
|
+
- Sets the real-time notifier for the graph.
|
152
|
+
- @param {RealTimeNotifier} notifier - The notifier implementation
|
153
|
+
\*/
|
154
|
+
setNotifier(notifier: RealTimeNotifier): void {
|
155
|
+
this.notifier = notifier;
|
156
|
+
}
|
157
|
+
|
158
|
+
/\*\*
|
159
|
+
|
160
|
+
- Loads a graph structure from a definition object.
|
161
|
+
- @private
|
162
|
+
- @param {GraphDefinition<T>} definition - The graph definition
|
163
|
+
\*/
|
164
|
+
private loadFromDefinition(definition: GraphDefinition<T>): void {
|
165
|
+
Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
|
166
|
+
this.addNode(nodeConfig, {
|
167
|
+
condition: nodeConfig.condition,
|
168
|
+
next: nodeConfig.next,
|
169
|
+
});
|
170
|
+
});
|
171
|
+
}
|
172
|
+
|
173
|
+
/\*\*
|
174
|
+
|
175
|
+
- Recursively checks if a node is part of a cycle.
|
176
|
+
- @private
|
177
|
+
- @param {string} nodeName - The name of the node to check
|
178
|
+
- @param {Set<string>} visited - Set of visited nodes
|
179
|
+
- @param {Set<string>} recStack - Set of nodes in the current recursion stack
|
180
|
+
- @returns {boolean} True if a cycle is detected, false otherwise
|
181
|
+
\*/
|
182
|
+
private isCyclic(
|
183
|
+
nodeName: string,
|
184
|
+
visited: Set<string>,
|
185
|
+
recStack: Set<string>
|
186
|
+
): boolean {
|
187
|
+
if (!visited.has(nodeName)) {
|
188
|
+
visited.add(nodeName);
|
189
|
+
recStack.add(nodeName);
|
190
|
+
|
191
|
+
const currentNode = this.nodes.get(nodeName);
|
192
|
+
if (currentNode?.next) {
|
193
|
+
for (const nextNode of currentNode.next) {
|
194
|
+
if (
|
195
|
+
!visited.has(nextNode) &&
|
196
|
+
this.isCyclic(nextNode, visited, recStack)
|
197
|
+
) {
|
198
|
+
return true;
|
199
|
+
} else if (recStack.has(nextNode)) {
|
200
|
+
return true;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
}
|
206
|
+
recStack.delete(nodeName);
|
207
|
+
return false;
|
208
|
+
}
|
209
|
+
|
210
|
+
/\*\*
|
211
|
+
|
212
|
+
- Checks if the graph contains any cycles.
|
213
|
+
- @returns {boolean} True if cycles are detected, false otherwise
|
214
|
+
\*/
|
215
|
+
public checkForCycles(): boolean {
|
216
|
+
const visited = new Set<string>();
|
217
|
+
const recStack = new Set<string>();
|
218
|
+
|
219
|
+
|
220
|
+
for (const nodeName of this.nodes.keys()) {
|
221
|
+
if (this.isCyclic(nodeName, visited, recStack)) {
|
222
|
+
return true;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
return false;
|
226
|
+
|
227
|
+
}
|
228
|
+
|
229
|
+
/\*\*
|
230
|
+
|
231
|
+
- Adds a new node to the graph.
|
232
|
+
- @param {Node<T>} node - The node to add
|
233
|
+
- @param {Object} options - Node configuration options
|
234
|
+
- @param {Function} [options.condition] - Condition function for node execution
|
235
|
+
- @param {string[]} [options.next] - Array of next node names
|
236
|
+
- @param {string[]} [options.events] - Array of event names to listen for
|
237
|
+
\*/
|
238
|
+
addNode(
|
239
|
+
node: Node<T>,
|
240
|
+
{
|
241
|
+
condition,
|
242
|
+
next,
|
243
|
+
events,
|
244
|
+
}: {
|
245
|
+
condition?: (state: SharedState<T>) => boolean;
|
246
|
+
next?: string[];
|
247
|
+
events?: string[];
|
248
|
+
}
|
249
|
+
): void {
|
250
|
+
node.next = next;
|
251
|
+
node.condition = condition;
|
252
|
+
|
253
|
+
|
254
|
+
if (events) {
|
255
|
+
events.forEach((event) => {
|
256
|
+
this.eventEmitter.on(event, async (data) => {
|
257
|
+
console.log(`Event "${event}" received by node "${node.name}"`);
|
258
|
+
const state = data.state || {};
|
259
|
+
await this.execute(state, node.name);
|
260
|
+
});
|
261
|
+
});
|
262
|
+
}
|
263
|
+
|
264
|
+
this.nodes.set(node.name, node);
|
265
|
+
|
266
|
+
}
|
267
|
+
|
268
|
+
/\*\*
|
269
|
+
|
270
|
+
- Emits an event to the graph's event emitter.
|
271
|
+
- @param {string} eventName - Name of the event to emit
|
272
|
+
- @param {any} data - Data to pass with the event
|
273
|
+
\*/
|
274
|
+
public emit(eventName: string, data: any): void {
|
275
|
+
console.log(`Event "${eventName}" emitted with data:`, data);
|
276
|
+
this.eventEmitter.emit(eventName, data);
|
277
|
+
}
|
278
|
+
|
279
|
+
/\*\*
|
280
|
+
|
281
|
+
- Adds a subgraph as a node in the current graph.
|
282
|
+
- @param {Graph<T>} subGraph - The subgraph to add
|
283
|
+
- @param {string} entryNode - The entry node name in the subgraph
|
284
|
+
- @param {string} name - The name for the subgraph node
|
285
|
+
\*/
|
286
|
+
addSubGraph(subGraph: Workflow<T>, entryNode: string, name: string): void {
|
287
|
+
const subGraphNode: Node<T> = {
|
288
|
+
name,
|
289
|
+
execute: async (state) => {
|
290
|
+
console.log(`Executing subgraph: ${name}`);
|
291
|
+
await subGraph.execute(state, entryNode);
|
292
|
+
return state;
|
293
|
+
},
|
294
|
+
};
|
295
|
+
this.nodes.set(name, subGraphNode);
|
296
|
+
}
|
297
|
+
|
298
|
+
/\*\*
|
299
|
+
|
300
|
+
- Executes the graph starting from a specific node.
|
301
|
+
- @param {SharedState<T>} state - The initial state
|
302
|
+
- @param {string} startNode - The name of the starting node
|
303
|
+
- @param {Function} [onStream] - Callback for streaming state updates
|
304
|
+
- @param {Function} [onError] - Callback for handling errors
|
305
|
+
\*/
|
306
|
+
async execute(
|
307
|
+
state: SharedState<T>,
|
308
|
+
startNode: string,
|
309
|
+
onStream?: (state: SharedState<T>) => void,
|
310
|
+
onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
|
311
|
+
): Promise<void> {
|
312
|
+
let currentNodeName = startNode;
|
313
|
+
|
314
|
+
|
315
|
+
while (currentNodeName) {
|
316
|
+
this.executedNodes.add(currentNodeName);
|
317
|
+
|
318
|
+
const currentNode = this.nodes.get(currentNodeName);
|
319
|
+
if (!currentNode) throw new Error(`Node ${currentNodeName} not found.`);
|
320
|
+
|
321
|
+
if (currentNode.condition && !currentNode.condition(state)) {
|
322
|
+
console.log(
|
323
|
+
`Condition for node "${currentNodeName}" not met. Ending Graph.`
|
324
|
+
);
|
325
|
+
break;
|
326
|
+
}
|
327
|
+
|
328
|
+
try {
|
329
|
+
if (this.notifier) {
|
330
|
+
this.notifier.notify("nodeExecutionStarted", {
|
331
|
+
graph: this.name,
|
332
|
+
node: currentNodeName,
|
333
|
+
});
|
334
|
+
}
|
335
|
+
|
336
|
+
console.log(`Executing node: ${currentNodeName}`);
|
337
|
+
const newState = await currentNode.execute(state);
|
338
|
+
Object.assign(state, mergeState(state, newState));
|
339
|
+
|
340
|
+
if (onStream) onStream(state);
|
341
|
+
|
342
|
+
if (this.persistence) {
|
343
|
+
await this.persistence.saveState(this.name, state, currentNodeName);
|
344
|
+
}
|
345
|
+
|
346
|
+
if (this.notifier) {
|
347
|
+
await this.notifier.notify("nodeExecutionCompleted", {
|
348
|
+
graph: this.name,
|
349
|
+
node: currentNodeName,
|
350
|
+
state,
|
351
|
+
});
|
352
|
+
}
|
353
|
+
} catch (error) {
|
354
|
+
console.error(`Error in node ${currentNodeName}:`, error);
|
355
|
+
if (onError) onError(error as Error, currentNodeName, state);
|
356
|
+
if (this.notifier) {
|
357
|
+
this.notifier.notify("nodeExecutionFailed", {
|
358
|
+
graph: this.name,
|
359
|
+
node: currentNodeName,
|
360
|
+
state,
|
361
|
+
error,
|
362
|
+
});
|
363
|
+
}
|
364
|
+
break;
|
365
|
+
}
|
366
|
+
|
367
|
+
const nextNodes = currentNode.next || [];
|
368
|
+
if (nextNodes.length > 1) {
|
369
|
+
await Promise.all(
|
370
|
+
nextNodes.map((nextNode) =>
|
371
|
+
this.execute(state, nextNode, onStream, onError)
|
372
|
+
)
|
373
|
+
);
|
374
|
+
break;
|
375
|
+
} else {
|
376
|
+
currentNodeName = nextNodes[0] || "";
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
console.log(`Graph completed for node: ${startNode}`);
|
381
|
+
|
382
|
+
}
|
33
383
|
|
34
|
-
|
384
|
+
/\*\*
|
385
|
+
|
386
|
+
- Executes multiple nodes in parallel with a concurrency limit.
|
387
|
+
- @param {SharedState<T>} state - The shared state
|
388
|
+
- @param {string[]} nodeNames - Array of node names to execute
|
389
|
+
- @param {number} [concurrencyLimit=5] - Maximum number of concurrent executions
|
390
|
+
- @param {Function} [onStream] - Callback for streaming state updates
|
391
|
+
- @param {Function} [onError] - Callback for handling errors
|
392
|
+
\*/
|
393
|
+
async executeParallel(
|
394
|
+
state: SharedState<T>,
|
395
|
+
nodeNames: string[],
|
396
|
+
concurrencyLimit: number = 5,
|
397
|
+
onStream?: (state: SharedState<T>) => void,
|
398
|
+
onError?: (error: Error, nodeName: string, state: SharedState<T>) => void
|
399
|
+
): Promise<void> {
|
400
|
+
console.log(`Executing nodes in parallel: ${nodeNames.join(", ")}`);
|
401
|
+
|
402
|
+
|
403
|
+
const executeWithLimit = async (nodeName: string) => {
|
404
|
+
await this.execute(state, nodeName, onStream, onError);
|
405
|
+
};
|
35
406
|
|
36
|
-
|
407
|
+
const chunks = [];
|
408
|
+
for (let i = 0; i < nodeNames.length; i += concurrencyLimit) {
|
409
|
+
chunks.push(nodeNames.slice(i, i + concurrencyLimit));
|
410
|
+
}
|
37
411
|
|
38
|
-
|
39
|
-
|
40
|
-
|
412
|
+
for (const chunk of chunks) {
|
413
|
+
await Promise.all(chunk.map(executeWithLimit));
|
414
|
+
}
|
41
415
|
|
42
|
-
|
416
|
+
}
|
43
417
|
|
44
|
-
|
418
|
+
/\*\*
|
419
|
+
|
420
|
+
- Updates the graph structure with a new definition.
|
421
|
+
- @param {GraphDefinition<T>} definition - The new graph definition
|
422
|
+
\*/
|
423
|
+
updateGraph(definition: GraphDefinition<T>): void {
|
424
|
+
Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
|
425
|
+
if (this.nodes.has(nodeConfig.name)) {
|
426
|
+
const existingNode = this.nodes.get(nodeConfig.name)!;
|
427
|
+
existingNode.next = nodeConfig.next || existingNode.next;
|
428
|
+
existingNode.condition = nodeConfig.condition || existingNode.condition;
|
429
|
+
} else {
|
430
|
+
this.addNode(nodeConfig, {
|
431
|
+
condition: nodeConfig.condition,
|
432
|
+
next: nodeConfig.next,
|
433
|
+
});
|
434
|
+
}
|
435
|
+
});
|
436
|
+
}
|
437
|
+
|
438
|
+
/\*\*
|
439
|
+
|
440
|
+
- Replace the graph with a new definition.
|
441
|
+
- @param {GraphDefinition<T>} definition - The new graph definition
|
442
|
+
\*/
|
443
|
+
replaceGraph(definition: GraphDefinition<T>): void {
|
444
|
+
this.nodes.clear();
|
445
|
+
this.loadFromDefinition(definition);
|
446
|
+
}
|
447
|
+
|
448
|
+
/\*\*
|
449
|
+
|
450
|
+
- Generates a visual representation of the graph using Mermaid diagram syntax.
|
451
|
+
- The diagram shows all nodes and their connections, with special highlighting for:
|
452
|
+
- - Entry nodes (green)
|
453
|
+
- - Event nodes (yellow)
|
454
|
+
- - Conditional nodes (orange)
|
455
|
+
-
|
456
|
+
- @param {string} [title] - Optional title for the diagram
|
457
|
+
- @returns {string} Mermaid diagram syntax representing the graph
|
458
|
+
\*/
|
459
|
+
generateMermaidDiagram(title?: string): string {
|
460
|
+
const lines: string[] = ["graph TD"];
|
461
|
+
|
462
|
+
|
463
|
+
if (title) {
|
464
|
+
lines.push(` subgraph ${title}`);
|
465
|
+
}
|
466
|
+
|
467
|
+
// Add nodes with styling
|
468
|
+
this.nodes.forEach((node, nodeName) => {
|
469
|
+
const hasEvents = node.events && node.events.length > 0;
|
470
|
+
const hasCondition = !!node.condition;
|
471
|
+
|
472
|
+
// Style nodes based on their properties
|
473
|
+
let style = "";
|
474
|
+
if (hasEvents) {
|
475
|
+
style = "style " + nodeName + " fill:#FFD700,stroke:#DAA520"; // Yellow for event nodes
|
476
|
+
} else if (hasCondition) {
|
477
|
+
style = "style " + nodeName + " fill:#FFA500,stroke:#FF8C00"; // Orange for conditional nodes
|
478
|
+
}
|
479
|
+
|
480
|
+
// Add node definition
|
481
|
+
lines.push(` ${nodeName}[${nodeName}]`);
|
482
|
+
if (style) {
|
483
|
+
lines.push(` ${style}`);
|
484
|
+
}
|
485
|
+
});
|
486
|
+
|
487
|
+
// Add connections
|
488
|
+
this.nodes.forEach((node, nodeName) => {
|
489
|
+
if (node.next) {
|
490
|
+
node.next.forEach((nextNode) => {
|
491
|
+
let connectionStyle = "";
|
492
|
+
if (node.condition) {
|
493
|
+
connectionStyle = "---|condition|"; // Add label for conditional connections
|
494
|
+
} else {
|
495
|
+
connectionStyle = "-->"; // Normal connection
|
496
|
+
}
|
497
|
+
lines.push(` ${nodeName} ${connectionStyle} ${nextNode}`);
|
498
|
+
});
|
499
|
+
}
|
500
|
+
|
501
|
+
// Add event connections if any
|
502
|
+
if (node.events && node.events.length > 0) {
|
503
|
+
node.events.forEach((event) => {
|
504
|
+
const eventNodeId = `${event}_event`;
|
505
|
+
lines.push(` ${eventNodeId}((${event})):::event`);
|
506
|
+
lines.push(` ${eventNodeId} -.->|trigger| ${nodeName}`);
|
507
|
+
});
|
508
|
+
// Add style class for event nodes
|
509
|
+
lines.push(" classDef event fill:#FFD700,stroke:#DAA520");
|
510
|
+
}
|
511
|
+
});
|
512
|
+
|
513
|
+
if (title) {
|
514
|
+
lines.push(" end");
|
515
|
+
}
|
516
|
+
|
517
|
+
return lines.join("\n");
|
45
518
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
519
|
+
}
|
520
|
+
|
521
|
+
/\*\*
|
522
|
+
|
523
|
+
- Renders the graph visualization using Mermaid syntax.
|
524
|
+
- This method can be used to visualize the graph structure in supported environments.
|
525
|
+
-
|
526
|
+
- @param {string} [title] - Optional title for the visualization
|
527
|
+
\*/
|
528
|
+
visualize(title?: string): void {
|
529
|
+
const diagram = this.generateMermaidDiagram(title);
|
530
|
+
console.log(
|
531
|
+
"To visualize this graph, use a Mermaid-compatible renderer with this syntax:"
|
532
|
+
);
|
533
|
+
console.log("\n`mermaid");
|
534
|
+
console.log(diagram);
|
535
|
+
console.log("`\n");
|
536
|
+
}
|
537
|
+
|
538
|
+
exportGraphToJson<T>(graph: GraphDefinition<T>): string {
|
539
|
+
const result = {
|
540
|
+
graphName: graph.name,
|
541
|
+
entryNode: graph.entryNode,
|
542
|
+
nodes: Object.entries(graph.nodes).reduce((acc, [key, node]) => {
|
543
|
+
acc[key] = {
|
544
|
+
name: node.name,
|
545
|
+
description: node.description || "No description provided",
|
546
|
+
execute: node.execute.name,
|
547
|
+
condition: node.condition ? node.condition.toString() : "None",
|
548
|
+
next: node.next || [],
|
549
|
+
};
|
550
|
+
return acc;
|
551
|
+
}, {} as Record<string, any>),
|
552
|
+
};
|
553
|
+
return JSON.stringify(result, null, 2);
|
554
|
+
}
|
555
|
+
}
|
556
|
+
// Création des workflows
|
557
|
+
const workflowA = new Workflow({
|
558
|
+
name: "WorkflowA",
|
559
|
+
entryNode: "node1",
|
560
|
+
nodes: {
|
561
|
+
node1: {
|
562
|
+
name: "node1",
|
563
|
+
execute: async (state: any) => {
|
564
|
+
console.log("WorkflowA node1 executed", state);
|
565
|
+
return Promise.resolve({});
|
566
|
+
},
|
567
|
+
},
|
568
|
+
node2: {
|
569
|
+
name: "node2",
|
570
|
+
execute: async (state: any) => {
|
571
|
+
console.log("WorkflowA node2 executed", state);
|
572
|
+
return Promise.resolve({});
|
573
|
+
},
|
574
|
+
events: ["event1"],
|
575
|
+
},
|
576
|
+
},
|
577
|
+
});
|
578
|
+
|
579
|
+
const workflowB = new Workflow({
|
580
|
+
name: "WorkflowB",
|
581
|
+
entryNode: "node1",
|
582
|
+
nodes: {
|
583
|
+
node1: {
|
584
|
+
name: "node1",
|
585
|
+
execute: async (state: any) => {
|
586
|
+
console.log("WorkflowB node1 executed", state);
|
587
|
+
state.exampleData = "test2";
|
588
|
+
return Promise.resolve({});
|
589
|
+
},
|
590
|
+
},
|
591
|
+
},
|
592
|
+
});
|
50
593
|
|
51
|
-
|
594
|
+
// Initialisation du gestionnaire d'exécution
|
595
|
+
const executor = new WorkflowExecutor();
|
52
596
|
|
53
|
-
|
597
|
+
workflowA.emit("event1", { exampleData: "test" });
|
54
598
|
|
55
|
-
|
56
|
-
|
57
|
-
|
599
|
+
// Ajout des workflows
|
600
|
+
executor.addWorkflow("WorkflowA", workflowA);
|
601
|
+
executor.addWorkflow("WorkflowB", workflowB);
|
602
|
+
|
603
|
+
// Exécution des workflows en parallèle
|
604
|
+
executor.executeWorkflowsInParallel(
|
605
|
+
["WorkflowA", "WorkflowB"],
|
606
|
+
{
|
607
|
+
exampleData: "test",
|
608
|
+
},
|
609
|
+
2
|
610
|
+
);
|
58
611
|
|
59
612
|
---
|
60
613
|
|
@@ -138,6 +691,59 @@ L'architecture mémoire combine une mémoire à court terme et une mémoire à l
|
|
138
691
|
|
139
692
|
---
|
140
693
|
|
694
|
+
### Listeners
|
695
|
+
|
696
|
+
Les **listeners** permettent de se connecter à des événements externes via WebSocket. Ils écoutent les mises à jour en temps réel et déclenchent des actions ou des callbacks spécifiques en réponse aux événements.
|
697
|
+
|
698
|
+
**Caractéristiques principales :**
|
699
|
+
|
700
|
+
- Connexion à des WebSockets pour écouter les événements.
|
701
|
+
- Gestion des abonnements avec des messages personnalisés.
|
702
|
+
- Déclenchement de callbacks pour traiter les données reçues.
|
703
|
+
|
704
|
+
**Exemple d'utilisation :**
|
705
|
+
|
706
|
+
```typescript
|
707
|
+
agent.addListener(
|
708
|
+
"listener-id",
|
709
|
+
"wss://example.com/socket",
|
710
|
+
() => JSON.stringify({ action: "subscribe" }),
|
711
|
+
async (data) => {
|
712
|
+
console.log("Data reçue :", data);
|
713
|
+
}
|
714
|
+
);
|
715
|
+
```
|
716
|
+
|
717
|
+
---
|
718
|
+
|
719
|
+
### Schedulers
|
720
|
+
|
721
|
+
Les **schedulers** permettent de planifier des tâches ou actions pour une exécution ultérieure. Ils utilisent des expressions cron pour définir les intervalles de planification.
|
722
|
+
|
723
|
+
**Caractéristiques principales :**
|
724
|
+
|
725
|
+
- Planification basée sur des expressions cron.
|
726
|
+
- Support des tâches récurrentes et non récurrentes.
|
727
|
+
- Gestion et annulation des tâches planifiées.
|
728
|
+
|
729
|
+
**Exemple d'utilisation :**
|
730
|
+
|
731
|
+
```typescript
|
732
|
+
const scheduler = new TaskScheduler(agentRuntime, redisCache);
|
733
|
+
|
734
|
+
const taskId = await scheduler.scheduleRequest({
|
735
|
+
originalRequest: "Analyse de marché",
|
736
|
+
cronExpression: "0 9 * * *", // Tous les jours à 9h
|
737
|
+
});
|
738
|
+
|
739
|
+
console.log(`Tâche planifiée avec ID : ${taskId}`);
|
740
|
+
|
741
|
+
// Annuler la tâche si nécessaire
|
742
|
+
scheduler.cancelScheduledRequest(taskId);
|
743
|
+
```
|
744
|
+
|
745
|
+
---
|
746
|
+
|
141
747
|
## Définir et exécuter des actions
|
142
748
|
|
143
749
|
### Qu'est-ce qu'une action ?
|