@ai.ntellect/core 0.7.13 → 0.8.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/dist/graph/controller.d.ts +3 -3
- package/dist/graph/controller.d.ts.map +1 -1
- package/dist/graph/controller.js +14 -5
- package/dist/graph/controller.js.map +1 -1
- package/dist/graph/event-manager.d.ts +9 -1
- package/dist/graph/event-manager.d.ts.map +1 -1
- package/dist/graph/event-manager.js +115 -37
- package/dist/graph/event-manager.js.map +1 -1
- package/dist/graph/index.d.ts +21 -2
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +60 -11
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/node.d.ts +0 -24
- package/dist/graph/node.d.ts.map +1 -1
- package/dist/graph/node.js +2 -71
- package/dist/graph/node.js.map +1 -1
- package/dist/graph/observer.d.ts +6 -87
- package/dist/graph/observer.d.ts.map +1 -1
- package/dist/graph/observer.js +3 -116
- package/dist/graph/observer.js.map +1 -1
- package/dist/index.d.ts +1 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/index.js.map +1 -1
- package/dist/interfaces/index.d.ts +10 -1
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/modules/agent/agent.d.ts +35 -0
- package/dist/modules/agent/agent.d.ts.map +1 -0
- package/dist/modules/agent/agent.js +106 -0
- package/dist/modules/agent/agent.js.map +1 -0
- package/dist/modules/agent/base/executor.d.ts +51 -0
- package/dist/modules/agent/base/executor.d.ts.map +1 -0
- package/dist/modules/agent/base/executor.js +66 -0
- package/dist/modules/agent/base/executor.js.map +1 -0
- package/dist/modules/agent/base/index.d.ts +30 -0
- package/dist/modules/agent/base/index.d.ts.map +1 -0
- package/dist/modules/agent/base/index.js +100 -0
- package/dist/modules/agent/base/index.js.map +1 -0
- package/dist/modules/agent/generic-assistant.d.ts +20 -0
- package/dist/modules/agent/generic-assistant.d.ts.map +1 -0
- package/dist/modules/agent/generic-assistant.js +89 -0
- package/dist/modules/agent/generic-assistant.js.map +1 -0
- package/dist/modules/agent/generic-executor.d.ts +57 -0
- package/dist/modules/agent/generic-executor.d.ts.map +1 -0
- package/dist/modules/agent/generic-executor.js +200 -0
- package/dist/modules/agent/generic-executor.js.map +1 -0
- package/dist/modules/agent/llm-factory.d.ts +19 -0
- package/dist/modules/agent/llm-factory.d.ts.map +1 -0
- package/dist/modules/agent/llm-factory.js +56 -0
- package/dist/modules/agent/llm-factory.js.map +1 -0
- package/dist/modules/agent/prompt-builder.d.ts +35 -0
- package/dist/modules/agent/prompt-builder.d.ts.map +1 -0
- package/dist/modules/agent/prompt-builder.js +76 -0
- package/dist/modules/agent/prompt-builder.js.map +1 -0
- package/dist/modules/memory/adapters/in-memory/index.d.ts.map +1 -1
- package/dist/modules/memory/adapters/in-memory/index.js +4 -3
- package/dist/modules/memory/adapters/in-memory/index.js.map +1 -1
- package/dist/modules/memory/adapters/meilisearch/index.d.ts.map +1 -1
- package/dist/modules/memory/adapters/meilisearch/index.js +7 -4
- package/dist/modules/memory/adapters/meilisearch/index.js.map +1 -1
- package/dist/modules/memory/adapters/redis/index.d.ts.map +1 -1
- package/dist/modules/memory/adapters/redis/index.js +2 -1
- package/dist/modules/memory/adapters/redis/index.js.map +1 -1
- package/dist/modules/nlp/engine.d.ts +126 -0
- package/dist/modules/nlp/engine.d.ts.map +1 -0
- package/dist/modules/nlp/engine.js +300 -0
- package/dist/modules/nlp/engine.js.map +1 -0
- package/dist/modules/nlp/index.d.ts +27 -0
- package/dist/modules/nlp/index.d.ts.map +1 -0
- package/dist/modules/nlp/index.js +56 -0
- package/dist/modules/nlp/index.js.map +1 -0
- package/dist/types/agent.d.ts +233 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +29 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/index.d.ts +81 -18
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/generate-action-schema.d.ts.map +1 -1
- package/graph/controller.ts +21 -10
- package/graph/event-manager.ts +135 -42
- package/graph/index.ts +58 -5
- package/graph/node.ts +2 -104
- package/graph/observer.ts +9 -215
- package/index.ts +2 -7
- package/interfaces/index.ts +12 -0
- package/modules/agent/agent.ts +108 -0
- package/modules/agent/base/executor.ts +100 -0
- package/modules/agent/base/index.ts +99 -0
- package/modules/agent/generic-assistant.ts +90 -0
- package/modules/agent/generic-executor.ts +259 -0
- package/modules/agent/llm-factory.ts +47 -0
- package/modules/agent/prompt-builder.ts +78 -0
- package/modules/memory/adapters/in-memory/index.ts +4 -3
- package/modules/memory/adapters/meilisearch/index.ts +7 -4
- package/modules/memory/adapters/redis/index.ts +2 -1
- package/modules/nlp/engine.ts +325 -0
- package/modules/nlp/index.ts +45 -0
- package/package.json +5 -2
- package/test/graph/controller.test.ts +18 -14
- package/test/graph/index.test.ts +10 -8
- package/test/graph/node.test.ts +18 -14
- package/types/agent.ts +174 -0
- package/types/index.ts +84 -18
@@ -0,0 +1,325 @@
|
|
1
|
+
import { ActionHandler, NLPConfig } from "../../types";
|
2
|
+
|
3
|
+
const { dockStart } = require("@nlpjs/basic");
|
4
|
+
|
5
|
+
/**
|
6
|
+
* NLP Engine for processing natural language commands
|
7
|
+
* @example
|
8
|
+
* const engine = await NLPEngine.create({
|
9
|
+
* corpus: require('./corpus.json'),
|
10
|
+
* responses: require('./responses.json'),
|
11
|
+
* entities: require('./entities.json')
|
12
|
+
* });
|
13
|
+
*
|
14
|
+
* engine.addAction('transferTokens', async (data) => {
|
15
|
+
* // Handle transfer logic
|
16
|
+
* });
|
17
|
+
*
|
18
|
+
* const response = await engine.process('transfer 5 ETH');
|
19
|
+
*/
|
20
|
+
export class NLPEngine {
|
21
|
+
private manager: any;
|
22
|
+
private responses: Record<string, any>;
|
23
|
+
private intentHandlers: Record<string, ActionHandler> = {};
|
24
|
+
|
25
|
+
constructor() {
|
26
|
+
this.responses = {};
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Creates and initializes a new NLP Engine
|
31
|
+
*/
|
32
|
+
static async create(config: NLPConfig): Promise<NLPEngine> {
|
33
|
+
const engine = new NLPEngine();
|
34
|
+
await engine.init(config);
|
35
|
+
return engine;
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Initializes the NLP engine with configuration
|
40
|
+
*/
|
41
|
+
private async init({
|
42
|
+
corpus,
|
43
|
+
responses,
|
44
|
+
entities,
|
45
|
+
language = "en",
|
46
|
+
threshold = 0.5,
|
47
|
+
}: NLPConfig) {
|
48
|
+
const dock = await dockStart({
|
49
|
+
settings: {
|
50
|
+
nlp: {
|
51
|
+
forceNER: true,
|
52
|
+
languages: [language],
|
53
|
+
corpora: corpus ? [corpus] : undefined,
|
54
|
+
},
|
55
|
+
ner: { threshold },
|
56
|
+
},
|
57
|
+
use: ["Basic", "LangEn"],
|
58
|
+
});
|
59
|
+
|
60
|
+
this.manager = dock.get("nlp");
|
61
|
+
this.responses = responses || {};
|
62
|
+
|
63
|
+
if (corpus) {
|
64
|
+
await this.manager.addCorpus(corpus);
|
65
|
+
}
|
66
|
+
|
67
|
+
if (entities) {
|
68
|
+
this.registerEntities(entities);
|
69
|
+
}
|
70
|
+
|
71
|
+
await this.manager.train();
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Registers entities for Named Entity Recognition (NER)
|
76
|
+
* @private
|
77
|
+
* @param {Record<string, any>} entities - Entity definitions
|
78
|
+
*/
|
79
|
+
private registerEntities(entities: Record<string, any>) {
|
80
|
+
Object.entries(entities).forEach(([name, data]: [string, any]) => {
|
81
|
+
if (data.options) {
|
82
|
+
Object.entries(data.options).forEach(([option, texts]) => {
|
83
|
+
this.manager.addNerRuleOptionTexts(
|
84
|
+
"en",
|
85
|
+
name,
|
86
|
+
option,
|
87
|
+
texts as string[]
|
88
|
+
);
|
89
|
+
});
|
90
|
+
} else if (data.regex) {
|
91
|
+
this.manager.addNerRegexRule("en", name, data.regex);
|
92
|
+
} else if (data.trim) {
|
93
|
+
data.trim.forEach((trimRule: any) => {
|
94
|
+
if (trimRule.position === "afterLast") {
|
95
|
+
trimRule.words.forEach((word: string) => {
|
96
|
+
this.manager.addNerAfterLastCondition("en", name, word);
|
97
|
+
});
|
98
|
+
} else if (trimRule.position === "betweenLast") {
|
99
|
+
this.manager.addNerBetweenLastCondition(
|
100
|
+
"en",
|
101
|
+
name,
|
102
|
+
trimRule.leftWords,
|
103
|
+
trimRule.rightWords
|
104
|
+
);
|
105
|
+
}
|
106
|
+
});
|
107
|
+
}
|
108
|
+
});
|
109
|
+
}
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Adds an action handler for a specific intent
|
113
|
+
* @param {string} name - Intent name
|
114
|
+
* @param {ActionHandler} handler - Action handler function
|
115
|
+
*/
|
116
|
+
addAction(name: string, handler: ActionHandler): void {
|
117
|
+
this.intentHandlers[name] = handler;
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Creates and loads a pre-trained NLP Engine
|
122
|
+
*/
|
123
|
+
static async loadFromModel(
|
124
|
+
modelPath: string,
|
125
|
+
responses?: Record<string, any>
|
126
|
+
): Promise<NLPEngine> {
|
127
|
+
const engine = new NLPEngine();
|
128
|
+
engine.responses = responses || {};
|
129
|
+
await engine.loadModel(modelPath);
|
130
|
+
return engine;
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Loads a pre-trained model and configures default actions
|
135
|
+
*/
|
136
|
+
private async loadModel(modelPath: string) {
|
137
|
+
const dock = await dockStart({
|
138
|
+
settings: {
|
139
|
+
nlp: {
|
140
|
+
forceNER: true,
|
141
|
+
languages: ["en"],
|
142
|
+
},
|
143
|
+
},
|
144
|
+
use: ["Basic", "LangEn"],
|
145
|
+
});
|
146
|
+
|
147
|
+
this.manager = dock.get("nlp");
|
148
|
+
await this.manager.load(modelPath);
|
149
|
+
|
150
|
+
// Configure default actions handler
|
151
|
+
this.setupDefaultActions();
|
152
|
+
}
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Setup default actions to handle responses
|
156
|
+
*/
|
157
|
+
private setupDefaultActions() {
|
158
|
+
this.manager.onIntent = async (data: any) => {
|
159
|
+
// Execute registered action if exists
|
160
|
+
if (data.actions?.length > 0) {
|
161
|
+
for (const actionData of data.actions) {
|
162
|
+
const result = await this.executeAction(actionData, data);
|
163
|
+
if (result) {
|
164
|
+
data.actionResult = result;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
// Format response if answer exists
|
170
|
+
if (data.answer && this.responses[data.answer]) {
|
171
|
+
data.jsonResponse = this.formatResponse(
|
172
|
+
this.responses[data.answer],
|
173
|
+
data.actionResult || {}
|
174
|
+
);
|
175
|
+
}
|
176
|
+
|
177
|
+
return data;
|
178
|
+
};
|
179
|
+
}
|
180
|
+
|
181
|
+
/**
|
182
|
+
* Execute a single action
|
183
|
+
*/
|
184
|
+
private async executeAction(actionData: any, context: any): Promise<any> {
|
185
|
+
const { action, parameters } = actionData;
|
186
|
+
const handler = this.manager.actions[action];
|
187
|
+
if (handler) {
|
188
|
+
return handler(context);
|
189
|
+
}
|
190
|
+
return null;
|
191
|
+
}
|
192
|
+
|
193
|
+
/**
|
194
|
+
* Processes natural language input text
|
195
|
+
* @param {string} input - Input text to process
|
196
|
+
* @returns {Promise<any>} Processing result with intent, entities and response
|
197
|
+
*/
|
198
|
+
async process(input: string) {
|
199
|
+
const result = await this.manager.process("en", input);
|
200
|
+
console.log("NLP Engine Result:", result);
|
201
|
+
|
202
|
+
// Si une action est définie, exécuter le handler
|
203
|
+
if (result.intent) {
|
204
|
+
const handler = this.intentHandlers[result.intent.split(".")[1]];
|
205
|
+
if (handler) {
|
206
|
+
const handlerResult = await handler(result);
|
207
|
+
return {
|
208
|
+
...result,
|
209
|
+
...handlerResult,
|
210
|
+
};
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
return result;
|
215
|
+
}
|
216
|
+
|
217
|
+
/**
|
218
|
+
* Trains the NLP model with current corpus
|
219
|
+
* @returns {Promise<void>}
|
220
|
+
*/
|
221
|
+
public async train(): Promise<void> {
|
222
|
+
await this.manager.train();
|
223
|
+
}
|
224
|
+
|
225
|
+
/**
|
226
|
+
* Exports the trained model
|
227
|
+
* @param {boolean} [minified=true] - Whether to minify the exported model
|
228
|
+
* @returns {string} Exported model as string
|
229
|
+
*/
|
230
|
+
public export(minified = true): string {
|
231
|
+
return this.manager.export(minified);
|
232
|
+
}
|
233
|
+
|
234
|
+
/**
|
235
|
+
* Imports a previously trained model
|
236
|
+
* @param {string} data - Model data to import
|
237
|
+
*/
|
238
|
+
public import(data: string): void {
|
239
|
+
this.manager.import(data);
|
240
|
+
}
|
241
|
+
|
242
|
+
/**
|
243
|
+
* Saves the current model to a file
|
244
|
+
* @param {string} [path='./model.json'] - Path to save the model
|
245
|
+
* @returns {Promise<void>}
|
246
|
+
*/
|
247
|
+
public async saveModel(path = "./model.json"): Promise<void> {
|
248
|
+
this.manager.save();
|
249
|
+
this.manager.save("./model.json");
|
250
|
+
}
|
251
|
+
|
252
|
+
/**
|
253
|
+
* Formats response using template and context
|
254
|
+
*/
|
255
|
+
private formatResponse(template: any, context: any): any {
|
256
|
+
const response = JSON.parse(JSON.stringify(template));
|
257
|
+
|
258
|
+
// Format data fields
|
259
|
+
if (response.data) {
|
260
|
+
Object.keys(response.data).forEach((key) => {
|
261
|
+
if (context[key] !== undefined) {
|
262
|
+
response.data[key] = context[key];
|
263
|
+
}
|
264
|
+
});
|
265
|
+
}
|
266
|
+
|
267
|
+
return response;
|
268
|
+
}
|
269
|
+
|
270
|
+
/**
|
271
|
+
* Gets entity value from NLP result
|
272
|
+
* @param {any} data - NLP processing result
|
273
|
+
* @param {string} entityName - Name of the entity to extract
|
274
|
+
* @returns {string|undefined} Entity value if found
|
275
|
+
*/
|
276
|
+
getEntity(data: any, entityName: string): string | undefined {
|
277
|
+
const entity = data.entities?.find((e: any) => e.entity === entityName);
|
278
|
+
return entity ? entity.utteranceText : undefined;
|
279
|
+
}
|
280
|
+
|
281
|
+
/**
|
282
|
+
* Gets entity option from NLP result
|
283
|
+
* @param {any} data - NLP processing result
|
284
|
+
* @param {string} entityName - Name of the entity to extract
|
285
|
+
* @returns {string|undefined} Entity option if found
|
286
|
+
*/
|
287
|
+
getEntityOption(data: any, entityName: string): string | undefined {
|
288
|
+
const entity = data.entities?.find((e: any) => e.entity === entityName);
|
289
|
+
return entity ? entity.option : undefined;
|
290
|
+
}
|
291
|
+
|
292
|
+
/**
|
293
|
+
* Gets recipient entity from NLP result
|
294
|
+
* @param {any} data - NLP processing result
|
295
|
+
* @returns {string|undefined} Recipient value if found
|
296
|
+
*/
|
297
|
+
getRecipient(data: any): string | undefined {
|
298
|
+
const toEntity = data.entities?.find((e: any) => e.entity === "to");
|
299
|
+
return toEntity ? toEntity.utteranceText : undefined;
|
300
|
+
}
|
301
|
+
|
302
|
+
/**
|
303
|
+
* Gets current responses configuration
|
304
|
+
* @returns {Record<string, any>} Current responses
|
305
|
+
*/
|
306
|
+
public getResponses(): Record<string, any> {
|
307
|
+
return this.responses;
|
308
|
+
}
|
309
|
+
|
310
|
+
/**
|
311
|
+
* Gets current corpus configuration
|
312
|
+
* @returns {any} Current corpus
|
313
|
+
*/
|
314
|
+
public getCorpus(): any {
|
315
|
+
return this.manager.corpora;
|
316
|
+
}
|
317
|
+
|
318
|
+
/**
|
319
|
+
* Gets current entities configuration
|
320
|
+
* @returns {any} Current entities configuration
|
321
|
+
*/
|
322
|
+
public getEntities(): any {
|
323
|
+
return this.manager.nerManager?.rules || {};
|
324
|
+
}
|
325
|
+
}
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import { NLPNodeConfig } from "@/interfaces";
|
2
|
+
import { ZodSchema } from "zod";
|
3
|
+
import { NLPEngine } from "./engine";
|
4
|
+
|
5
|
+
/**
|
6
|
+
* NLPNode class handles natural language processing operations with type-safe schema validation
|
7
|
+
* @template T - Zod schema type for validation
|
8
|
+
*/
|
9
|
+
export class NLPNode<T extends ZodSchema> {
|
10
|
+
private engine!: NLPEngine;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Creates an instance of NLPNode
|
14
|
+
* @param {NLPNodeConfig<T>} config - Configuration object for the NLP node
|
15
|
+
*/
|
16
|
+
constructor(private config: NLPNodeConfig<T>) {}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Initializes the NLP engine and sets up intent handlers
|
20
|
+
* @returns {Promise<void>}
|
21
|
+
*/
|
22
|
+
async initialize() {
|
23
|
+
this.engine = await NLPEngine.create(this.config.nlpConfig);
|
24
|
+
console.log("Loaded engine");
|
25
|
+
if (this.config.intentHandlers) {
|
26
|
+
Object.entries(this.config.intentHandlers).forEach(
|
27
|
+
([intent, handler]) => {
|
28
|
+
this.engine.addAction(intent, handler);
|
29
|
+
}
|
30
|
+
);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Processes the input text through the NLP engine
|
36
|
+
* @param {string} input - Text to be processed
|
37
|
+
* @returns {Promise<any>} - Processing result from the engine
|
38
|
+
*/
|
39
|
+
async process(input: string) {
|
40
|
+
console.log("NLP Node processing:", input);
|
41
|
+
const result = await this.engine.process(input);
|
42
|
+
console.log("NLP Node result:", result);
|
43
|
+
return result;
|
44
|
+
}
|
45
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ai.ntellect/core",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.8.0",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"scripts": {
|
@@ -17,8 +17,11 @@
|
|
17
17
|
"author": "Lorcann Rauzduel",
|
18
18
|
"license": "ISC",
|
19
19
|
"dependencies": {
|
20
|
+
"@ai-sdk/openai": "^1.1.15",
|
21
|
+
"@nlpjs/basic": "5.0.0-alpha.5",
|
20
22
|
"@types/node-cron": "^3.0.11",
|
21
|
-
"ai": "^
|
23
|
+
"ai": "^4.1.46",
|
24
|
+
"chalk": "^5.4.1",
|
22
25
|
"node-cron": "^3.0.3",
|
23
26
|
"redis": "^4.7.0",
|
24
27
|
"rxjs": "^7.8.1",
|
@@ -56,12 +56,14 @@ describe("GraphController", () => {
|
|
56
56
|
);
|
57
57
|
|
58
58
|
expect(results).to.have.length(3);
|
59
|
-
expect(results[0].counter).to.equal(10);
|
60
|
-
expect(results[1].counter).to.equal(20);
|
61
|
-
expect(results[2].counter).to.equal(30);
|
62
|
-
expect(results[0].message).to.equal("test1-graph1");
|
63
|
-
expect(results[1].message).to.equal("test2-graph2");
|
64
|
-
expect(results[2].message).to.equal("test3-graph3");
|
59
|
+
expect(results[0].context.counter).to.equal(10);
|
60
|
+
expect(results[1].context.counter).to.equal(20);
|
61
|
+
expect(results[2].context.counter).to.equal(30);
|
62
|
+
expect(results[0].context.message).to.equal("test1-graph1");
|
63
|
+
expect(results[1].context.message).to.equal("test2-graph2");
|
64
|
+
expect(results[2].context.message).to.equal("test3-graph3");
|
65
|
+
expect(results[0].graphName).to.equal("graph1");
|
66
|
+
expect(results[0].nodeName).to.equal("start");
|
65
67
|
});
|
66
68
|
|
67
69
|
it("should handle missing params and params gracefully", async () => {
|
@@ -74,10 +76,10 @@ describe("GraphController", () => {
|
|
74
76
|
);
|
75
77
|
|
76
78
|
expect(results).to.have.length(2);
|
77
|
-
expect(results[0].counter).to.equal(0);
|
78
|
-
expect(results[1].counter).to.equal(0);
|
79
|
-
expect(results[0].message).to.equal("graph1");
|
80
|
-
expect(results[1].message).to.equal("graph2");
|
79
|
+
expect(results[0].context.counter).to.equal(0);
|
80
|
+
expect(results[1].context.counter).to.equal(0);
|
81
|
+
expect(results[0].context.message).to.equal("graph1");
|
82
|
+
expect(results[1].context.message).to.equal("graph2");
|
81
83
|
});
|
82
84
|
});
|
83
85
|
|
@@ -111,8 +113,8 @@ describe("GraphController", () => {
|
|
111
113
|
expect(executionTime).to.be.greaterThan(0);
|
112
114
|
expect(results).to.have.length(5);
|
113
115
|
results.forEach((result, i) => {
|
114
|
-
expect(result.counter).to.equal((i + 1) * 10);
|
115
|
-
expect(result.message).to.equal(`test${i + 1}-graph${i + 1}`);
|
116
|
+
expect(result.context.counter).to.equal((i + 1) * 10);
|
117
|
+
expect(result.context.message).to.equal(`test${i + 1}-graph${i + 1}`);
|
116
118
|
});
|
117
119
|
});
|
118
120
|
|
@@ -175,8 +177,10 @@ describe("GraphController", () => {
|
|
175
177
|
|
176
178
|
const allResults = [...parallelResults, ...sequentialResults];
|
177
179
|
expect(allResults).to.have.length(4);
|
178
|
-
expect(allResults.map((r) => r.counter)).to.deep.equal([
|
179
|
-
|
180
|
+
expect(allResults.map((r) => r.context.counter)).to.deep.equal([
|
181
|
+
10, 20, 30, 40,
|
182
|
+
]);
|
183
|
+
expect(allResults.map((r) => r.context.message)).to.deep.equal([
|
180
184
|
"parallel1-graph1",
|
181
185
|
"parallel2-graph2",
|
182
186
|
"seq1-graph3",
|
package/test/graph/index.test.ts
CHANGED
@@ -6,7 +6,7 @@ import { z } from "zod";
|
|
6
6
|
import { GraphController } from "../../graph/controller";
|
7
7
|
import { GraphFlow } from "../../graph/index";
|
8
8
|
import { NodeParams } from "../../graph/node";
|
9
|
-
import {
|
9
|
+
import { GraphConfig, GraphContext, GraphNodeConfig } from "../../types";
|
10
10
|
|
11
11
|
use(chaiAsPromised);
|
12
12
|
|
@@ -540,8 +540,8 @@ describe("GraphFlow", function () {
|
|
540
540
|
[{}, {}]
|
541
541
|
);
|
542
542
|
|
543
|
-
expect(results[0].value).to.equal(2); // Graph1: 1 * 2
|
544
|
-
expect(results[1].value).to.equal(5); // Graph2: 2 + 3
|
543
|
+
expect(results[0].context.value).to.equal(2); // Graph1: 1 * 2
|
544
|
+
expect(results[1].context.value).to.equal(5); // Graph2: 2 + 3
|
545
545
|
});
|
546
546
|
|
547
547
|
/**
|
@@ -587,22 +587,24 @@ describe("GraphFlow", function () {
|
|
587
587
|
[{}, {}]
|
588
588
|
);
|
589
589
|
|
590
|
-
expect(results[0].value).to.equal(2); // Graph1: 1 * 2
|
591
|
-
expect(results[1].value).to.equal(5); // Graph2: 3 + 2
|
590
|
+
expect(results[0].context.value).to.equal(2); // Graph1: 1 * 2
|
591
|
+
expect(results[1].context.value).to.equal(5); // Graph2: 3 + 2
|
592
592
|
});
|
593
593
|
|
594
594
|
/**
|
595
595
|
* Tests single event waiting functionality
|
596
596
|
*/
|
597
597
|
it("should wait for a single event before continuing", async function () {
|
598
|
-
this.timeout(5000);
|
599
|
-
|
600
598
|
const waitingNode: GraphNodeConfig<TestSchema> = {
|
601
599
|
name: "waitingNode",
|
602
600
|
execute: async (context: GraphContext<typeof TestSchema>) => {
|
603
601
|
context.value = 1;
|
604
602
|
},
|
605
|
-
|
603
|
+
when: {
|
604
|
+
events: ["someEvent"],
|
605
|
+
timeout: 1000,
|
606
|
+
strategy: { type: "single" },
|
607
|
+
},
|
606
608
|
next: ["finalNode"],
|
607
609
|
};
|
608
610
|
|
package/test/graph/node.test.ts
CHANGED
@@ -512,10 +512,10 @@ describe("GraphNode", () => {
|
|
512
512
|
const nodes = new Map();
|
513
513
|
nodes.set("waitForEventsNode", {
|
514
514
|
name: "waitForEventsNode",
|
515
|
-
|
515
|
+
when: {
|
516
516
|
events: ["event1", "event2"],
|
517
517
|
timeout: 1000,
|
518
|
-
strategy: "all",
|
518
|
+
strategy: { type: "all" },
|
519
519
|
},
|
520
520
|
execute: async (context: TestContext) => {
|
521
521
|
context.message = "Events received";
|
@@ -554,10 +554,10 @@ describe("GraphNode", () => {
|
|
554
554
|
const nodes = new Map();
|
555
555
|
nodes.set("timeoutNode", {
|
556
556
|
name: "timeoutNode",
|
557
|
-
|
557
|
+
when: {
|
558
558
|
events: ["event1", "event2"],
|
559
559
|
timeout: 100,
|
560
|
-
strategy: "all",
|
560
|
+
strategy: { type: "all" },
|
561
561
|
},
|
562
562
|
execute: async (context: TestContext) => {
|
563
563
|
context.message = "Should not execute";
|
@@ -571,7 +571,6 @@ describe("GraphNode", () => {
|
|
571
571
|
eventSubject,
|
572
572
|
stateSubject
|
573
573
|
);
|
574
|
-
|
575
574
|
await expect(
|
576
575
|
node.executeNode("timeoutNode", { counter: 0, message: "Hello" }, null)
|
577
576
|
).to.be.rejectedWith("Timeout waiting for events");
|
@@ -581,10 +580,10 @@ describe("GraphNode", () => {
|
|
581
580
|
const nodes = new Map();
|
582
581
|
nodes.set("partialEventsNode", {
|
583
582
|
name: "partialEventsNode",
|
584
|
-
|
583
|
+
when: {
|
585
584
|
events: ["event1", "event2"],
|
586
585
|
timeout: 1000,
|
587
|
-
strategy: "all",
|
586
|
+
strategy: { type: "all" },
|
588
587
|
},
|
589
588
|
execute: async (context: TestContext) => {
|
590
589
|
context.message = "All events received";
|
@@ -598,14 +597,12 @@ describe("GraphNode", () => {
|
|
598
597
|
eventSubject,
|
599
598
|
stateSubject
|
600
599
|
);
|
601
|
-
|
602
600
|
const execution = node.executeNode(
|
603
601
|
"partialEventsNode",
|
604
602
|
{ counter: 0, message: "Hello" },
|
605
603
|
null
|
606
604
|
);
|
607
605
|
|
608
|
-
// N'émettre qu'un seul événement
|
609
606
|
setTimeout(() => {
|
610
607
|
eventEmitter.emit("event1", { data: "test1" });
|
611
608
|
}, 100);
|
@@ -617,13 +614,20 @@ describe("GraphNode", () => {
|
|
617
614
|
const nodes = new Map();
|
618
615
|
nodes.set("correlatedEventsNode", {
|
619
616
|
name: "correlatedEventsNode",
|
620
|
-
|
617
|
+
when: {
|
621
618
|
events: ["payment", "stock"],
|
622
619
|
timeout: 1000,
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
620
|
+
strategy: {
|
621
|
+
type: "correlate",
|
622
|
+
correlation: (events: Array<{ type: string; payload?: any }>) => {
|
623
|
+
const paymentEvent = events.find(
|
624
|
+
(e: { type: string }) => e.type === "payment"
|
625
|
+
);
|
626
|
+
const stockEvent = events.find(
|
627
|
+
(e: { type: string }) => e.type === "stock"
|
628
|
+
);
|
629
|
+
return paymentEvent?.payload?.id === stockEvent?.payload?.id;
|
630
|
+
},
|
627
631
|
},
|
628
632
|
},
|
629
633
|
execute: (context: TestContext) => {
|