@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.
@@ -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;