@baselineos/protocol-core 1.0.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/.turbo/turbo-build.log +14 -0
- package/.turbo/turbo-test.log +15 -0
- package/CHANGELOG.md +49 -0
- package/LICENSE +17 -0
- package/README.md +18 -0
- package/dist/index.d.ts +1322 -0
- package/dist/index.js +2653 -0
- package/package.json +31 -0
- package/src/__tests__/functional.test.ts +269 -0
- package/src/__tests__/smoke.test.ts +23 -0
- package/src/chromadb.d.ts +9 -0
- package/src/index.ts +117 -0
- package/src/knowledge/knowledge-graph.ts +1441 -0
- package/src/knowledge/vector-store.ts +722 -0
- package/src/lang/lang.ts +278 -0
- package/src/lexicon/lexicon.ts +414 -0
- package/src/parser/grammar.ts +240 -0
- package/src/parser/parser.ts +420 -0
- package/src/types/index.ts +799 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,1441 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
|
|
3
|
+
// ── Interfaces ──────────────────────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
export interface KnowledgeNode {
|
|
6
|
+
id: string;
|
|
7
|
+
type: string;
|
|
8
|
+
name: string;
|
|
9
|
+
level: number;
|
|
10
|
+
properties: Record<string, unknown>;
|
|
11
|
+
metadata: {
|
|
12
|
+
created: number;
|
|
13
|
+
lastModified: number;
|
|
14
|
+
version: number;
|
|
15
|
+
confidence: number;
|
|
16
|
+
};
|
|
17
|
+
embeddings: number[];
|
|
18
|
+
tags: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface KnowledgeRelationship {
|
|
22
|
+
id: string;
|
|
23
|
+
from: string;
|
|
24
|
+
to: string;
|
|
25
|
+
type: string;
|
|
26
|
+
weight: number;
|
|
27
|
+
properties: Record<string, unknown>;
|
|
28
|
+
metadata: {
|
|
29
|
+
created: number;
|
|
30
|
+
lastModified: number;
|
|
31
|
+
confidence: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface KnowledgeAgent {
|
|
36
|
+
id: string;
|
|
37
|
+
type: string;
|
|
38
|
+
capabilities: string[];
|
|
39
|
+
state: string;
|
|
40
|
+
knowledge: Map<string, unknown>;
|
|
41
|
+
reasoning: ReasoningEngine;
|
|
42
|
+
tools: string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ReasoningEngine {
|
|
46
|
+
type: string;
|
|
47
|
+
rules: string[];
|
|
48
|
+
context: Map<string, unknown>;
|
|
49
|
+
history: unknown[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface KnowledgeChain {
|
|
53
|
+
id: string;
|
|
54
|
+
type: string;
|
|
55
|
+
steps: ChainStep[];
|
|
56
|
+
state: string;
|
|
57
|
+
executionHistory: ChainExecution[];
|
|
58
|
+
performance: {
|
|
59
|
+
totalExecutions: number;
|
|
60
|
+
averageExecutionTime: number;
|
|
61
|
+
successRate: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ChainStep {
|
|
66
|
+
tool: string;
|
|
67
|
+
parameters: Record<string, unknown>;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ChainExecution {
|
|
71
|
+
input: unknown;
|
|
72
|
+
output: unknown;
|
|
73
|
+
executionTime: number;
|
|
74
|
+
timestamp: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface KnowledgeTool {
|
|
78
|
+
id: string;
|
|
79
|
+
type: string;
|
|
80
|
+
capabilities: string[];
|
|
81
|
+
state: string;
|
|
82
|
+
usage: {
|
|
83
|
+
totalUses: number;
|
|
84
|
+
lastUsed: number | null;
|
|
85
|
+
successRate: number;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface QueryResult {
|
|
90
|
+
success: boolean;
|
|
91
|
+
query?: string;
|
|
92
|
+
results?: unknown[];
|
|
93
|
+
error?: string;
|
|
94
|
+
metadata?: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface KnowledgeGraphConfig {
|
|
98
|
+
maxNodes?: number;
|
|
99
|
+
maxRelationships?: number;
|
|
100
|
+
knowledgeRetention?: number;
|
|
101
|
+
reasoningDepth?: number;
|
|
102
|
+
vectorStore?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface KnowledgeGraphMetrics {
|
|
106
|
+
totalNodes: number;
|
|
107
|
+
totalRelationships: number;
|
|
108
|
+
knowledgeQueries: number;
|
|
109
|
+
reasoningOperations: number;
|
|
110
|
+
lastOptimization: number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface NodeData {
|
|
114
|
+
id?: string;
|
|
115
|
+
type?: string;
|
|
116
|
+
name?: string;
|
|
117
|
+
level?: number;
|
|
118
|
+
properties?: Record<string, unknown>;
|
|
119
|
+
confidence?: number;
|
|
120
|
+
embeddings?: number[];
|
|
121
|
+
tags?: string[];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
interface RelationshipData {
|
|
125
|
+
id?: string;
|
|
126
|
+
from: string;
|
|
127
|
+
to: string;
|
|
128
|
+
type?: string;
|
|
129
|
+
weight?: number;
|
|
130
|
+
properties?: Record<string, unknown>;
|
|
131
|
+
confidence?: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface QueryOptions {
|
|
135
|
+
type?: string;
|
|
136
|
+
depth?: number;
|
|
137
|
+
limit?: number;
|
|
138
|
+
persona?: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── KnowledgeGraphEngine ────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
export class KnowledgeGraphEngine extends EventEmitter {
|
|
144
|
+
private config: Required<KnowledgeGraphConfig>;
|
|
145
|
+
private nodes: Map<string, KnowledgeNode>;
|
|
146
|
+
private relationships: Map<string, KnowledgeRelationship>;
|
|
147
|
+
private personaKnowledge: Map<string, Map<string, unknown>>;
|
|
148
|
+
private knowledgePatterns: Map<string, unknown[]>;
|
|
149
|
+
private agents: Map<string, KnowledgeAgent>;
|
|
150
|
+
private chains: Map<string, KnowledgeChain>;
|
|
151
|
+
private tools: Map<string, KnowledgeTool>;
|
|
152
|
+
private metrics: KnowledgeGraphMetrics;
|
|
153
|
+
|
|
154
|
+
constructor(config: KnowledgeGraphConfig = {}) {
|
|
155
|
+
super();
|
|
156
|
+
|
|
157
|
+
this.config = {
|
|
158
|
+
maxNodes: config.maxNodes ?? 10000,
|
|
159
|
+
maxRelationships: config.maxRelationships ?? 50000,
|
|
160
|
+
knowledgeRetention: config.knowledgeRetention ?? 0.95,
|
|
161
|
+
reasoningDepth: config.reasoningDepth ?? 5,
|
|
162
|
+
vectorStore: config.vectorStore ?? {},
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
this.nodes = new Map();
|
|
166
|
+
this.relationships = new Map();
|
|
167
|
+
this.personaKnowledge = new Map();
|
|
168
|
+
this.knowledgePatterns = new Map();
|
|
169
|
+
this.agents = new Map();
|
|
170
|
+
this.chains = new Map();
|
|
171
|
+
this.tools = new Map();
|
|
172
|
+
|
|
173
|
+
this.metrics = {
|
|
174
|
+
totalNodes: 0,
|
|
175
|
+
totalRelationships: 0,
|
|
176
|
+
knowledgeQueries: 0,
|
|
177
|
+
reasoningOperations: 0,
|
|
178
|
+
lastOptimization: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ── Initialization ──────────────────────────────────────────────────────────
|
|
183
|
+
|
|
184
|
+
async initializeEngine(): Promise<void> {
|
|
185
|
+
console.log('[KnowledgeGraph] Initializing knowledge graph engine...');
|
|
186
|
+
|
|
187
|
+
this.initializeKnowledgeStructures();
|
|
188
|
+
this.initializeAgents();
|
|
189
|
+
this.initializeChains();
|
|
190
|
+
this.initializeTools();
|
|
191
|
+
|
|
192
|
+
console.log('[KnowledgeGraph] Knowledge graph engine initialized.');
|
|
193
|
+
this.emit('initialized', { metrics: this.metrics });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private initializeKnowledgeStructures(): void {
|
|
197
|
+
// Create root knowledge nodes
|
|
198
|
+
const rootNode = this.createNode({
|
|
199
|
+
id: 'root',
|
|
200
|
+
type: 'root',
|
|
201
|
+
name: 'Knowledge Root',
|
|
202
|
+
level: 0,
|
|
203
|
+
properties: { description: 'Root node of the knowledge graph' },
|
|
204
|
+
confidence: 1.0,
|
|
205
|
+
tags: ['root', 'system'],
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const conceptNode = this.createNode({
|
|
209
|
+
id: 'concepts',
|
|
210
|
+
type: 'category',
|
|
211
|
+
name: 'Concepts',
|
|
212
|
+
level: 1,
|
|
213
|
+
properties: { description: 'Abstract concepts and ideas' },
|
|
214
|
+
confidence: 1.0,
|
|
215
|
+
tags: ['category', 'concepts'],
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const entityNode = this.createNode({
|
|
219
|
+
id: 'entities',
|
|
220
|
+
type: 'category',
|
|
221
|
+
name: 'Entities',
|
|
222
|
+
level: 1,
|
|
223
|
+
properties: { description: 'Concrete entities and objects' },
|
|
224
|
+
confidence: 1.0,
|
|
225
|
+
tags: ['category', 'entities'],
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const processNode = this.createNode({
|
|
229
|
+
id: 'processes',
|
|
230
|
+
type: 'category',
|
|
231
|
+
name: 'Processes',
|
|
232
|
+
level: 1,
|
|
233
|
+
properties: { description: 'Actions, workflows, and procedures' },
|
|
234
|
+
confidence: 1.0,
|
|
235
|
+
tags: ['category', 'processes'],
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const relationNode = this.createNode({
|
|
239
|
+
id: 'relations',
|
|
240
|
+
type: 'category',
|
|
241
|
+
name: 'Relations',
|
|
242
|
+
level: 1,
|
|
243
|
+
properties: { description: 'Relationships and connections' },
|
|
244
|
+
confidence: 1.0,
|
|
245
|
+
tags: ['category', 'relations'],
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Create root relationships
|
|
249
|
+
this.createRelationship({ from: rootNode.id, to: conceptNode.id, type: 'contains', weight: 1.0 });
|
|
250
|
+
this.createRelationship({ from: rootNode.id, to: entityNode.id, type: 'contains', weight: 1.0 });
|
|
251
|
+
this.createRelationship({ from: rootNode.id, to: processNode.id, type: 'contains', weight: 1.0 });
|
|
252
|
+
this.createRelationship({ from: rootNode.id, to: relationNode.id, type: 'contains', weight: 1.0 });
|
|
253
|
+
|
|
254
|
+
console.log('[KnowledgeGraph] Knowledge structures initialized with root nodes.');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private initializeAgents(): void {
|
|
258
|
+
const agentTypes: string[] = [
|
|
259
|
+
'knowledge-curator',
|
|
260
|
+
'pattern-recognizer',
|
|
261
|
+
'relationship-builder',
|
|
262
|
+
'query-optimizer',
|
|
263
|
+
'learning-agent',
|
|
264
|
+
];
|
|
265
|
+
|
|
266
|
+
for (const agentType of agentTypes) {
|
|
267
|
+
this.createAgent(agentType);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
console.log(`[KnowledgeGraph] Initialized ${agentTypes.length} knowledge agents.`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private initializeChains(): void {
|
|
274
|
+
const chainTypes: string[] = [
|
|
275
|
+
'knowledge-acquisition',
|
|
276
|
+
'pattern-detection',
|
|
277
|
+
'relationship-inference',
|
|
278
|
+
'knowledge-optimization',
|
|
279
|
+
'learning-pipeline',
|
|
280
|
+
];
|
|
281
|
+
|
|
282
|
+
for (const chainType of chainTypes) {
|
|
283
|
+
this.createChain(chainType);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
console.log(`[KnowledgeGraph] Initialized ${chainTypes.length} knowledge chains.`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private initializeTools(): void {
|
|
290
|
+
const toolTypes: string[] = [
|
|
291
|
+
'knowledge-query',
|
|
292
|
+
'pattern-matcher',
|
|
293
|
+
'relationship-analyzer',
|
|
294
|
+
'graph-optimizer',
|
|
295
|
+
'learning-analyzer',
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
for (const toolType of toolTypes) {
|
|
299
|
+
this.createTool(toolType);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
console.log(`[KnowledgeGraph] Initialized ${toolTypes.length} knowledge tools.`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ── Node / Relationship / Agent / Chain / Tool Creation ─────────────────────
|
|
306
|
+
|
|
307
|
+
createNode(nodeData: NodeData): KnowledgeNode {
|
|
308
|
+
const id = nodeData.id ?? `node-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
309
|
+
|
|
310
|
+
const node: KnowledgeNode = {
|
|
311
|
+
id,
|
|
312
|
+
type: nodeData.type ?? 'generic',
|
|
313
|
+
name: nodeData.name ?? id,
|
|
314
|
+
level: nodeData.level ?? 0,
|
|
315
|
+
properties: nodeData.properties ?? {},
|
|
316
|
+
metadata: {
|
|
317
|
+
created: Date.now(),
|
|
318
|
+
lastModified: Date.now(),
|
|
319
|
+
version: 1,
|
|
320
|
+
confidence: nodeData.confidence ?? 0.5,
|
|
321
|
+
},
|
|
322
|
+
embeddings: nodeData.embeddings ?? [],
|
|
323
|
+
tags: nodeData.tags ?? [],
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
if (this.nodes.size >= this.config.maxNodes) {
|
|
327
|
+
this.pruneNodes();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
this.nodes.set(id, node);
|
|
331
|
+
this.metrics.totalNodes = this.nodes.size;
|
|
332
|
+
|
|
333
|
+
this.emit('nodeCreated', { node });
|
|
334
|
+
return node;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
createRelationship(relData: RelationshipData): KnowledgeRelationship {
|
|
338
|
+
const id = relData.id ?? `rel-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
339
|
+
|
|
340
|
+
const relationship: KnowledgeRelationship = {
|
|
341
|
+
id,
|
|
342
|
+
from: relData.from,
|
|
343
|
+
to: relData.to,
|
|
344
|
+
type: relData.type ?? 'related',
|
|
345
|
+
weight: relData.weight ?? 0.5,
|
|
346
|
+
properties: relData.properties ?? {},
|
|
347
|
+
metadata: {
|
|
348
|
+
created: Date.now(),
|
|
349
|
+
lastModified: Date.now(),
|
|
350
|
+
confidence: relData.confidence ?? 0.5,
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
if (this.relationships.size >= this.config.maxRelationships) {
|
|
355
|
+
this.pruneRelationships();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
this.relationships.set(id, relationship);
|
|
359
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
360
|
+
|
|
361
|
+
this.emit('relationshipCreated', { relationship });
|
|
362
|
+
return relationship;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
createAgent(agentType: string): KnowledgeAgent {
|
|
366
|
+
const id = `agent-${agentType}-${Date.now()}`;
|
|
367
|
+
|
|
368
|
+
const agent: KnowledgeAgent = {
|
|
369
|
+
id,
|
|
370
|
+
type: agentType,
|
|
371
|
+
capabilities: this.getAgentCapabilities(agentType),
|
|
372
|
+
state: 'idle',
|
|
373
|
+
knowledge: new Map(),
|
|
374
|
+
reasoning: this.createReasoningEngine(agentType),
|
|
375
|
+
tools: this.getAgentTools(agentType),
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
this.agents.set(id, agent);
|
|
379
|
+
this.emit('agentCreated', { agent });
|
|
380
|
+
return agent;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
createChain(chainType: string): KnowledgeChain {
|
|
384
|
+
const id = `chain-${chainType}-${Date.now()}`;
|
|
385
|
+
|
|
386
|
+
const chain: KnowledgeChain = {
|
|
387
|
+
id,
|
|
388
|
+
type: chainType,
|
|
389
|
+
steps: this.getChainSteps(chainType),
|
|
390
|
+
state: 'idle',
|
|
391
|
+
executionHistory: [],
|
|
392
|
+
performance: {
|
|
393
|
+
totalExecutions: 0,
|
|
394
|
+
averageExecutionTime: 0,
|
|
395
|
+
successRate: 1.0,
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
this.chains.set(id, chain);
|
|
400
|
+
this.emit('chainCreated', { chain });
|
|
401
|
+
return chain;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
createTool(toolType: string): KnowledgeTool {
|
|
405
|
+
const id = `tool-${toolType}-${Date.now()}`;
|
|
406
|
+
|
|
407
|
+
const tool: KnowledgeTool = {
|
|
408
|
+
id,
|
|
409
|
+
type: toolType,
|
|
410
|
+
capabilities: this.getToolCapabilities(toolType),
|
|
411
|
+
state: 'ready',
|
|
412
|
+
usage: {
|
|
413
|
+
totalUses: 0,
|
|
414
|
+
lastUsed: null,
|
|
415
|
+
successRate: 1.0,
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
this.tools.set(id, tool);
|
|
420
|
+
this.emit('toolCreated', { tool });
|
|
421
|
+
return tool;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ── Querying ────────────────────────────────────────────────────────────────
|
|
425
|
+
|
|
426
|
+
async queryKnowledge(query: string, options: QueryOptions = {}): Promise<QueryResult> {
|
|
427
|
+
this.metrics.knowledgeQueries++;
|
|
428
|
+
|
|
429
|
+
const queryType = options.type ?? 'semantic';
|
|
430
|
+
const depth = options.depth ?? this.config.reasoningDepth;
|
|
431
|
+
|
|
432
|
+
try {
|
|
433
|
+
let results: unknown[];
|
|
434
|
+
|
|
435
|
+
switch (queryType) {
|
|
436
|
+
case 'semantic':
|
|
437
|
+
results = this.semanticQuery(query, depth);
|
|
438
|
+
break;
|
|
439
|
+
case 'pattern':
|
|
440
|
+
results = this.patternQuery(query, depth);
|
|
441
|
+
break;
|
|
442
|
+
case 'relationship':
|
|
443
|
+
results = this.relationshipQuery(query, depth);
|
|
444
|
+
break;
|
|
445
|
+
case 'persona':
|
|
446
|
+
results = this.personaQuery(query, depth, options.persona);
|
|
447
|
+
break;
|
|
448
|
+
default:
|
|
449
|
+
results = this.semanticQuery(query, depth);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const reasonedResults = this.applyReasoning(results, query, depth);
|
|
453
|
+
|
|
454
|
+
this.emit('queryCompleted', { query, results: reasonedResults });
|
|
455
|
+
|
|
456
|
+
return {
|
|
457
|
+
success: true,
|
|
458
|
+
query,
|
|
459
|
+
results: reasonedResults,
|
|
460
|
+
metadata: {
|
|
461
|
+
type: queryType,
|
|
462
|
+
depth,
|
|
463
|
+
totalResults: reasonedResults.length,
|
|
464
|
+
queryTime: Date.now(),
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
} catch (error) {
|
|
468
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
469
|
+
console.log(`[KnowledgeGraph] Query failed: ${message}`);
|
|
470
|
+
return {
|
|
471
|
+
success: false,
|
|
472
|
+
query,
|
|
473
|
+
error: message,
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private semanticQuery(query: string, depth: number): unknown[] {
|
|
479
|
+
const results: unknown[] = [];
|
|
480
|
+
const visited = new Set<string>();
|
|
481
|
+
const queue: Array<{ nodeId: string; currentDepth: number }> = [];
|
|
482
|
+
|
|
483
|
+
// Start BFS from all root-level nodes
|
|
484
|
+
for (const [nodeId, node] of this.nodes) {
|
|
485
|
+
if (node.level === 0 || node.level === 1) {
|
|
486
|
+
queue.push({ nodeId, currentDepth: 0 });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
while (queue.length > 0) {
|
|
491
|
+
const item = queue.shift();
|
|
492
|
+
if (!item) break;
|
|
493
|
+
|
|
494
|
+
const { nodeId, currentDepth } = item;
|
|
495
|
+
|
|
496
|
+
if (visited.has(nodeId) || currentDepth > depth) continue;
|
|
497
|
+
visited.add(nodeId);
|
|
498
|
+
|
|
499
|
+
const node = this.nodes.get(nodeId);
|
|
500
|
+
if (!node) continue;
|
|
501
|
+
|
|
502
|
+
if (this.matchesQuery(node, query)) {
|
|
503
|
+
const relevance = this.calculateRelevance(node, query);
|
|
504
|
+
results.push({
|
|
505
|
+
node,
|
|
506
|
+
relevance,
|
|
507
|
+
depth: currentDepth,
|
|
508
|
+
path: this.findPathToNode(nodeId),
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Enqueue connected nodes
|
|
513
|
+
const connected = this.getConnectedNodes(nodeId);
|
|
514
|
+
for (const connectedId of connected) {
|
|
515
|
+
if (!visited.has(connectedId)) {
|
|
516
|
+
queue.push({ nodeId: connectedId, currentDepth: currentDepth + 1 });
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Sort by relevance descending
|
|
522
|
+
results.sort((a: unknown, b: unknown) => {
|
|
523
|
+
const aRel = (a as Record<string, unknown>).relevance as number;
|
|
524
|
+
const bRel = (b as Record<string, unknown>).relevance as number;
|
|
525
|
+
return bRel - aRel;
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
return results;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
private patternQuery(query: string, depth: number): unknown[] {
|
|
532
|
+
const results: unknown[] = [];
|
|
533
|
+
|
|
534
|
+
for (const [patternKey, patterns] of this.knowledgePatterns) {
|
|
535
|
+
const lowerKey = patternKey.toLowerCase();
|
|
536
|
+
const lowerQuery = query.toLowerCase();
|
|
537
|
+
|
|
538
|
+
if (lowerKey.includes(lowerQuery) || lowerQuery.includes(lowerKey)) {
|
|
539
|
+
for (const pattern of patterns) {
|
|
540
|
+
results.push({
|
|
541
|
+
pattern,
|
|
542
|
+
patternKey,
|
|
543
|
+
relevance: this.calculateStringRelevance(patternKey, query),
|
|
544
|
+
depth: 0,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Also traverse nodes looking for pattern matches
|
|
551
|
+
for (const [, node] of this.nodes) {
|
|
552
|
+
if (node.tags.some((tag: string) => query.toLowerCase().includes(tag.toLowerCase()))) {
|
|
553
|
+
results.push({
|
|
554
|
+
node,
|
|
555
|
+
relevance: this.calculateRelevance(node, query),
|
|
556
|
+
depth: 0,
|
|
557
|
+
matchType: 'tag-pattern',
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
results.sort((a: unknown, b: unknown) => {
|
|
563
|
+
const aRel = (a as Record<string, unknown>).relevance as number;
|
|
564
|
+
const bRel = (b as Record<string, unknown>).relevance as number;
|
|
565
|
+
return bRel - aRel;
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
return results.slice(0, depth * 10);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
private relationshipQuery(query: string, depth: number): unknown[] {
|
|
572
|
+
const results: unknown[] = [];
|
|
573
|
+
|
|
574
|
+
for (const [, relationship] of this.relationships) {
|
|
575
|
+
const fromNode = this.nodes.get(relationship.from);
|
|
576
|
+
const toNode = this.nodes.get(relationship.to);
|
|
577
|
+
|
|
578
|
+
if (!fromNode || !toNode) continue;
|
|
579
|
+
|
|
580
|
+
const fromMatch = this.matchesQuery(fromNode, query);
|
|
581
|
+
const toMatch = this.matchesQuery(toNode, query);
|
|
582
|
+
|
|
583
|
+
if (fromMatch || toMatch) {
|
|
584
|
+
results.push({
|
|
585
|
+
relationship,
|
|
586
|
+
fromNode,
|
|
587
|
+
toNode,
|
|
588
|
+
relevance: (
|
|
589
|
+
this.calculateRelevance(fromNode, query) +
|
|
590
|
+
this.calculateRelevance(toNode, query)
|
|
591
|
+
) / 2,
|
|
592
|
+
depth: 0,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
results.sort((a: unknown, b: unknown) => {
|
|
598
|
+
const aRel = (a as Record<string, unknown>).relevance as number;
|
|
599
|
+
const bRel = (b as Record<string, unknown>).relevance as number;
|
|
600
|
+
return bRel - aRel;
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
return results.slice(0, depth * 10);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
private personaQuery(query: string, depth: number, persona?: string): unknown[] {
|
|
607
|
+
const results: unknown[] = [];
|
|
608
|
+
|
|
609
|
+
if (persona && this.personaKnowledge.has(persona)) {
|
|
610
|
+
const pKnowledge = this.personaKnowledge.get(persona)!;
|
|
611
|
+
for (const [key, value] of pKnowledge) {
|
|
612
|
+
if (key.toLowerCase().includes(query.toLowerCase()) || query.toLowerCase().includes(key.toLowerCase())) {
|
|
613
|
+
results.push({
|
|
614
|
+
key,
|
|
615
|
+
value,
|
|
616
|
+
persona,
|
|
617
|
+
relevance: this.calculateStringRelevance(key, query),
|
|
618
|
+
depth: 0,
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
} else {
|
|
623
|
+
// Search across all persona knowledge
|
|
624
|
+
for (const [personaId, pKnowledge] of this.personaKnowledge) {
|
|
625
|
+
for (const [key, value] of pKnowledge) {
|
|
626
|
+
if (key.toLowerCase().includes(query.toLowerCase()) || query.toLowerCase().includes(key.toLowerCase())) {
|
|
627
|
+
results.push({
|
|
628
|
+
key,
|
|
629
|
+
value,
|
|
630
|
+
persona: personaId,
|
|
631
|
+
relevance: this.calculateStringRelevance(key, query),
|
|
632
|
+
depth: 0,
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
results.sort((a: unknown, b: unknown) => {
|
|
640
|
+
const aRel = (a as Record<string, unknown>).relevance as number;
|
|
641
|
+
const bRel = (b as Record<string, unknown>).relevance as number;
|
|
642
|
+
return bRel - aRel;
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
return results.slice(0, depth * 10);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// ── Reasoning ───────────────────────────────────────────────────────────────
|
|
649
|
+
|
|
650
|
+
private applyReasoning(results: unknown[], query: string, depth: number): unknown[] {
|
|
651
|
+
this.metrics.reasoningOperations++;
|
|
652
|
+
|
|
653
|
+
if (results.length === 0) return results;
|
|
654
|
+
|
|
655
|
+
// Apply confidence filtering
|
|
656
|
+
const filtered = results.filter((result: unknown) => {
|
|
657
|
+
const r = result as Record<string, unknown>;
|
|
658
|
+
const relevance = (r.relevance as number) ?? 0;
|
|
659
|
+
return relevance >= (1.0 - this.config.knowledgeRetention);
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// Apply depth-based weighting
|
|
663
|
+
const weighted = filtered.map((result: unknown) => {
|
|
664
|
+
const r = result as Record<string, unknown>;
|
|
665
|
+
const d = (r.depth as number) ?? 0;
|
|
666
|
+
const relevance = (r.relevance as number) ?? 0;
|
|
667
|
+
const depthWeight = 1.0 / (1.0 + d * 0.1);
|
|
668
|
+
return {
|
|
669
|
+
...r,
|
|
670
|
+
adjustedRelevance: relevance * depthWeight,
|
|
671
|
+
};
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
// Sort by adjusted relevance
|
|
675
|
+
weighted.sort((a, b) => {
|
|
676
|
+
return (b.adjustedRelevance as number) - (a.adjustedRelevance as number);
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// Apply reasoning depth limit
|
|
680
|
+
const limited = weighted.slice(0, depth * 20);
|
|
681
|
+
|
|
682
|
+
this.emit('reasoningApplied', { query, inputCount: results.length, outputCount: limited.length });
|
|
683
|
+
|
|
684
|
+
return limited;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// ── Chain Execution ─────────────────────────────────────────────────────────
|
|
688
|
+
|
|
689
|
+
async executeChain(chain: KnowledgeChain, input: unknown): Promise<unknown> {
|
|
690
|
+
const startTime = Date.now();
|
|
691
|
+
chain.state = 'executing';
|
|
692
|
+
|
|
693
|
+
let currentInput = input;
|
|
694
|
+
|
|
695
|
+
try {
|
|
696
|
+
for (const step of chain.steps) {
|
|
697
|
+
currentInput = await this.executeStep(step, currentInput);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const executionTime = Date.now() - startTime;
|
|
701
|
+
|
|
702
|
+
chain.executionHistory.push({
|
|
703
|
+
input,
|
|
704
|
+
output: currentInput,
|
|
705
|
+
executionTime,
|
|
706
|
+
timestamp: Date.now(),
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
chain.performance.totalExecutions++;
|
|
710
|
+
chain.performance.averageExecutionTime =
|
|
711
|
+
(chain.performance.averageExecutionTime * (chain.performance.totalExecutions - 1) + executionTime) /
|
|
712
|
+
chain.performance.totalExecutions;
|
|
713
|
+
chain.performance.successRate =
|
|
714
|
+
(chain.performance.successRate * (chain.performance.totalExecutions - 1) + 1.0) /
|
|
715
|
+
chain.performance.totalExecutions;
|
|
716
|
+
|
|
717
|
+
chain.state = 'idle';
|
|
718
|
+
|
|
719
|
+
this.emit('chainExecuted', { chainId: chain.id, executionTime });
|
|
720
|
+
return currentInput;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
chain.state = 'error';
|
|
723
|
+
chain.performance.totalExecutions++;
|
|
724
|
+
chain.performance.successRate =
|
|
725
|
+
(chain.performance.successRate * (chain.performance.totalExecutions - 1)) /
|
|
726
|
+
chain.performance.totalExecutions;
|
|
727
|
+
|
|
728
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
729
|
+
this.emit('chainError', { chainId: chain.id, error: message });
|
|
730
|
+
throw error;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
private async executeStep(step: ChainStep, input: unknown): Promise<unknown> {
|
|
735
|
+
const toolId = step.tool;
|
|
736
|
+
let tool: KnowledgeTool | undefined;
|
|
737
|
+
|
|
738
|
+
for (const [, t] of this.tools) {
|
|
739
|
+
if (t.type === toolId || t.id === toolId) {
|
|
740
|
+
tool = t;
|
|
741
|
+
break;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
if (!tool) {
|
|
746
|
+
console.log(`[KnowledgeGraph] Tool not found for step: ${toolId}, passing input through.`);
|
|
747
|
+
return input;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return this.executeTool(tool, step, input);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
private async executeTool(tool: KnowledgeTool, step: ChainStep, input: unknown): Promise<unknown> {
|
|
754
|
+
tool.state = 'executing';
|
|
755
|
+
tool.usage.totalUses++;
|
|
756
|
+
tool.usage.lastUsed = Date.now();
|
|
757
|
+
|
|
758
|
+
let result: unknown;
|
|
759
|
+
|
|
760
|
+
try {
|
|
761
|
+
switch (tool.type) {
|
|
762
|
+
case 'knowledge-query':
|
|
763
|
+
result = this.executeKnowledgeQuery(input, step.parameters);
|
|
764
|
+
break;
|
|
765
|
+
case 'pattern-matcher':
|
|
766
|
+
result = this.executePatternMatching(input, step.parameters);
|
|
767
|
+
break;
|
|
768
|
+
case 'relationship-analyzer':
|
|
769
|
+
result = this.executeRelationshipBuilding(input, step.parameters);
|
|
770
|
+
break;
|
|
771
|
+
case 'graph-optimizer':
|
|
772
|
+
result = this.executeOptimization(input, step.parameters);
|
|
773
|
+
break;
|
|
774
|
+
case 'learning-analyzer':
|
|
775
|
+
result = this.executeLearningAnalysis(input, step.parameters);
|
|
776
|
+
break;
|
|
777
|
+
default:
|
|
778
|
+
result = input;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
tool.state = 'ready';
|
|
782
|
+
tool.usage.successRate =
|
|
783
|
+
(tool.usage.successRate * (tool.usage.totalUses - 1) + 1.0) / tool.usage.totalUses;
|
|
784
|
+
|
|
785
|
+
this.emit('toolExecuted', { toolId: tool.id, toolType: tool.type });
|
|
786
|
+
return result;
|
|
787
|
+
} catch (error) {
|
|
788
|
+
tool.state = 'error';
|
|
789
|
+
tool.usage.successRate =
|
|
790
|
+
(tool.usage.successRate * (tool.usage.totalUses - 1)) / tool.usage.totalUses;
|
|
791
|
+
|
|
792
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
793
|
+
this.emit('toolError', { toolId: tool.id, error: message });
|
|
794
|
+
throw error;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// ── Query Matching & Relevance ──────────────────────────────────────────────
|
|
799
|
+
|
|
800
|
+
private matchesQuery(node: KnowledgeNode, query: string): boolean {
|
|
801
|
+
const lowerQuery = query.toLowerCase();
|
|
802
|
+
const lowerName = node.name.toLowerCase();
|
|
803
|
+
|
|
804
|
+
if (lowerName.includes(lowerQuery) || lowerQuery.includes(lowerName)) {
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
const description = (node.properties.description as string) ?? '';
|
|
809
|
+
if (description.toLowerCase().includes(lowerQuery)) {
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
for (const tag of node.tags) {
|
|
814
|
+
if (tag.toLowerCase().includes(lowerQuery) || lowerQuery.includes(tag.toLowerCase())) {
|
|
815
|
+
return true;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
private calculateRelevance(node: KnowledgeNode, query: string): number {
|
|
823
|
+
let relevance = 0;
|
|
824
|
+
const lowerQuery = query.toLowerCase();
|
|
825
|
+
const lowerName = node.name.toLowerCase();
|
|
826
|
+
|
|
827
|
+
// Name exact match
|
|
828
|
+
if (lowerName === lowerQuery) {
|
|
829
|
+
relevance += 1.0;
|
|
830
|
+
} else if (lowerName.includes(lowerQuery)) {
|
|
831
|
+
relevance += 0.7;
|
|
832
|
+
} else if (lowerQuery.includes(lowerName)) {
|
|
833
|
+
relevance += 0.5;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// Description match
|
|
837
|
+
const description = (node.properties.description as string) ?? '';
|
|
838
|
+
if (description.toLowerCase().includes(lowerQuery)) {
|
|
839
|
+
relevance += 0.3;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Tag matches
|
|
843
|
+
for (const tag of node.tags) {
|
|
844
|
+
if (tag.toLowerCase() === lowerQuery) {
|
|
845
|
+
relevance += 0.4;
|
|
846
|
+
} else if (tag.toLowerCase().includes(lowerQuery) || lowerQuery.includes(tag.toLowerCase())) {
|
|
847
|
+
relevance += 0.2;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Confidence weighting
|
|
852
|
+
relevance *= node.metadata.confidence;
|
|
853
|
+
|
|
854
|
+
// Clamp to [0, 1]
|
|
855
|
+
return Math.min(1.0, Math.max(0, relevance));
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
private calculateStringRelevance(str: string, query: string): number {
|
|
859
|
+
const lowerStr = str.toLowerCase();
|
|
860
|
+
const lowerQuery = query.toLowerCase();
|
|
861
|
+
|
|
862
|
+
if (lowerStr === lowerQuery) return 1.0;
|
|
863
|
+
if (lowerStr.includes(lowerQuery)) return 0.7;
|
|
864
|
+
if (lowerQuery.includes(lowerStr)) return 0.5;
|
|
865
|
+
|
|
866
|
+
// Simple token overlap
|
|
867
|
+
const strTokens = lowerStr.split(/\s+/);
|
|
868
|
+
const queryTokens = lowerQuery.split(/\s+/);
|
|
869
|
+
let overlapCount = 0;
|
|
870
|
+
|
|
871
|
+
for (const qt of queryTokens) {
|
|
872
|
+
if (strTokens.some((st: string) => st.includes(qt) || qt.includes(st))) {
|
|
873
|
+
overlapCount++;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
return queryTokens.length > 0 ? overlapCount / queryTokens.length * 0.5 : 0;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// ── Graph Traversal ─────────────────────────────────────────────────────────
|
|
881
|
+
|
|
882
|
+
findPathToNode(nodeId: string): string[] {
|
|
883
|
+
const path: string[] = [];
|
|
884
|
+
const visited = new Set<string>();
|
|
885
|
+
const queue: Array<{ id: string; trail: string[] }> = [{ id: 'root', trail: ['root'] }];
|
|
886
|
+
|
|
887
|
+
if (nodeId === 'root') return ['root'];
|
|
888
|
+
|
|
889
|
+
while (queue.length > 0) {
|
|
890
|
+
const item = queue.shift();
|
|
891
|
+
if (!item) break;
|
|
892
|
+
|
|
893
|
+
const { id, trail } = item;
|
|
894
|
+
|
|
895
|
+
if (visited.has(id)) continue;
|
|
896
|
+
visited.add(id);
|
|
897
|
+
|
|
898
|
+
if (id === nodeId) {
|
|
899
|
+
return trail;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
const connected = this.getConnectedNodes(id);
|
|
903
|
+
for (const connectedId of connected) {
|
|
904
|
+
if (!visited.has(connectedId)) {
|
|
905
|
+
queue.push({ id: connectedId, trail: [...trail, connectedId] });
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return path.length > 0 ? path : [nodeId];
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
getConnectedNodes(nodeId: string): string[] {
|
|
914
|
+
const connected: string[] = [];
|
|
915
|
+
|
|
916
|
+
for (const [, relationship] of this.relationships) {
|
|
917
|
+
if (relationship.from === nodeId) {
|
|
918
|
+
connected.push(relationship.to);
|
|
919
|
+
} else if (relationship.to === nodeId) {
|
|
920
|
+
connected.push(relationship.from);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
return connected;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// ── Lookup Tables ───────────────────────────────────────────────────────────
|
|
928
|
+
|
|
929
|
+
private getAgentCapabilities(agentType: string): string[] {
|
|
930
|
+
const capabilities: Record<string, string[]> = {
|
|
931
|
+
'knowledge-curator': [
|
|
932
|
+
'knowledge-acquisition',
|
|
933
|
+
'knowledge-validation',
|
|
934
|
+
'knowledge-organization',
|
|
935
|
+
'knowledge-deduplication',
|
|
936
|
+
],
|
|
937
|
+
'pattern-recognizer': [
|
|
938
|
+
'pattern-detection',
|
|
939
|
+
'pattern-classification',
|
|
940
|
+
'anomaly-detection',
|
|
941
|
+
'trend-analysis',
|
|
942
|
+
],
|
|
943
|
+
'relationship-builder': [
|
|
944
|
+
'relationship-inference',
|
|
945
|
+
'relationship-validation',
|
|
946
|
+
'relationship-strengthening',
|
|
947
|
+
'relationship-pruning',
|
|
948
|
+
],
|
|
949
|
+
'query-optimizer': [
|
|
950
|
+
'query-planning',
|
|
951
|
+
'query-caching',
|
|
952
|
+
'query-optimization',
|
|
953
|
+
'result-ranking',
|
|
954
|
+
],
|
|
955
|
+
'learning-agent': [
|
|
956
|
+
'supervised-learning',
|
|
957
|
+
'unsupervised-learning',
|
|
958
|
+
'reinforcement-learning',
|
|
959
|
+
'transfer-learning',
|
|
960
|
+
],
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
return capabilities[agentType] ?? ['generic-capability'];
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
private createReasoningEngine(agentType: string): ReasoningEngine {
|
|
967
|
+
return {
|
|
968
|
+
type: agentType,
|
|
969
|
+
rules: this.getReasoningRules(agentType),
|
|
970
|
+
context: new Map(),
|
|
971
|
+
history: [],
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
private getReasoningRules(agentType: string): string[] {
|
|
976
|
+
const rules: Record<string, string[]> = {
|
|
977
|
+
'knowledge-curator': [
|
|
978
|
+
'validate-source-credibility',
|
|
979
|
+
'check-knowledge-consistency',
|
|
980
|
+
'merge-duplicate-knowledge',
|
|
981
|
+
'maintain-knowledge-hierarchy',
|
|
982
|
+
],
|
|
983
|
+
'pattern-recognizer': [
|
|
984
|
+
'identify-recurring-patterns',
|
|
985
|
+
'classify-pattern-types',
|
|
986
|
+
'detect-anomalies',
|
|
987
|
+
'track-pattern-evolution',
|
|
988
|
+
],
|
|
989
|
+
'relationship-builder': [
|
|
990
|
+
'infer-implicit-relationships',
|
|
991
|
+
'validate-relationship-consistency',
|
|
992
|
+
'strengthen-confirmed-relationships',
|
|
993
|
+
'prune-weak-relationships',
|
|
994
|
+
],
|
|
995
|
+
'query-optimizer': [
|
|
996
|
+
'analyze-query-complexity',
|
|
997
|
+
'select-optimal-traversal',
|
|
998
|
+
'cache-frequent-queries',
|
|
999
|
+
'rank-results-by-relevance',
|
|
1000
|
+
],
|
|
1001
|
+
'learning-agent': [
|
|
1002
|
+
'extract-features',
|
|
1003
|
+
'update-model-weights',
|
|
1004
|
+
'evaluate-performance',
|
|
1005
|
+
'adapt-learning-rate',
|
|
1006
|
+
],
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
return rules[agentType] ?? ['generic-rule'];
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
private getAgentTools(agentType: string): string[] {
|
|
1013
|
+
const tools: Record<string, string[]> = {
|
|
1014
|
+
'knowledge-curator': ['knowledge-query', 'pattern-matcher'],
|
|
1015
|
+
'pattern-recognizer': ['pattern-matcher', 'learning-analyzer'],
|
|
1016
|
+
'relationship-builder': ['relationship-analyzer', 'knowledge-query'],
|
|
1017
|
+
'query-optimizer': ['knowledge-query', 'graph-optimizer'],
|
|
1018
|
+
'learning-agent': ['learning-analyzer', 'pattern-matcher'],
|
|
1019
|
+
};
|
|
1020
|
+
|
|
1021
|
+
return tools[agentType] ?? ['knowledge-query'];
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
private getChainSteps(chainType: string): ChainStep[] {
|
|
1025
|
+
const steps: Record<string, ChainStep[]> = {
|
|
1026
|
+
'knowledge-acquisition': [
|
|
1027
|
+
{ tool: 'knowledge-query', parameters: { action: 'extract' } },
|
|
1028
|
+
{ tool: 'pattern-matcher', parameters: { action: 'validate' } },
|
|
1029
|
+
{ tool: 'knowledge-query', parameters: { action: 'store' } },
|
|
1030
|
+
],
|
|
1031
|
+
'pattern-detection': [
|
|
1032
|
+
{ tool: 'knowledge-query', parameters: { action: 'gather' } },
|
|
1033
|
+
{ tool: 'pattern-matcher', parameters: { action: 'detect' } },
|
|
1034
|
+
{ tool: 'learning-analyzer', parameters: { action: 'classify' } },
|
|
1035
|
+
],
|
|
1036
|
+
'relationship-inference': [
|
|
1037
|
+
{ tool: 'knowledge-query', parameters: { action: 'gather' } },
|
|
1038
|
+
{ tool: 'relationship-analyzer', parameters: { action: 'infer' } },
|
|
1039
|
+
{ tool: 'relationship-analyzer', parameters: { action: 'validate' } },
|
|
1040
|
+
],
|
|
1041
|
+
'knowledge-optimization': [
|
|
1042
|
+
{ tool: 'knowledge-query', parameters: { action: 'analyze' } },
|
|
1043
|
+
{ tool: 'graph-optimizer', parameters: { action: 'optimize' } },
|
|
1044
|
+
{ tool: 'graph-optimizer', parameters: { action: 'verify' } },
|
|
1045
|
+
],
|
|
1046
|
+
'learning-pipeline': [
|
|
1047
|
+
{ tool: 'knowledge-query', parameters: { action: 'extract' } },
|
|
1048
|
+
{ tool: 'learning-analyzer', parameters: { action: 'learn' } },
|
|
1049
|
+
{ tool: 'learning-analyzer', parameters: { action: 'evaluate' } },
|
|
1050
|
+
],
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
return steps[chainType] ?? [{ tool: 'knowledge-query', parameters: { action: 'default' } }];
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
private getToolCapabilities(toolType: string): string[] {
|
|
1057
|
+
const capabilities: Record<string, string[]> = {
|
|
1058
|
+
'knowledge-query': [
|
|
1059
|
+
'semantic-search',
|
|
1060
|
+
'pattern-search',
|
|
1061
|
+
'relationship-search',
|
|
1062
|
+
'full-text-search',
|
|
1063
|
+
],
|
|
1064
|
+
'pattern-matcher': [
|
|
1065
|
+
'exact-match',
|
|
1066
|
+
'fuzzy-match',
|
|
1067
|
+
'regex-match',
|
|
1068
|
+
'semantic-match',
|
|
1069
|
+
],
|
|
1070
|
+
'relationship-analyzer': [
|
|
1071
|
+
'path-finding',
|
|
1072
|
+
'cluster-detection',
|
|
1073
|
+
'centrality-analysis',
|
|
1074
|
+
'community-detection',
|
|
1075
|
+
],
|
|
1076
|
+
'graph-optimizer': [
|
|
1077
|
+
'node-pruning',
|
|
1078
|
+
'relationship-pruning',
|
|
1079
|
+
'index-optimization',
|
|
1080
|
+
'cache-optimization',
|
|
1081
|
+
],
|
|
1082
|
+
'learning-analyzer': [
|
|
1083
|
+
'feature-extraction',
|
|
1084
|
+
'model-training',
|
|
1085
|
+
'performance-evaluation',
|
|
1086
|
+
'prediction',
|
|
1087
|
+
],
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
return capabilities[toolType] ?? ['generic-capability'];
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// ── Tool Execution Implementations ──────────────────────────────────────────
|
|
1094
|
+
|
|
1095
|
+
private executeKnowledgeQuery(input: unknown, parameters: Record<string, unknown>): unknown {
|
|
1096
|
+
console.log(`[KnowledgeGraph] Executing knowledge query with action: ${parameters.action}`);
|
|
1097
|
+
return input;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
private executePatternMatching(input: unknown, parameters: Record<string, unknown>): unknown {
|
|
1101
|
+
console.log(`[KnowledgeGraph] Executing pattern matching with action: ${parameters.action}`);
|
|
1102
|
+
return input;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
private executeRelationshipBuilding(input: unknown, parameters: Record<string, unknown>): unknown {
|
|
1106
|
+
console.log(`[KnowledgeGraph] Executing relationship building with action: ${parameters.action}`);
|
|
1107
|
+
return input;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
private executeOptimization(input: unknown, parameters: Record<string, unknown>): unknown {
|
|
1111
|
+
console.log(`[KnowledgeGraph] Executing optimization with action: ${parameters.action}`);
|
|
1112
|
+
return input;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
private executeLearningAnalysis(input: unknown, parameters: Record<string, unknown>): unknown {
|
|
1116
|
+
console.log(`[KnowledgeGraph] Executing learning analysis with action: ${parameters.action}`);
|
|
1117
|
+
return input;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// ── Pruning ─────────────────────────────────────────────────────────────────
|
|
1121
|
+
|
|
1122
|
+
private pruneNodes(): void {
|
|
1123
|
+
const threshold = 1.0 - this.config.knowledgeRetention;
|
|
1124
|
+
const toRemove: string[] = [];
|
|
1125
|
+
|
|
1126
|
+
for (const [nodeId, node] of this.nodes) {
|
|
1127
|
+
if (node.metadata.confidence < threshold && node.type !== 'root' && node.type !== 'category') {
|
|
1128
|
+
toRemove.push(nodeId);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// Sort by confidence ascending and remove lowest
|
|
1133
|
+
toRemove.sort((a, b) => {
|
|
1134
|
+
const aConf = this.nodes.get(a)?.metadata.confidence ?? 0;
|
|
1135
|
+
const bConf = this.nodes.get(b)?.metadata.confidence ?? 0;
|
|
1136
|
+
return aConf - bConf;
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
const removeCount = Math.min(toRemove.length, Math.floor(this.config.maxNodes * 0.1));
|
|
1140
|
+
for (let i = 0; i < removeCount; i++) {
|
|
1141
|
+
this.nodes.delete(toRemove[i]);
|
|
1142
|
+
// Also remove associated relationships
|
|
1143
|
+
for (const [relId, rel] of this.relationships) {
|
|
1144
|
+
if (rel.from === toRemove[i] || rel.to === toRemove[i]) {
|
|
1145
|
+
this.relationships.delete(relId);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
this.metrics.totalNodes = this.nodes.size;
|
|
1151
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
1152
|
+
|
|
1153
|
+
console.log(`[KnowledgeGraph] Pruned ${removeCount} low-confidence nodes.`);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
private pruneRelationships(): void {
|
|
1157
|
+
const toRemove: string[] = [];
|
|
1158
|
+
|
|
1159
|
+
for (const [relId, rel] of this.relationships) {
|
|
1160
|
+
if (rel.metadata.confidence < (1.0 - this.config.knowledgeRetention)) {
|
|
1161
|
+
toRemove.push(relId);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
toRemove.sort((a, b) => {
|
|
1166
|
+
const aConf = this.relationships.get(a)?.metadata.confidence ?? 0;
|
|
1167
|
+
const bConf = this.relationships.get(b)?.metadata.confidence ?? 0;
|
|
1168
|
+
return aConf - bConf;
|
|
1169
|
+
});
|
|
1170
|
+
|
|
1171
|
+
const removeCount = Math.min(toRemove.length, Math.floor(this.config.maxRelationships * 0.1));
|
|
1172
|
+
for (let i = 0; i < removeCount; i++) {
|
|
1173
|
+
this.relationships.delete(toRemove[i]);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
1177
|
+
|
|
1178
|
+
console.log(`[KnowledgeGraph] Pruned ${removeCount} weak relationships.`);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// ── Status & Optimization ──────────────────────────────────────────────────
|
|
1182
|
+
|
|
1183
|
+
getStatus(): Record<string, unknown> {
|
|
1184
|
+
return {
|
|
1185
|
+
config: this.config,
|
|
1186
|
+
metrics: { ...this.metrics },
|
|
1187
|
+
nodes: {
|
|
1188
|
+
total: this.nodes.size,
|
|
1189
|
+
byType: this.getNodeCountsByType(),
|
|
1190
|
+
},
|
|
1191
|
+
relationships: {
|
|
1192
|
+
total: this.relationships.size,
|
|
1193
|
+
byType: this.getRelationshipCountsByType(),
|
|
1194
|
+
},
|
|
1195
|
+
agents: {
|
|
1196
|
+
total: this.agents.size,
|
|
1197
|
+
byState: this.getAgentCountsByState(),
|
|
1198
|
+
},
|
|
1199
|
+
chains: {
|
|
1200
|
+
total: this.chains.size,
|
|
1201
|
+
byState: this.getChainCountsByState(),
|
|
1202
|
+
},
|
|
1203
|
+
tools: {
|
|
1204
|
+
total: this.tools.size,
|
|
1205
|
+
byState: this.getToolCountsByState(),
|
|
1206
|
+
},
|
|
1207
|
+
personaKnowledge: {
|
|
1208
|
+
totalPersonas: this.personaKnowledge.size,
|
|
1209
|
+
},
|
|
1210
|
+
knowledgePatterns: {
|
|
1211
|
+
totalPatterns: this.knowledgePatterns.size,
|
|
1212
|
+
},
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
private getNodeCountsByType(): Record<string, number> {
|
|
1217
|
+
const counts: Record<string, number> = {};
|
|
1218
|
+
for (const [, node] of this.nodes) {
|
|
1219
|
+
counts[node.type] = (counts[node.type] ?? 0) + 1;
|
|
1220
|
+
}
|
|
1221
|
+
return counts;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
private getRelationshipCountsByType(): Record<string, number> {
|
|
1225
|
+
const counts: Record<string, number> = {};
|
|
1226
|
+
for (const [, rel] of this.relationships) {
|
|
1227
|
+
counts[rel.type] = (counts[rel.type] ?? 0) + 1;
|
|
1228
|
+
}
|
|
1229
|
+
return counts;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
private getAgentCountsByState(): Record<string, number> {
|
|
1233
|
+
const counts: Record<string, number> = {};
|
|
1234
|
+
for (const [, agent] of this.agents) {
|
|
1235
|
+
counts[agent.state] = (counts[agent.state] ?? 0) + 1;
|
|
1236
|
+
}
|
|
1237
|
+
return counts;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
private getChainCountsByState(): Record<string, number> {
|
|
1241
|
+
const counts: Record<string, number> = {};
|
|
1242
|
+
for (const [, chain] of this.chains) {
|
|
1243
|
+
counts[chain.state] = (counts[chain.state] ?? 0) + 1;
|
|
1244
|
+
}
|
|
1245
|
+
return counts;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
private getToolCountsByState(): Record<string, number> {
|
|
1249
|
+
const counts: Record<string, number> = {};
|
|
1250
|
+
for (const [, tool] of this.tools) {
|
|
1251
|
+
counts[tool.state] = (counts[tool.state] ?? 0) + 1;
|
|
1252
|
+
}
|
|
1253
|
+
return counts;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
async optimize(): Promise<void> {
|
|
1257
|
+
console.log('[KnowledgeGraph] Starting knowledge graph optimization...');
|
|
1258
|
+
|
|
1259
|
+
// Remove low-confidence nodes
|
|
1260
|
+
const nodeThreshold = 1.0 - this.config.knowledgeRetention;
|
|
1261
|
+
const nodesToRemove: string[] = [];
|
|
1262
|
+
|
|
1263
|
+
for (const [nodeId, node] of this.nodes) {
|
|
1264
|
+
if (node.metadata.confidence < nodeThreshold && node.type !== 'root' && node.type !== 'category') {
|
|
1265
|
+
nodesToRemove.push(nodeId);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
for (const nodeId of nodesToRemove) {
|
|
1270
|
+
this.nodes.delete(nodeId);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// Remove weak relationships
|
|
1274
|
+
const relsToRemove: string[] = [];
|
|
1275
|
+
|
|
1276
|
+
for (const [relId, rel] of this.relationships) {
|
|
1277
|
+
if (rel.metadata.confidence < nodeThreshold) {
|
|
1278
|
+
relsToRemove.push(relId);
|
|
1279
|
+
}
|
|
1280
|
+
// Also remove orphaned relationships
|
|
1281
|
+
if (!this.nodes.has(rel.from) || !this.nodes.has(rel.to)) {
|
|
1282
|
+
relsToRemove.push(relId);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
for (const relId of relsToRemove) {
|
|
1287
|
+
this.relationships.delete(relId);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
this.metrics.totalNodes = this.nodes.size;
|
|
1291
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
1292
|
+
this.metrics.lastOptimization = Date.now();
|
|
1293
|
+
|
|
1294
|
+
console.log(
|
|
1295
|
+
`[KnowledgeGraph] Optimization complete. Removed ${nodesToRemove.length} nodes and ${relsToRemove.length} relationships.`
|
|
1296
|
+
);
|
|
1297
|
+
|
|
1298
|
+
this.emit('optimized', {
|
|
1299
|
+
removedNodes: nodesToRemove.length,
|
|
1300
|
+
removedRelationships: relsToRemove.length,
|
|
1301
|
+
metrics: this.metrics,
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// ── Persona Knowledge ──────────────────────────────────────────────────────
|
|
1306
|
+
|
|
1307
|
+
addPersonaKnowledge(personaId: string, key: string, value: unknown): void {
|
|
1308
|
+
if (!this.personaKnowledge.has(personaId)) {
|
|
1309
|
+
this.personaKnowledge.set(personaId, new Map());
|
|
1310
|
+
}
|
|
1311
|
+
this.personaKnowledge.get(personaId)!.set(key, value);
|
|
1312
|
+
this.emit('personaKnowledgeAdded', { personaId, key });
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
getPersonaKnowledge(personaId: string): Map<string, unknown> | undefined {
|
|
1316
|
+
return this.personaKnowledge.get(personaId);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// ── Knowledge Pattern Management ───────────────────────────────────────────
|
|
1320
|
+
|
|
1321
|
+
addKnowledgePattern(patternKey: string, pattern: unknown): void {
|
|
1322
|
+
if (!this.knowledgePatterns.has(patternKey)) {
|
|
1323
|
+
this.knowledgePatterns.set(patternKey, []);
|
|
1324
|
+
}
|
|
1325
|
+
this.knowledgePatterns.get(patternKey)!.push(pattern);
|
|
1326
|
+
this.emit('patternAdded', { patternKey });
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
getKnowledgePatterns(patternKey: string): unknown[] | undefined {
|
|
1330
|
+
return this.knowledgePatterns.get(patternKey);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// ── Node & Relationship Accessors ──────────────────────────────────────────
|
|
1334
|
+
|
|
1335
|
+
getNode(nodeId: string): KnowledgeNode | undefined {
|
|
1336
|
+
return this.nodes.get(nodeId);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
getRelationship(relId: string): KnowledgeRelationship | undefined {
|
|
1340
|
+
return this.relationships.get(relId);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
getAllNodes(): KnowledgeNode[] {
|
|
1344
|
+
return Array.from(this.nodes.values());
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
getAllRelationships(): KnowledgeRelationship[] {
|
|
1348
|
+
return Array.from(this.relationships.values());
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
getNodesByType(type: string): KnowledgeNode[] {
|
|
1352
|
+
const result: KnowledgeNode[] = [];
|
|
1353
|
+
for (const [, node] of this.nodes) {
|
|
1354
|
+
if (node.type === type) {
|
|
1355
|
+
result.push(node);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
return result;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
getRelationshipsByType(type: string): KnowledgeRelationship[] {
|
|
1362
|
+
const result: KnowledgeRelationship[] = [];
|
|
1363
|
+
for (const [, rel] of this.relationships) {
|
|
1364
|
+
if (rel.type === type) {
|
|
1365
|
+
result.push(rel);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return result;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
updateNode(nodeId: string, updates: Partial<KnowledgeNode>): KnowledgeNode | undefined {
|
|
1372
|
+
const node = this.nodes.get(nodeId);
|
|
1373
|
+
if (!node) return undefined;
|
|
1374
|
+
|
|
1375
|
+
if (updates.name !== undefined) node.name = updates.name;
|
|
1376
|
+
if (updates.type !== undefined) node.type = updates.type;
|
|
1377
|
+
if (updates.level !== undefined) node.level = updates.level;
|
|
1378
|
+
if (updates.properties !== undefined) node.properties = { ...node.properties, ...updates.properties };
|
|
1379
|
+
if (updates.tags !== undefined) node.tags = updates.tags;
|
|
1380
|
+
if (updates.embeddings !== undefined) node.embeddings = updates.embeddings;
|
|
1381
|
+
|
|
1382
|
+
node.metadata.lastModified = Date.now();
|
|
1383
|
+
node.metadata.version++;
|
|
1384
|
+
|
|
1385
|
+
this.emit('nodeUpdated', { node });
|
|
1386
|
+
return node;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
updateRelationship(relId: string, updates: Partial<KnowledgeRelationship>): KnowledgeRelationship | undefined {
|
|
1390
|
+
const rel = this.relationships.get(relId);
|
|
1391
|
+
if (!rel) return undefined;
|
|
1392
|
+
|
|
1393
|
+
if (updates.type !== undefined) rel.type = updates.type;
|
|
1394
|
+
if (updates.weight !== undefined) rel.weight = updates.weight;
|
|
1395
|
+
if (updates.properties !== undefined) rel.properties = { ...rel.properties, ...updates.properties };
|
|
1396
|
+
|
|
1397
|
+
rel.metadata.lastModified = Date.now();
|
|
1398
|
+
|
|
1399
|
+
this.emit('relationshipUpdated', { relationship: rel });
|
|
1400
|
+
return rel;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
deleteNode(nodeId: string): boolean {
|
|
1404
|
+
if (!this.nodes.has(nodeId)) return false;
|
|
1405
|
+
|
|
1406
|
+
this.nodes.delete(nodeId);
|
|
1407
|
+
|
|
1408
|
+
// Remove associated relationships
|
|
1409
|
+
const relsToRemove: string[] = [];
|
|
1410
|
+
for (const [relId, rel] of this.relationships) {
|
|
1411
|
+
if (rel.from === nodeId || rel.to === nodeId) {
|
|
1412
|
+
relsToRemove.push(relId);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
for (const relId of relsToRemove) {
|
|
1416
|
+
this.relationships.delete(relId);
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
this.metrics.totalNodes = this.nodes.size;
|
|
1420
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
1421
|
+
|
|
1422
|
+
this.emit('nodeDeleted', { nodeId, removedRelationships: relsToRemove.length });
|
|
1423
|
+
return true;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
deleteRelationship(relId: string): boolean {
|
|
1427
|
+
if (!this.relationships.has(relId)) return false;
|
|
1428
|
+
|
|
1429
|
+
this.relationships.delete(relId);
|
|
1430
|
+
this.metrics.totalRelationships = this.relationships.size;
|
|
1431
|
+
|
|
1432
|
+
this.emit('relationshipDeleted', { relId });
|
|
1433
|
+
return true;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
getMetrics(): KnowledgeGraphMetrics {
|
|
1437
|
+
return { ...this.metrics };
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
export default KnowledgeGraphEngine;
|