@ai.ntellect/core 0.6.1 → 0.6.2
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/create-llm-to-select-multiple-graph copy.js +201 -0
- package/dist/create-llm-to-select-multiple-graph.js +142 -0
- package/dist/graph/controller.js +6 -6
- package/dist/graph/engine.js +198 -135
- package/dist/index copy.js +76 -0
- package/dist/utils/setup-graphs.js +28 -0
- package/dist/utils/stringifiy-zod-schema.js +41 -0
- package/graph/controller.ts +7 -9
- package/graph/engine.ts +0 -3
- package/index.ts +1 -1
- package/package.json +1 -1
- package/dist/test/graph/controller.test.js +0 -170
- package/dist/test/graph/engine.test.js +0 -465
- package/dist/test/memory/adapters/meilisearch.test.js +0 -250
- package/dist/test/memory/adapters/redis.test.js +0 -143
- package/dist/test/memory/base.test.js +0 -209
- package/dist/test/services/agenda.test.js +0 -230
- package/dist/test/services/queue.test.js +0 -258
- package/dist/utils/schema-generator.js +0 -46
- package/dist/utils/state-manager.js +0 -20
package/dist/graph/engine.js
CHANGED
@@ -13,24 +13,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
13
|
};
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
15
15
|
exports.GraphEngine = void 0;
|
16
|
-
const dotenv_1 = require("dotenv");
|
17
16
|
const events_1 = __importDefault(require("events"));
|
18
17
|
const zod_1 = require("zod");
|
19
|
-
(0, dotenv_1.configDotenv)();
|
20
18
|
/**
|
21
|
-
*
|
22
|
-
* The worflow can handle state management, event emissions, and conditional execution paths.
|
19
|
+
* Représente un workflow dirigé capable d’exécuter des noeuds en séquence ou en parallèle.
|
23
20
|
*
|
24
|
-
* @template T -
|
21
|
+
* @template T - Le type de données stockées dans le contexte du workflow
|
25
22
|
*/
|
26
23
|
class GraphEngine {
|
27
24
|
/**
|
28
|
-
*
|
25
|
+
* Crée une nouvelle instance de GraphEngine.
|
29
26
|
*
|
30
|
-
* @param {GraphDefinition<T>} [definition] -
|
31
|
-
* @param {
|
32
|
-
* @param {boolean} [config.autoDetectCycles] - Whether to check for cycles during initialization
|
33
|
-
* @throws {Error} If cycles are detected when autoDetectCycles is true
|
27
|
+
* @param {GraphDefinition<T>} [definition] - La définition initiale du workflow
|
28
|
+
* @param {GraphOptions<T>} [options] - Options de configuration
|
34
29
|
*/
|
35
30
|
constructor(definition, options) {
|
36
31
|
this.name = (definition === null || definition === void 0 ? void 0 : definition.name) || "anonymous";
|
@@ -41,74 +36,69 @@ class GraphEngine {
|
|
41
36
|
this.persistence = null;
|
42
37
|
this.notifier = null;
|
43
38
|
this.schema = options === null || options === void 0 ? void 0 : options.schema;
|
44
|
-
this.currentState = {
|
39
|
+
this.currentState = {};
|
45
40
|
if (definition) {
|
46
41
|
this.loadFromDefinition(definition);
|
47
42
|
}
|
48
43
|
if ((options === null || options === void 0 ? void 0 : options.autoDetectCycles) && this.checkForCycles()) {
|
49
|
-
throw new Error("Cycle
|
44
|
+
throw new Error("Cycle détecté dans le workflow");
|
50
45
|
}
|
51
46
|
if (options === null || options === void 0 ? void 0 : options.initialState) {
|
52
47
|
this.setState(options.initialState);
|
53
48
|
}
|
54
49
|
}
|
55
50
|
/**
|
56
|
-
*
|
57
|
-
* @param {string} key -
|
58
|
-
* @param {any} value -
|
51
|
+
* Ajoute un élément au contexte global.
|
52
|
+
* @param {string} key - La clé
|
53
|
+
* @param {any} value - La valeur
|
59
54
|
*/
|
60
55
|
addToContext(key, value) {
|
61
56
|
this.globalContext.set(key, value);
|
62
57
|
}
|
63
58
|
/**
|
64
|
-
*
|
65
|
-
* @param {string} key -
|
66
|
-
* @returns {any} The stored value, or undefined if not found
|
59
|
+
* Récupère un élément du contexte global.
|
60
|
+
* @param {string} key - La clé
|
67
61
|
*/
|
68
62
|
getContext(key) {
|
69
63
|
return this.globalContext.get(key);
|
70
64
|
}
|
71
65
|
/**
|
72
|
-
*
|
73
|
-
* @param {string} key -
|
66
|
+
* Supprime un élément du contexte global.
|
67
|
+
* @param {string} key - La clé
|
74
68
|
*/
|
75
69
|
removeFromContext(key) {
|
76
70
|
this.globalContext.delete(key);
|
77
71
|
}
|
78
72
|
/**
|
79
|
-
*
|
80
|
-
* @param {Persistence<T>} persistence
|
73
|
+
* Définit la couche de persistance.
|
74
|
+
* @param {Persistence<T>} persistence
|
81
75
|
*/
|
82
76
|
setPersistence(persistence) {
|
83
77
|
this.persistence = persistence;
|
84
78
|
}
|
85
79
|
/**
|
86
|
-
*
|
87
|
-
* @param {RealTimeNotifier} notifier
|
80
|
+
* Définit le notifier en temps réel.
|
81
|
+
* @param {RealTimeNotifier} notifier
|
88
82
|
*/
|
89
83
|
setNotifier(notifier) {
|
90
84
|
this.notifier = notifier;
|
91
85
|
}
|
92
86
|
/**
|
93
|
-
*
|
87
|
+
* Charge un workflow à partir d'une définition.
|
94
88
|
* @private
|
95
|
-
* @param {GraphDefinition<T>} definition
|
89
|
+
* @param {GraphDefinition<T>} definition
|
96
90
|
*/
|
97
91
|
loadFromDefinition(definition) {
|
98
92
|
Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
|
99
|
-
this.addNode(nodeConfig
|
100
|
-
condition: nodeConfig.condition,
|
101
|
-
relationships: nodeConfig.relationships,
|
102
|
-
});
|
93
|
+
this.addNode(nodeConfig);
|
103
94
|
});
|
104
95
|
}
|
105
96
|
/**
|
106
|
-
*
|
107
|
-
* @
|
108
|
-
* @param {string}
|
109
|
-
* @param {Set<string>}
|
110
|
-
* @
|
111
|
-
* @returns {boolean} True if a cycle is detected, false otherwise
|
97
|
+
* Vérifie récursivement s’il existe un cycle dans le workflow.
|
98
|
+
* @param {string} nodeName
|
99
|
+
* @param {Set<string>} visited
|
100
|
+
* @param {Set<string>} recStack
|
101
|
+
* @returns {boolean}
|
112
102
|
*/
|
113
103
|
isCyclic(nodeName, visited, recStack) {
|
114
104
|
if (!visited.has(nodeName)) {
|
@@ -132,8 +122,8 @@ class GraphEngine {
|
|
132
122
|
return false;
|
133
123
|
}
|
134
124
|
/**
|
135
|
-
*
|
136
|
-
* @returns {boolean}
|
125
|
+
* Vérifie si le workflow contient des cycles.
|
126
|
+
* @returns {boolean}
|
137
127
|
*/
|
138
128
|
checkForCycles() {
|
139
129
|
const visited = new Set();
|
@@ -146,18 +136,18 @@ class GraphEngine {
|
|
146
136
|
return false;
|
147
137
|
}
|
148
138
|
/**
|
149
|
-
*
|
150
|
-
* @param {Node<T>} node
|
151
|
-
* @param {Object} options - Node configuration options
|
152
|
-
* @param {Function} [options.condition] - Condition function for node execution
|
153
|
-
* @param {string[]} [options.relations] - Array of relations node names
|
154
|
-
* @param {string[]} [options.events] - Array of event names to listen for
|
139
|
+
* Ajoute un nouveau nœud au workflow.
|
140
|
+
* @param {Node<T>} node
|
155
141
|
*/
|
156
|
-
addNode(node
|
157
|
-
node.relationships
|
158
|
-
|
159
|
-
|
160
|
-
|
142
|
+
addNode(node) {
|
143
|
+
if (node.relationships) {
|
144
|
+
node.relationships.forEach((relationship) => {
|
145
|
+
var _a, _b;
|
146
|
+
(_b = (_a = this.nodes.get(relationship.name)) === null || _a === void 0 ? void 0 : _a.relationships) === null || _b === void 0 ? void 0 : _b.push(relationship);
|
147
|
+
});
|
148
|
+
}
|
149
|
+
if (node.events) {
|
150
|
+
node.events.forEach((event) => {
|
161
151
|
this.eventEmitter.on(event, (data) => __awaiter(this, void 0, void 0, function* () {
|
162
152
|
const state = data.state || {};
|
163
153
|
yield this.execute(state, node.name);
|
@@ -167,18 +157,18 @@ class GraphEngine {
|
|
167
157
|
this.nodes.set(node.name, node);
|
168
158
|
}
|
169
159
|
/**
|
170
|
-
*
|
171
|
-
* @param {string} eventName
|
172
|
-
* @param {any} data
|
160
|
+
* Émet un événement sur l'event emitter du workflow.
|
161
|
+
* @param {string} eventName
|
162
|
+
* @param {any} data
|
173
163
|
*/
|
174
164
|
emit(eventName, data) {
|
175
165
|
this.eventEmitter.emit(eventName, data);
|
176
166
|
}
|
177
167
|
/**
|
178
|
-
*
|
179
|
-
* @param {
|
180
|
-
* @param {string} entryNode -
|
181
|
-
* @param {string} name -
|
168
|
+
* Ajoute un sous-graph (GraphEngine) comme un nœud dans le workflow courant.
|
169
|
+
* @param {GraphEngine<T>} subGraph
|
170
|
+
* @param {string} entryNode - Le nom du nœud de démarrage dans le sous-graph
|
171
|
+
* @param {string} name - Le nom symbolique à donner au sous-graph
|
182
172
|
*/
|
183
173
|
addSubGraph(subGraph, entryNode, name) {
|
184
174
|
const subGraphNode = {
|
@@ -191,22 +181,23 @@ class GraphEngine {
|
|
191
181
|
this.nodes.set(name, subGraphNode);
|
192
182
|
}
|
193
183
|
/**
|
194
|
-
*
|
195
|
-
* @param {SharedState<T>} state
|
196
|
-
* @param {string} startNode
|
197
|
-
* @param {
|
198
|
-
* @param {
|
184
|
+
* Exécute le workflow à partir d’un nœud donné.
|
185
|
+
* @param {SharedState<T>} state
|
186
|
+
* @param {string} startNode
|
187
|
+
* @param {(state: SharedState<T>) => void} [onStream] - Callback sur l’évolution de l’état
|
188
|
+
* @param {(error: Error, nodeName: string, state: SharedState<T>) => void} [onError] - Callback sur erreur
|
199
189
|
*/
|
200
190
|
execute(state, startNode, onStream, onError) {
|
201
191
|
return __awaiter(this, void 0, void 0, function* () {
|
202
192
|
var _a, _b;
|
203
193
|
try {
|
194
|
+
// Valide l'état initial via le schéma global (si défini)
|
204
195
|
if (this.schema) {
|
205
196
|
try {
|
206
|
-
this.schema.parse(state
|
197
|
+
this.schema.parse(state);
|
207
198
|
}
|
208
199
|
catch (error) {
|
209
|
-
const validationError = new Error(
|
200
|
+
const validationError = new Error(`Échec de la validation de l'état initial: ${error instanceof Error ? error.message : error}`);
|
210
201
|
if (onError)
|
211
202
|
onError(validationError, startNode, state);
|
212
203
|
throw validationError;
|
@@ -217,13 +208,16 @@ class GraphEngine {
|
|
217
208
|
while (currentNodeName) {
|
218
209
|
this.executedNodes.add(currentNodeName);
|
219
210
|
const currentNode = this.nodes.get(currentNodeName);
|
220
|
-
if (!currentNode)
|
221
|
-
throw new Error(`
|
211
|
+
if (!currentNode) {
|
212
|
+
throw new Error(`Nœud ${currentNodeName} introuvable.`);
|
213
|
+
}
|
214
|
+
// Vérification de condition (si présente)
|
222
215
|
if (currentNode.condition &&
|
223
216
|
!currentNode.condition(this.currentState)) {
|
224
217
|
break;
|
225
218
|
}
|
226
219
|
try {
|
220
|
+
// Notifier : début d'exécution du nœud
|
227
221
|
if (this.notifier) {
|
228
222
|
this.notifier.notify("nodeExecutionStarted", {
|
229
223
|
workflow: this.name,
|
@@ -235,11 +229,13 @@ class GraphEngine {
|
|
235
229
|
if (newState) {
|
236
230
|
this.setState(newState);
|
237
231
|
if (onStream)
|
238
|
-
onStream(this
|
232
|
+
onStream(this);
|
239
233
|
}
|
234
|
+
// Sauvegarde via la persistence (optionnel)
|
240
235
|
if (this.persistence) {
|
241
236
|
yield this.persistence.saveState(this.name, this.currentState, currentNodeName);
|
242
237
|
}
|
238
|
+
// Notifier : fin d'exécution du nœud
|
243
239
|
if (this.notifier) {
|
244
240
|
yield this.notifier.notify("nodeExecutionCompleted", {
|
245
241
|
workflow: this.name,
|
@@ -249,8 +245,9 @@ class GraphEngine {
|
|
249
245
|
}
|
250
246
|
}
|
251
247
|
catch (error) {
|
252
|
-
if (onError)
|
248
|
+
if (onError) {
|
253
249
|
onError(error, currentNodeName, this.currentState);
|
250
|
+
}
|
254
251
|
if (this.notifier) {
|
255
252
|
this.notifier.notify("nodeExecutionFailed", {
|
256
253
|
workflow: this.name,
|
@@ -261,12 +258,16 @@ class GraphEngine {
|
|
261
258
|
}
|
262
259
|
break;
|
263
260
|
}
|
261
|
+
// Gestion des relations (branchements)
|
264
262
|
const relationsNodes = currentNode.relationships || [];
|
265
263
|
if (relationsNodes.length > 1) {
|
264
|
+
// Exécution parallèle des branches
|
266
265
|
yield Promise.all(relationsNodes.map((relation) => this.execute(this.currentState, relation.name, onStream, onError)));
|
266
|
+
// Après exécution en parallèle, on arrête la boucle
|
267
267
|
break;
|
268
268
|
}
|
269
269
|
else {
|
270
|
+
// Cas normal : un seul chemin
|
270
271
|
currentNodeName = ((_b = relationsNodes[0]) === null || _b === void 0 ? void 0 : _b.name) || "";
|
271
272
|
}
|
272
273
|
}
|
@@ -281,12 +282,10 @@ class GraphEngine {
|
|
281
282
|
});
|
282
283
|
}
|
283
284
|
/**
|
284
|
-
*
|
285
|
-
* @param {SharedState<T>} state
|
286
|
-
* @param {string[]} nodeNames
|
287
|
-
* @param {number} [concurrencyLimit=5]
|
288
|
-
* @param {Function} [onStream] - Callback for streaming state updates
|
289
|
-
* @param {Function} [onError] - Callback for handling errors
|
285
|
+
* Exécute plusieurs nœuds en parallèle au sein du même workflow, avec une limite de concurrence.
|
286
|
+
* @param {SharedState<T>} state
|
287
|
+
* @param {string[]} nodeNames
|
288
|
+
* @param {number} [concurrencyLimit=5]
|
290
289
|
*/
|
291
290
|
executeParallel(state_1, nodeNames_1) {
|
292
291
|
return __awaiter(this, arguments, void 0, function* (state, nodeNames, concurrencyLimit = 5, onStream, onError) {
|
@@ -303,8 +302,8 @@ class GraphEngine {
|
|
303
302
|
});
|
304
303
|
}
|
305
304
|
/**
|
306
|
-
*
|
307
|
-
* @param {GraphDefinition<T>} definition
|
305
|
+
* Met à jour le workflow avec une nouvelle définition (mise à jour des nœuds existants ou ajout de nouveaux).
|
306
|
+
* @param {GraphDefinition<T>} definition
|
308
307
|
*/
|
309
308
|
updateGraph(definition) {
|
310
309
|
Object.entries(definition.nodes).forEach(([_, nodeConfig]) => {
|
@@ -313,78 +312,69 @@ class GraphEngine {
|
|
313
312
|
existingNode.relationships =
|
314
313
|
nodeConfig.relationships || existingNode.relationships;
|
315
314
|
existingNode.condition = nodeConfig.condition || existingNode.condition;
|
315
|
+
existingNode.events = nodeConfig.events || existingNode.events;
|
316
316
|
}
|
317
317
|
else {
|
318
|
-
this.addNode(nodeConfig
|
319
|
-
condition: nodeConfig.condition,
|
320
|
-
relationships: nodeConfig.relationships,
|
321
|
-
});
|
318
|
+
this.addNode(nodeConfig);
|
322
319
|
}
|
323
320
|
});
|
324
321
|
}
|
325
322
|
/**
|
326
|
-
*
|
327
|
-
* @param {GraphDefinition<T>} definition
|
323
|
+
* Remplace complètement le workflow par une nouvelle définition.
|
324
|
+
* @param {GraphDefinition<T>} definition
|
328
325
|
*/
|
329
326
|
replaceGraph(definition) {
|
330
327
|
this.nodes.clear();
|
331
328
|
this.loadFromDefinition(definition);
|
332
329
|
}
|
333
330
|
/**
|
334
|
-
*
|
335
|
-
*
|
336
|
-
*
|
337
|
-
* - Event nodes (yellow)
|
338
|
-
* - Conditional nodes (orange)
|
339
|
-
*
|
340
|
-
* @param {string} [title] - Optional title for the diagram
|
341
|
-
* @returns {string} Mermaid diagram syntax representing the worflow
|
331
|
+
* Génère un diagramme Mermaid pour visualiser le workflow.
|
332
|
+
* @param {string} [title]
|
333
|
+
* @returns {string}
|
342
334
|
*/
|
343
335
|
generateMermaidDiagram(title) {
|
344
336
|
const lines = ["flowchart TD"];
|
345
337
|
if (title) {
|
346
338
|
lines.push(` subgraph ${title}`);
|
347
339
|
}
|
348
|
-
//
|
340
|
+
// Ajout des nœuds
|
349
341
|
this.nodes.forEach((node, nodeName) => {
|
350
342
|
const hasEvents = node.events && node.events.length > 0;
|
351
343
|
const hasCondition = !!node.condition;
|
352
|
-
// Style
|
344
|
+
// Style selon les propriétés
|
353
345
|
let style = "";
|
354
346
|
if (hasEvents) {
|
355
|
-
style = "style " + nodeName + " fill:#FFD700,stroke:#DAA520"; //
|
347
|
+
style = "style " + nodeName + " fill:#FFD700,stroke:#DAA520"; // Jaune pour event
|
356
348
|
}
|
357
349
|
else if (hasCondition) {
|
358
|
-
style = "style " + nodeName + " fill:#FFA500,stroke:#FF8C00"; // Orange
|
350
|
+
style = "style " + nodeName + " fill:#FFA500,stroke:#FF8C00"; // Orange pour condition
|
359
351
|
}
|
360
|
-
// Add node definition
|
361
352
|
lines.push(` ${nodeName}[${nodeName}]`);
|
362
353
|
if (style) {
|
363
354
|
lines.push(` ${style}`);
|
364
355
|
}
|
365
356
|
});
|
366
|
-
//
|
357
|
+
// Ajout des connexions
|
367
358
|
this.nodes.forEach((node, nodeName) => {
|
368
359
|
if (node.relationships) {
|
369
360
|
node.relationships.forEach((relationsNode) => {
|
370
361
|
let connectionStyle = "";
|
371
362
|
if (node.condition) {
|
372
|
-
connectionStyle = "---|condition|";
|
363
|
+
connectionStyle = "---|condition|";
|
373
364
|
}
|
374
365
|
else {
|
375
|
-
connectionStyle = "-->";
|
366
|
+
connectionStyle = "-->";
|
376
367
|
}
|
377
368
|
lines.push(` ${nodeName} ${connectionStyle} ${relationsNode}`);
|
378
369
|
});
|
379
370
|
}
|
380
|
-
//
|
371
|
+
// Gestion des events
|
381
372
|
if (node.events && node.events.length > 0) {
|
382
373
|
node.events.forEach((event) => {
|
383
374
|
const eventNodeId = `${event}_event`;
|
384
375
|
lines.push(` ${eventNodeId}((${event})):::event`);
|
385
376
|
lines.push(` ${eventNodeId} -.->|trigger| ${nodeName}`);
|
386
377
|
});
|
387
|
-
// Add style class for event nodes
|
388
378
|
lines.push(" classDef event fill:#FFD700,stroke:#DAA520");
|
389
379
|
}
|
390
380
|
});
|
@@ -394,23 +384,26 @@ class GraphEngine {
|
|
394
384
|
return lines.join("\n");
|
395
385
|
}
|
396
386
|
/**
|
397
|
-
*
|
398
|
-
*
|
399
|
-
*
|
400
|
-
* @param {string} [title] - Optional title for the visualization
|
387
|
+
* Affiche le diagramme Mermaid dans la console.
|
388
|
+
* @param {string} [title]
|
401
389
|
*/
|
402
390
|
visualize(title) {
|
403
391
|
const diagram = this.generateMermaidDiagram(title);
|
404
|
-
console.log("
|
392
|
+
console.log("Pour visualiser ce workflow, utilisez un rendu compatible Mermaid avec la syntaxe suivante :");
|
405
393
|
console.log("\n```mermaid");
|
406
394
|
console.log(diagram);
|
407
395
|
console.log("```\n");
|
408
396
|
}
|
409
|
-
|
397
|
+
/**
|
398
|
+
* Exporte la définition du workflow au format JSON (pour debug ou documentation).
|
399
|
+
* @param {GraphDefinition<T>} workflow
|
400
|
+
* @returns {string} JSON string
|
401
|
+
*/
|
402
|
+
exportGraphToJson(workflow) {
|
410
403
|
const result = {
|
411
|
-
|
412
|
-
entryNode:
|
413
|
-
nodes: Object.entries(
|
404
|
+
workflowName: workflow.name,
|
405
|
+
entryNode: workflow.entryNode,
|
406
|
+
nodes: Object.entries(workflow.nodes).reduce((acc, [key, node]) => {
|
414
407
|
acc[key] = {
|
415
408
|
name: node.name,
|
416
409
|
description: node.description || "No description provided",
|
@@ -424,15 +417,14 @@ class GraphEngine {
|
|
424
417
|
return JSON.stringify(result, null, 2);
|
425
418
|
}
|
426
419
|
/**
|
427
|
-
*
|
428
|
-
*
|
429
|
-
*
|
430
|
-
* @returns {string} A formatted string describing the workflow schema
|
420
|
+
* Génère une représentation textuelle (console) du schéma du workflow.
|
421
|
+
* @returns {string}
|
431
422
|
*/
|
432
423
|
visualizeSchema() {
|
433
424
|
const output = [];
|
434
425
|
output.push(`📋 Graph: ${this.name}`);
|
435
426
|
output.push("=".repeat(50));
|
427
|
+
// Schéma global
|
436
428
|
if (this.schema) {
|
437
429
|
output.push("🔷 Global Schema:");
|
438
430
|
output.push("-".repeat(30));
|
@@ -446,20 +438,25 @@ class GraphEngine {
|
|
446
438
|
}
|
447
439
|
output.push("");
|
448
440
|
}
|
441
|
+
// Détails des nœuds
|
449
442
|
output.push("🔷 Nodes:");
|
450
443
|
output.push("-".repeat(30));
|
451
444
|
this.nodes.forEach((node, nodeName) => {
|
452
445
|
output.push(`\n📍 Node: ${nodeName}`);
|
453
446
|
output.push(`Description: ${node.description || "No description provided"}`);
|
454
447
|
if (node.relationships && node.relationships.length > 0) {
|
455
|
-
|
448
|
+
const rels = node.relationships.map((r) => r.name).join(", ");
|
449
|
+
output.push(`Next nodes: ${rels}`);
|
456
450
|
}
|
457
451
|
output.push("");
|
458
452
|
});
|
459
453
|
return output.join("\n");
|
460
454
|
}
|
461
455
|
/**
|
462
|
-
*
|
456
|
+
* Décrit récursivement un type Zod pour l'affichage.
|
457
|
+
* @param {z.ZodType} type
|
458
|
+
* @param {number} indent
|
459
|
+
* @returns {string}
|
463
460
|
*/
|
464
461
|
describeZodType(type, indent = 0) {
|
465
462
|
const padding = " ".repeat(indent);
|
@@ -505,29 +502,29 @@ class GraphEngine {
|
|
505
502
|
return type.constructor.name.replace("Zod", "") || "unknown";
|
506
503
|
}
|
507
504
|
/**
|
508
|
-
*
|
509
|
-
* @param {SharedState<T>} state
|
510
|
-
* @param {Partial<T>} updates
|
511
|
-
* @returns {SharedState<T>}
|
505
|
+
* Met à jour le contexte du workflow pour un nœud, en renvoyant un nouvel état.
|
506
|
+
* @param {SharedState<T>} state
|
507
|
+
* @param {Partial<T>} updates
|
508
|
+
* @returns {SharedState<T>}
|
512
509
|
*/
|
513
510
|
updateNodeState(state, updates) {
|
514
|
-
return Object.assign(Object.assign({}, state),
|
511
|
+
return Object.assign(Object.assign({}, state), updates);
|
515
512
|
}
|
516
513
|
/**
|
517
|
-
*
|
518
|
-
* @returns {SharedState<T>}
|
514
|
+
* Récupère l'état courant du workflow.
|
515
|
+
* @returns {SharedState<T>}
|
519
516
|
*/
|
520
517
|
getState() {
|
521
518
|
return this.currentState;
|
522
519
|
}
|
523
520
|
/**
|
524
|
-
*
|
525
|
-
* @param {Partial<SharedState<T>>} state
|
521
|
+
* Définit le nouvel état courant du workflow et met à jour le contexte global.
|
522
|
+
* @param {Partial<SharedState<T>>} state
|
526
523
|
*/
|
527
524
|
setState(state) {
|
528
525
|
this.currentState = this.mergeStates(this.currentState, state);
|
529
|
-
if (state
|
530
|
-
Object.entries(state
|
526
|
+
if (state) {
|
527
|
+
Object.entries(state).forEach(([key, value]) => {
|
531
528
|
this.globalContext.set(key, value);
|
532
529
|
});
|
533
530
|
}
|
@@ -535,29 +532,95 @@ class GraphEngine {
|
|
535
532
|
if (currentNode) {
|
536
533
|
const node = this.nodes.get(currentNode);
|
537
534
|
if (node) {
|
538
|
-
node.state = Object.assign(Object.assign({}, (node.state || {})), (state
|
535
|
+
node.state = Object.assign(Object.assign({}, (node.state || {})), (state || {}));
|
539
536
|
}
|
540
537
|
}
|
541
538
|
}
|
542
539
|
/**
|
543
|
-
*
|
544
|
-
* @param {SharedState<T>} currentState
|
545
|
-
* @param {Partial<SharedState<T>>} newState
|
546
|
-
* @returns {SharedState<T>}
|
540
|
+
* Fusionne deux états.
|
541
|
+
* @param {SharedState<T>} currentState
|
542
|
+
* @param {Partial<SharedState<T>>} newState
|
543
|
+
* @returns {SharedState<T>}
|
547
544
|
*/
|
548
545
|
mergeStates(currentState, newState) {
|
549
|
-
return Object.assign(Object.assign({}, currentState),
|
546
|
+
return Object.assign(Object.assign({}, currentState), (newState || {}));
|
550
547
|
}
|
551
548
|
/**
|
552
|
-
*
|
553
|
-
* @param {Partial<
|
554
|
-
* @returns {SharedState<T>}
|
549
|
+
* Met à jour l'état courant et le renvoie.
|
550
|
+
* @param {Partial<T>} updates
|
551
|
+
* @returns {SharedState<T>}
|
555
552
|
*/
|
556
553
|
updateState(updates) {
|
557
554
|
const currentState = this.getState();
|
558
|
-
const newState = Object.assign(Object.assign({}, currentState),
|
555
|
+
const newState = Object.assign(Object.assign({}, currentState), updates);
|
559
556
|
this.setState(newState);
|
560
557
|
return newState;
|
561
558
|
}
|
559
|
+
/* =============================================
|
560
|
+
= MÉTHODES STATIQUES POUR PLUSIEURS GRAPHES =
|
561
|
+
============================================= */
|
562
|
+
/**
|
563
|
+
* Exécute plusieurs GraphEngine en **séquence** (l'un après l'autre).
|
564
|
+
* @param graphs Liste des graphes à exécuter
|
565
|
+
* @param startNodes Noms des nœuds de départ correspondants
|
566
|
+
* @param initialStates États initiaux correspondants
|
567
|
+
* @param onStream Callback d'avancement
|
568
|
+
* @param onError Callback d'erreur
|
569
|
+
* @returns Tableau des états finaux de chaque graphe
|
570
|
+
*/
|
571
|
+
static executeGraphsInSequence(graphs, startNodes, initialStates, onStream, onError) {
|
572
|
+
return __awaiter(this, void 0, void 0, function* () {
|
573
|
+
const finalStates = [];
|
574
|
+
for (let i = 0; i < graphs.length; i++) {
|
575
|
+
const graph = graphs[i];
|
576
|
+
const startNode = startNodes[i];
|
577
|
+
const initialState = initialStates[i];
|
578
|
+
const result = yield graph.execute(initialState, startNode, onStream, onError);
|
579
|
+
finalStates.push(result);
|
580
|
+
}
|
581
|
+
return finalStates;
|
582
|
+
});
|
583
|
+
}
|
584
|
+
/**
|
585
|
+
* Exécute plusieurs GraphEngine en **parallèle** (sans limite de concurrence).
|
586
|
+
* @param graphs Liste des graphes
|
587
|
+
* @param startNodes Noms des nœuds de départ
|
588
|
+
* @param initialStates États initiaux
|
589
|
+
* @param onStream Callback d'avancement
|
590
|
+
* @param onError Callback d'erreur
|
591
|
+
* @returns Tableau des états finaux de chaque graphe
|
592
|
+
*/
|
593
|
+
static executeGraphsInParallel(graphs, startNodes, initialStates, onStream, onError) {
|
594
|
+
return __awaiter(this, void 0, void 0, function* () {
|
595
|
+
const promises = graphs.map((graph, index) => graph.execute(initialStates[index], startNodes[index], onStream, onError));
|
596
|
+
return Promise.all(promises);
|
597
|
+
});
|
598
|
+
}
|
599
|
+
/**
|
600
|
+
* Exécute plusieurs GraphEngine en parallèle **avec une limite de concurrence**.
|
601
|
+
* @param graphs Liste des graphes
|
602
|
+
* @param startNodes Noms des nœuds de départ
|
603
|
+
* @param initialStates États initiaux
|
604
|
+
* @param concurrencyLimit Limite de concurrence
|
605
|
+
* @param onStream Callback d'avancement
|
606
|
+
* @param onError Callback d'erreur
|
607
|
+
* @returns Tableau des états finaux de chaque graphe
|
608
|
+
*/
|
609
|
+
static executeGraphsWithConcurrencyLimit(graphs, startNodes, initialStates, concurrencyLimit, onStream, onError) {
|
610
|
+
return __awaiter(this, void 0, void 0, function* () {
|
611
|
+
const results = [];
|
612
|
+
for (let i = 0; i < graphs.length; i += concurrencyLimit) {
|
613
|
+
const chunkGraphs = graphs.slice(i, i + concurrencyLimit);
|
614
|
+
const chunkStartNodes = startNodes.slice(i, i + concurrencyLimit);
|
615
|
+
const chunkInitialStates = initialStates.slice(i, i + concurrencyLimit);
|
616
|
+
const chunkPromises = chunkGraphs.map((graph, index) => {
|
617
|
+
return graph.execute(chunkInitialStates[index], chunkStartNodes[index], onStream, onError);
|
618
|
+
});
|
619
|
+
const chunkResults = yield Promise.all(chunkPromises);
|
620
|
+
results.push(...chunkResults);
|
621
|
+
}
|
622
|
+
return results;
|
623
|
+
});
|
624
|
+
}
|
562
625
|
}
|
563
626
|
exports.GraphEngine = GraphEngine;
|