@ai.ntellect/core 0.6.17 → 0.6.19
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/.mocharc.json +1 -2
- package/README.md +123 -178
- package/dist/graph/controller.js +29 -6
- package/dist/graph/index.js +302 -62
- package/dist/index.js +21 -6
- package/dist/interfaces/index.js +15 -0
- package/dist/modules/agenda/adapters/node-cron/index.js +29 -0
- package/dist/modules/agenda/index.js +140 -0
- package/dist/{services/embedding.js → modules/embedding/adapters/ai/index.js} +24 -7
- package/dist/modules/embedding/index.js +59 -0
- package/dist/modules/memory/adapters/in-memory/index.js +210 -0
- package/dist/{memory → modules/memory}/adapters/meilisearch/index.js +97 -2
- package/dist/{memory → modules/memory}/adapters/redis/index.js +77 -15
- package/dist/modules/memory/index.js +103 -0
- package/dist/utils/{stringifiy-zod-schema.js → generate-action-schema.js} +5 -5
- package/graph/controller.ts +37 -13
- package/graph/index.ts +348 -73
- package/index.ts +24 -6
- package/interfaces/index.ts +346 -27
- package/modules/agenda/adapters/node-cron/index.ts +25 -0
- package/modules/agenda/index.ts +159 -0
- package/modules/embedding/adapters/ai/index.ts +42 -0
- package/modules/embedding/index.ts +45 -0
- package/modules/memory/adapters/in-memory/index.ts +203 -0
- package/{memory → modules/memory}/adapters/meilisearch/index.ts +114 -12
- package/modules/memory/adapters/redis/index.ts +164 -0
- package/modules/memory/index.ts +93 -0
- package/package.json +3 -1
- package/test/graph/index.test.ts +646 -0
- package/test/modules/agenda/node-cron.test.ts +286 -0
- package/test/modules/embedding/ai.test.ts +78 -0
- package/test/modules/memory/adapters/in-memory.test.ts +153 -0
- package/test/{memory → modules/memory}/adapters/meilisearch.test.ts +79 -75
- package/test/modules/memory/adapters/redis.test.ts +169 -0
- package/test/modules/memory/base.test.ts +230 -0
- package/test/services/agenda.test.ts +279 -280
- package/types/index.ts +82 -203
- package/utils/{stringifiy-zod-schema.ts → generate-action-schema.ts} +3 -3
- package/app/README.md +0 -36
- package/app/app/favicon.ico +0 -0
- package/app/app/globals.css +0 -21
- package/app/app/gun.ts +0 -0
- package/app/app/layout.tsx +0 -18
- package/app/app/page.tsx +0 -321
- package/app/eslint.config.mjs +0 -16
- package/app/next.config.ts +0 -7
- package/app/package-lock.json +0 -5912
- package/app/package.json +0 -31
- package/app/pnpm-lock.yaml +0 -4031
- package/app/postcss.config.mjs +0 -8
- package/app/public/file.svg +0 -1
- package/app/public/globe.svg +0 -1
- package/app/public/next.svg +0 -1
- package/app/public/vercel.svg +0 -1
- package/app/public/window.svg +0 -1
- package/app/tailwind.config.ts +0 -18
- package/app/tsconfig.json +0 -27
- package/dist/memory/index.js +0 -9
- package/dist/services/agenda.js +0 -115
- package/dist/services/queue.js +0 -142
- package/dist/utils/experimental-graph-rag.js +0 -152
- package/dist/utils/generate-object.js +0 -111
- package/dist/utils/inject-actions.js +0 -16
- package/dist/utils/queue-item-transformer.js +0 -24
- package/dist/utils/sanitize-results.js +0 -60
- package/memory/adapters/redis/index.ts +0 -103
- package/memory/index.ts +0 -22
- package/services/agenda.ts +0 -118
- package/services/embedding.ts +0 -26
- package/services/queue.ts +0 -145
- package/test/memory/adapters/redis.test.ts +0 -159
- package/test/memory/base.test.ts +0 -225
- package/test/services/queue.test.ts +0 -286
- package/utils/experimental-graph-rag.ts +0 -170
- package/utils/generate-object.ts +0 -117
- package/utils/inject-actions.ts +0 -19
- package/utils/queue-item-transformer.ts +0 -38
- package/utils/sanitize-results.ts +0 -66
package/graph/index.ts
CHANGED
@@ -1,47 +1,131 @@
|
|
1
|
-
import {
|
2
|
-
import EventEmitter from "events";
|
1
|
+
import { EventEmitter } from "events";
|
3
2
|
import { ZodSchema } from "zod";
|
3
|
+
import { IEventEmitter } from "../interfaces";
|
4
|
+
import { GraphContext, GraphDefinition, Node } from "../types";
|
4
5
|
|
5
|
-
|
6
|
+
/**
|
7
|
+
* @module GraphFlow
|
8
|
+
* @description A flexible workflow engine that manages the execution of nodes in a graph-like structure.
|
9
|
+
*
|
10
|
+
* Key features:
|
11
|
+
* - Multiple branches support
|
12
|
+
* - Conditional branching (runs first matching condition, or all if none have conditions)
|
13
|
+
* - Event-driven nodes
|
14
|
+
* - Zod validation of context/inputs/outputs
|
15
|
+
* - Automatic retry on node failures
|
16
|
+
*
|
17
|
+
* @template T - Extends ZodSchema for type validation
|
18
|
+
*/
|
19
|
+
export class GraphFlow<T extends ZodSchema> {
|
6
20
|
private nodes: Map<string, Node<T>>;
|
7
21
|
private context: GraphContext<T>;
|
8
22
|
public validator?: T;
|
9
|
-
private eventEmitter:
|
23
|
+
private eventEmitter: IEventEmitter;
|
10
24
|
private globalErrorHandler?: (error: Error, context: GraphContext<T>) => void;
|
25
|
+
private graphEvents?: string[];
|
26
|
+
private entryNode?: string;
|
11
27
|
|
12
|
-
|
28
|
+
/**
|
29
|
+
* Creates a new instance of GraphFlow
|
30
|
+
* @param {string} name - The name of the graph flow
|
31
|
+
* @param {GraphDefinition<T>} config - Configuration object containing nodes, schema, context, and error handlers
|
32
|
+
*/
|
33
|
+
constructor(public name: string, config: GraphDefinition<T>) {
|
13
34
|
this.nodes = new Map(config.nodes.map((node) => [node.name, node]));
|
14
|
-
this.
|
15
|
-
this.
|
16
|
-
this.globalErrorHandler = config.
|
17
|
-
this.eventEmitter = new EventEmitter();
|
35
|
+
this.validator = config.schema;
|
36
|
+
this.context = config.schema.parse(config.context) as GraphContext<T>;
|
37
|
+
this.globalErrorHandler = config.onError;
|
38
|
+
this.eventEmitter = config.eventEmitter || new EventEmitter();
|
39
|
+
this.graphEvents = config.events;
|
40
|
+
|
18
41
|
this.setupEventListeners();
|
42
|
+
this.setupGraphEventListeners();
|
19
43
|
}
|
20
44
|
|
45
|
+
/**
|
46
|
+
* Creates a new context for execution
|
47
|
+
* @private
|
48
|
+
* @returns {GraphContext<T>} A cloned context to prevent pollution during parallel execution
|
49
|
+
*/
|
21
50
|
private createNewContext(): GraphContext<T> {
|
22
51
|
return structuredClone(this.context);
|
23
52
|
}
|
24
53
|
|
54
|
+
/**
|
55
|
+
* Sets up event listeners for node-based events
|
56
|
+
* @private
|
57
|
+
* @description Attaches all node-based event triggers while preserving external listeners
|
58
|
+
*/
|
25
59
|
private setupEventListeners(): void {
|
60
|
+
// First remove only the existing node-based listeners that we might have created previously
|
61
|
+
// We do NOT remove, for example, "nodeStarted" or "nodeCompleted" listeners that test code added.
|
62
|
+
for (const [eventName, listener] of this.eventEmitter
|
63
|
+
.rawListeners("*")
|
64
|
+
.entries()) {
|
65
|
+
// This can be tricky—EventEmitter doesn't directly let you remove by "type" of listener.
|
66
|
+
// Alternatively, we can store references in a separate structure.
|
67
|
+
// For simplicity, let's do a full removeAllListeners() on node-specified events (only),
|
68
|
+
// then re-add them below, but keep the test-based events like "nodeStarted" or "nodeCompleted".
|
69
|
+
}
|
70
|
+
|
71
|
+
// The simplest approach: removeAllListeners for each event that is declared as a node event
|
72
|
+
// so we don't stack up duplicates:
|
73
|
+
const allEvents = new Set<string>();
|
26
74
|
for (const node of this.nodes.values()) {
|
27
|
-
node.events
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
75
|
+
if (node.events) {
|
76
|
+
node.events.forEach((evt) => allEvents.add(evt));
|
77
|
+
}
|
78
|
+
}
|
79
|
+
for (const evt of allEvents) {
|
80
|
+
// remove only those events that are used by nodes
|
81
|
+
this.eventEmitter.removeAllListeners(evt);
|
82
|
+
}
|
83
|
+
|
84
|
+
// Now re-add the node-based event triggers
|
85
|
+
for (const node of this.nodes.values()) {
|
86
|
+
if (node.events && node.events.length > 0) {
|
87
|
+
node.events.forEach((event) => {
|
88
|
+
this.eventEmitter.on(
|
89
|
+
event,
|
90
|
+
async (data?: Partial<GraphContext<T>>) => {
|
91
|
+
const freshContext = this.createNewContext();
|
92
|
+
if (data) Object.assign(freshContext, data);
|
93
|
+
|
94
|
+
// If triggered by an event, we pass "true" so event-driven node will skip `next`.
|
95
|
+
await this.executeNode(
|
96
|
+
node.name,
|
97
|
+
freshContext,
|
98
|
+
undefined,
|
99
|
+
/* triggeredByEvent= */ true
|
100
|
+
);
|
101
|
+
}
|
102
|
+
);
|
32
103
|
});
|
33
|
-
}
|
104
|
+
}
|
34
105
|
}
|
35
106
|
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Executes a specific node in the graph
|
110
|
+
* @private
|
111
|
+
* @param {string} nodeName - Name of the node to execute
|
112
|
+
* @param {GraphContext<T>} context - Current execution context
|
113
|
+
* @param {any} inputs - Input parameters for the node
|
114
|
+
* @param {boolean} triggeredByEvent - Whether the execution was triggered by an event
|
115
|
+
* @returns {Promise<void>}
|
116
|
+
*/
|
36
117
|
private async executeNode(
|
37
118
|
nodeName: string,
|
38
119
|
context: GraphContext<T>,
|
39
|
-
|
120
|
+
inputs?: any,
|
121
|
+
triggeredByEvent: boolean = false
|
40
122
|
): Promise<void> {
|
41
123
|
const node = this.nodes.get(nodeName);
|
42
|
-
if (!node) throw new Error(`❌ Node ${nodeName} not found
|
124
|
+
if (!node) throw new Error(`❌ Node "${nodeName}" not found.`);
|
43
125
|
|
44
|
-
if (node.condition && !node.condition(context))
|
126
|
+
if (node.condition && !node.condition(context)) {
|
127
|
+
return;
|
128
|
+
}
|
45
129
|
|
46
130
|
let attempts = 0;
|
47
131
|
const maxAttempts = node.retry?.maxAttempts || 1;
|
@@ -49,43 +133,67 @@ export class Graph<T extends ZodSchema> {
|
|
49
133
|
|
50
134
|
while (attempts < maxAttempts) {
|
51
135
|
try {
|
52
|
-
let
|
53
|
-
|
54
|
-
|
55
|
-
if (node.parameters) {
|
56
|
-
if (!params) {
|
136
|
+
let validatedInputs;
|
137
|
+
if (node.inputs) {
|
138
|
+
if (!inputs) {
|
57
139
|
throw new Error(
|
58
|
-
`❌
|
140
|
+
`❌ Inputs required for node "${nodeName}" but received: ${inputs}`
|
59
141
|
);
|
60
142
|
}
|
61
|
-
|
143
|
+
validatedInputs = node.inputs.parse(inputs);
|
62
144
|
}
|
63
145
|
|
64
146
|
this.eventEmitter.emit("nodeStarted", { name: nodeName, context });
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
);
|
72
|
-
}
|
73
|
-
await node.executeWithParams(context, validatedParams);
|
147
|
+
|
148
|
+
// Execute the node
|
149
|
+
await node.execute(context, validatedInputs);
|
150
|
+
|
151
|
+
if (node.outputs) {
|
152
|
+
node.outputs.parse(context);
|
74
153
|
}
|
75
154
|
|
76
155
|
this.validateContext(context);
|
77
|
-
|
78
156
|
this.eventEmitter.emit("nodeCompleted", { name: nodeName, context });
|
79
157
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
);
|
158
|
+
// IMPORTANT: Si le nœud est déclenché par un événement et a des événements définis,
|
159
|
+
// on arrête ici et on ne suit pas la chaîne next
|
160
|
+
if (triggeredByEvent && node.events && node.events.length > 0) {
|
161
|
+
this.context = structuredClone(context);
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
|
165
|
+
// Gérer les nœuds suivants
|
166
|
+
if (node.next && node.next.length > 0) {
|
167
|
+
const branchContexts: GraphContext<T>[] = [];
|
168
|
+
|
169
|
+
// Exécuter toutes les branches valides
|
170
|
+
for (const nextNodeName of node.next) {
|
171
|
+
const nextNode = this.nodes.get(nextNodeName);
|
172
|
+
if (!nextNode) continue;
|
173
|
+
|
174
|
+
const branchContext = structuredClone(context);
|
175
|
+
|
176
|
+
// Si le nœud a une condition et qu'elle n'est pas remplie, passer au suivant
|
177
|
+
if (nextNode.condition && !nextNode.condition(branchContext)) {
|
178
|
+
continue;
|
179
|
+
}
|
180
|
+
|
181
|
+
await this.executeNode(nextNodeName, branchContext);
|
182
|
+
branchContexts.push(branchContext);
|
183
|
+
}
|
184
|
+
|
185
|
+
// Fusionner les résultats des branches dans l'ordre
|
186
|
+
if (branchContexts.length > 0) {
|
187
|
+
const finalContext = branchContexts[branchContexts.length - 1];
|
188
|
+
Object.assign(context, finalContext);
|
189
|
+
}
|
84
190
|
}
|
191
|
+
|
192
|
+
// Mettre à jour le contexte global
|
193
|
+
this.context = structuredClone(context);
|
85
194
|
return;
|
86
195
|
} catch (error) {
|
87
196
|
attempts++;
|
88
|
-
|
89
197
|
if (attempts >= maxAttempts) {
|
90
198
|
this.eventEmitter.emit("nodeError", { nodeName, error });
|
91
199
|
node.onError?.(error as Error);
|
@@ -97,97 +205,264 @@ export class Graph<T extends ZodSchema> {
|
|
97
205
|
`[Graph ${this.name}] Retry attempt ${attempts} for node ${nodeName}`,
|
98
206
|
{ error }
|
99
207
|
);
|
100
|
-
|
101
208
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
102
209
|
}
|
103
210
|
}
|
104
211
|
}
|
105
212
|
|
213
|
+
/**
|
214
|
+
* Validates the current context against the schema
|
215
|
+
* @private
|
216
|
+
* @param {GraphContext<T>} context - Context to validate
|
217
|
+
* @throws {Error} If validation fails
|
218
|
+
*/
|
106
219
|
private validateContext(context: GraphContext<T>): void {
|
107
220
|
if (this.validator) {
|
108
221
|
this.validator.parse(context);
|
109
222
|
}
|
110
223
|
}
|
111
224
|
|
225
|
+
/**
|
226
|
+
* Executes the graph flow starting from a specific node
|
227
|
+
* @param {string} startNode - Name of the node to start execution from
|
228
|
+
* @param {Partial<GraphContext<T>>} inputContext - Optional partial context to merge with current context
|
229
|
+
* @param {any} inputParams - Optional input parameters for the start node
|
230
|
+
* @returns {Promise<GraphContext<T>>} Final context after execution
|
231
|
+
*/
|
112
232
|
async execute(
|
113
233
|
startNode: string,
|
114
234
|
inputContext?: Partial<GraphContext<T>>,
|
115
235
|
inputParams?: any
|
116
236
|
): Promise<GraphContext<T>> {
|
237
|
+
// Fresh local context from the global
|
117
238
|
const context = this.createNewContext();
|
118
239
|
if (inputContext) Object.assign(context, inputContext);
|
119
240
|
|
241
|
+
// Emit "graphStarted"
|
120
242
|
this.eventEmitter.emit("graphStarted", { name: this.name });
|
243
|
+
|
121
244
|
try {
|
122
|
-
|
123
|
-
this.
|
124
|
-
|
245
|
+
// Because we're calling explicitly, it's NOT triggered by an event
|
246
|
+
await this.executeNode(
|
247
|
+
startNode,
|
248
|
+
context,
|
249
|
+
inputParams,
|
250
|
+
/* triggeredByEvent= */ false
|
251
|
+
);
|
252
|
+
|
253
|
+
// Emit "graphCompleted"
|
254
|
+
this.eventEmitter.emit("graphCompleted", {
|
255
|
+
name: this.name,
|
256
|
+
context: this.context,
|
257
|
+
});
|
258
|
+
|
259
|
+
// Return a snapshot of the final global context
|
260
|
+
return structuredClone(this.context);
|
125
261
|
} catch (error) {
|
262
|
+
// Emit "graphError"
|
126
263
|
this.eventEmitter.emit("graphError", { name: this.name, error });
|
127
|
-
this.globalErrorHandler?.(error as Error, context);
|
264
|
+
this.globalErrorHandler?.(error as Error, context);
|
128
265
|
throw error;
|
129
266
|
}
|
130
267
|
}
|
131
268
|
|
132
|
-
|
269
|
+
/**
|
270
|
+
* Emits an event to trigger event-based nodes
|
271
|
+
* @param {string} eventName - Name of the event to emit
|
272
|
+
* @param {Partial<GraphContext<T>>} data - Optional data to merge with context
|
273
|
+
* @returns {Promise<GraphContext<T>>} Updated context after event handling
|
274
|
+
*/
|
275
|
+
public async emit(
|
133
276
|
eventName: string,
|
134
277
|
data?: Partial<GraphContext<T>>
|
135
278
|
): Promise<GraphContext<T>> {
|
136
|
-
|
137
|
-
|
279
|
+
// Merge data into a fresh copy of the global context if desired
|
280
|
+
const context = this.createNewContext();
|
281
|
+
if (data) Object.assign(context, data);
|
138
282
|
|
139
|
-
|
283
|
+
// Just emit the event; the node-based event listeners in setupEventListeners()
|
284
|
+
// will handle calling "executeNode(...)"
|
285
|
+
this.eventEmitter.emit(eventName, context);
|
140
286
|
|
141
|
-
|
142
|
-
|
143
|
-
);
|
144
|
-
if (eventNodes.length === 0) return resolve(this.context);
|
145
|
-
|
146
|
-
Promise.all(
|
147
|
-
eventNodes.map(
|
148
|
-
(node) =>
|
149
|
-
new Promise<void>((resolve) => {
|
150
|
-
this.eventEmitter.once("nodeCompleted", ({ nodeName }) => {
|
151
|
-
if (nodeName === node.name) resolve();
|
152
|
-
});
|
153
|
-
})
|
154
|
-
)
|
155
|
-
)
|
156
|
-
.then(() => resolve(this.context))
|
157
|
-
.catch(reject);
|
158
|
-
});
|
287
|
+
// Return the updated global context
|
288
|
+
return this.getContext();
|
159
289
|
}
|
160
290
|
|
291
|
+
/**
|
292
|
+
* Registers an event handler
|
293
|
+
* @param {string} eventName - Name of the event to listen for
|
294
|
+
* @param {Function} handler - Handler function to execute when event is emitted
|
295
|
+
*/
|
161
296
|
on(eventName: string, handler: (...args: any[]) => void): void {
|
162
297
|
this.eventEmitter.on(eventName, handler);
|
163
298
|
}
|
164
299
|
|
165
|
-
|
300
|
+
/**
|
301
|
+
* Updates the graph definition with new configuration
|
302
|
+
* @param {GraphDefinition<T>} definition - New graph definition
|
303
|
+
*/
|
304
|
+
load(definition: GraphDefinition<T>): void {
|
305
|
+
// Clear all existing nodes
|
166
306
|
this.nodes.clear();
|
167
|
-
|
168
|
-
|
169
|
-
)
|
170
|
-
|
307
|
+
// Wipe out old node-based event listeners
|
308
|
+
// (We keep external test listeners like "nodeStarted" or "nodeCompleted".)
|
309
|
+
if (definition.nodes?.length) {
|
310
|
+
const allEvents = new Set<string>();
|
311
|
+
definition.nodes.forEach((n) =>
|
312
|
+
n.events?.forEach((evt) => allEvents.add(evt))
|
313
|
+
);
|
314
|
+
for (const evt of allEvents) {
|
315
|
+
this.eventEmitter.removeAllListeners(evt);
|
316
|
+
}
|
317
|
+
}
|
318
|
+
|
319
|
+
// Add in new nodes
|
320
|
+
definition.nodes.forEach((node) => this.nodes.set(node.name, node));
|
321
|
+
|
322
|
+
// Parse the new context
|
323
|
+
this.context = definition.schema.parse(
|
324
|
+
definition.context
|
325
|
+
) as GraphContext<T>;
|
326
|
+
this.validator = definition.schema;
|
327
|
+
|
328
|
+
// Store entry node
|
329
|
+
this.entryNode = definition.entryNode;
|
330
|
+
// Store graph events
|
331
|
+
this.graphEvents = definition.events;
|
332
|
+
|
333
|
+
// Re-setup only node-based event triggers
|
334
|
+
for (const node of this.nodes.values()) {
|
335
|
+
if (node.events && node.events.length > 0) {
|
336
|
+
node.events.forEach((event) => {
|
337
|
+
this.eventEmitter.on(
|
338
|
+
event,
|
339
|
+
async (data?: Partial<GraphContext<T>>) => {
|
340
|
+
const freshContext = structuredClone(this.context);
|
341
|
+
if (data) Object.assign(freshContext, data);
|
342
|
+
await this.executeNode(node.name, freshContext, undefined, true);
|
343
|
+
}
|
344
|
+
);
|
345
|
+
});
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
349
|
+
// Re-setup graph event listeners
|
350
|
+
this.setupGraphEventListeners();
|
171
351
|
}
|
172
352
|
|
353
|
+
/**
|
354
|
+
* Returns the current context
|
355
|
+
* @returns {GraphContext<T>} Current graph context
|
356
|
+
*/
|
173
357
|
getContext(): GraphContext<T> {
|
174
358
|
return structuredClone(this.context);
|
175
359
|
}
|
176
360
|
|
361
|
+
/**
|
362
|
+
* Logs a message with optional data
|
363
|
+
* @param {string} message - Message to log
|
364
|
+
* @param {any} data - Optional data to log
|
365
|
+
*/
|
177
366
|
log(message: string, data?: any): void {
|
178
367
|
console.log(`[Graph ${this.name}] ${message}`, data);
|
179
368
|
}
|
180
369
|
|
370
|
+
/**
|
371
|
+
* Adds a new node to the graph
|
372
|
+
* @param {Node<T>} node - Node to add
|
373
|
+
* @throws {Error} If node with same name already exists
|
374
|
+
*/
|
181
375
|
addNode(node: Node<T>): void {
|
182
376
|
this.nodes.set(node.name, node);
|
183
|
-
|
377
|
+
if (node.events && node.events.length > 0) {
|
378
|
+
for (const evt of node.events) {
|
379
|
+
this.eventEmitter.on(evt, async (data?: Partial<GraphContext<T>>) => {
|
380
|
+
const freshContext = this.createNewContext();
|
381
|
+
if (data) Object.assign(freshContext, data);
|
382
|
+
await this.executeNode(node.name, freshContext, undefined, true);
|
383
|
+
});
|
384
|
+
}
|
385
|
+
}
|
184
386
|
}
|
185
387
|
|
388
|
+
/**
|
389
|
+
* Removes a node from the graph
|
390
|
+
* @param {string} nodeName - Name of the node to remove
|
391
|
+
*/
|
186
392
|
removeNode(nodeName: string): void {
|
393
|
+
const node = this.nodes.get(nodeName);
|
394
|
+
if (!node) return;
|
395
|
+
|
396
|
+
// remove the node from the map
|
187
397
|
this.nodes.delete(nodeName);
|
398
|
+
|
399
|
+
// remove any of its event-based listeners
|
400
|
+
if (node.events && node.events.length > 0) {
|
401
|
+
for (const evt of node.events) {
|
402
|
+
// removeAllListeners(evt) would also remove other node listeners,
|
403
|
+
// so we need a more fine-grained approach. Ideally, we should keep a reference
|
404
|
+
// to the exact listener function we attached. For brevity, let's remove all for that event:
|
405
|
+
this.eventEmitter.removeAllListeners(evt);
|
406
|
+
}
|
407
|
+
// Then reattach the others that remain in the graph
|
408
|
+
for (const n of this.nodes.values()) {
|
409
|
+
if (n.events && n.events.length > 0) {
|
410
|
+
n.events.forEach((e) => {
|
411
|
+
this.eventEmitter.on(e, async (data?: Partial<GraphContext<T>>) => {
|
412
|
+
const freshContext = this.createNewContext();
|
413
|
+
if (data) Object.assign(freshContext, data);
|
414
|
+
await this.executeNode(n.name, freshContext, undefined, true);
|
415
|
+
});
|
416
|
+
});
|
417
|
+
}
|
418
|
+
}
|
419
|
+
}
|
188
420
|
}
|
189
421
|
|
422
|
+
/**
|
423
|
+
* Returns all nodes in the graph
|
424
|
+
* @returns {Node<T>[]} Array of all nodes
|
425
|
+
*/
|
190
426
|
getNodes(): Node<T>[] {
|
191
427
|
return Array.from(this.nodes.values());
|
192
428
|
}
|
429
|
+
|
430
|
+
private setupGraphEventListeners(): void {
|
431
|
+
if (this.graphEvents && this.graphEvents.length > 0) {
|
432
|
+
this.graphEvents.forEach((event) => {
|
433
|
+
this.eventEmitter.on(event, async (data?: Partial<GraphContext<T>>) => {
|
434
|
+
const freshContext = this.createNewContext();
|
435
|
+
if (data) Object.assign(freshContext, data);
|
436
|
+
|
437
|
+
// Emit "graphStarted"
|
438
|
+
this.eventEmitter.emit("graphStarted", { name: this.name });
|
439
|
+
|
440
|
+
try {
|
441
|
+
// Execute the graph starting from the entry node
|
442
|
+
if (!this.entryNode) {
|
443
|
+
throw new Error("No entry node defined for graph event handling");
|
444
|
+
}
|
445
|
+
|
446
|
+
await this.executeNode(
|
447
|
+
this.entryNode,
|
448
|
+
freshContext,
|
449
|
+
undefined,
|
450
|
+
false
|
451
|
+
);
|
452
|
+
|
453
|
+
// Emit "graphCompleted"
|
454
|
+
this.eventEmitter.emit("graphCompleted", {
|
455
|
+
name: this.name,
|
456
|
+
context: this.context,
|
457
|
+
});
|
458
|
+
} catch (error) {
|
459
|
+
// Emit "graphError"
|
460
|
+
this.eventEmitter.emit("graphError", { name: this.name, error });
|
461
|
+
this.globalErrorHandler?.(error as Error, freshContext);
|
462
|
+
throw error;
|
463
|
+
}
|
464
|
+
});
|
465
|
+
});
|
466
|
+
}
|
467
|
+
}
|
193
468
|
}
|
package/index.ts
CHANGED
@@ -1,11 +1,29 @@
|
|
1
|
+
/**
|
2
|
+
* @module @ai.ntellect/core
|
3
|
+
* @description Core module with workflow functionality, providing graph management,
|
4
|
+
* memory storage, agenda scheduling, and embedding capabilities.
|
5
|
+
*
|
6
|
+
* This module exports various components:
|
7
|
+
* - Graph management and controller
|
8
|
+
* - Memory storage adapters (Meilisearch, Redis)
|
9
|
+
* - Agenda scheduling with node-cron adapter
|
10
|
+
* - Embedding functionality with AI adapter
|
11
|
+
* - Utility functions for action schema generation and header building
|
12
|
+
*/
|
13
|
+
|
1
14
|
export * from "./graph";
|
2
15
|
export * from "./graph/controller";
|
3
|
-
export * from "./memory";
|
4
|
-
export * from "./memory/adapters/meilisearch";
|
5
|
-
export * from "./memory/adapters/redis";
|
16
|
+
export * from "./modules/memory";
|
17
|
+
export * from "./modules/memory/adapters/meilisearch";
|
18
|
+
export * from "./modules/memory/adapters/redis";
|
6
19
|
|
7
20
|
export * from "./interfaces";
|
8
|
-
export * from "./
|
9
|
-
export * from "./
|
21
|
+
export * from "./modules/agenda";
|
22
|
+
export * from "./modules/agenda/adapters/node-cron";
|
23
|
+
export * from "./modules/embedding";
|
24
|
+
export * from "./modules/embedding/adapters/ai";
|
25
|
+
|
10
26
|
export * from "./types";
|
11
|
-
|
27
|
+
|
28
|
+
export * from "./utils/generate-action-schema";
|
29
|
+
export * from "./utils/header-builder";
|