UNPKG

ultimate-mcp-server

Version:

The definitive all-in-one Model Context Protocol server for AI-assisted coding across 30+ platforms

305 lines 10.5 kB
/** * Cognitive Memory Manager * Main entry point for cognitive search and memory functionality */ import { KnowledgeGraphManager } from './knowledge-graph.js'; import { CodeAnalyzer } from './code-analyzer.js'; import { Logger } from '../utils/logger.js'; import { createEmbeddingProvider } from '../rag/embeddings.js'; import * as fs from 'fs/promises'; import * as path from 'path'; const logger = new Logger('CognitiveMemory'); export class CognitiveMemoryManager { knowledgeGraph; codeAnalyzer; embeddingProvider; config; constructor(config = {}) { this.config = config; this.knowledgeGraph = new KnowledgeGraphManager(config); this.codeAnalyzer = new CodeAnalyzer(); } async initialize() { // Initialize embedding provider if API key is available if (process.env.OPENAI_API_KEY || process.env.COHERE_API_KEY) { if (process.env.OPENAI_API_KEY) { this.embeddingProvider = createEmbeddingProvider({ provider: 'openai', model: 'text-embedding-3-small', apiKey: process.env.OPENAI_API_KEY }); } else if (process.env.COHERE_API_KEY) { this.embeddingProvider = createEmbeddingProvider({ provider: 'cohere', model: 'embed-english-v3.0', apiKey: process.env.COHERE_API_KEY }); } } else { // Use local embedding provider this.embeddingProvider = createEmbeddingProvider({ provider: 'local', model: 'simple-hash' }); } await this.knowledgeGraph.initialize(this.embeddingProvider); logger.info('Cognitive memory system initialized'); } /** * Add a concept to the knowledge graph */ async addConcept(name, content, metadata = {}) { return this.knowledgeGraph.addNode({ type: 'concept', name, content, metadata, importance: metadata.importance || 0.5 }); } /** * Add an entity to the knowledge graph */ async addEntity(name, content, entityType, metadata = {}) { return this.knowledgeGraph.addNode({ type: 'entity', name, content, metadata: { ...metadata, entityType }, importance: metadata.importance || 0.5 }); } /** * Add a memory to the knowledge graph */ async addMemory(content, context, metadata = {}) { return this.knowledgeGraph.addNode({ type: 'memory', name: `Memory: ${content.substring(0, 50)}...`, content, metadata: { ...metadata, context }, importance: metadata.importance || 0.6 }); } /** * Add a relationship between nodes */ async addRelationship(sourceId, targetId, type, weight = 0.5, metadata = {}) { return this.knowledgeGraph.addEdge({ source: sourceId, target: targetId, type, weight, metadata }); } /** * Analyze and add code to the knowledge graph */ async analyzeAndAddCode(filePath, content) { // Read file content if not provided if (!content) { content = await fs.readFile(filePath, 'utf-8'); } // Analyze code const analysis = await this.codeAnalyzer.analyzeCode(content, filePath); // Add code node const codeNode = await this.knowledgeGraph.addNode({ type: 'code', name: path.basename(filePath), content: content, metadata: { filePath, language: path.extname(filePath).substring(1), complexity: analysis.complexity, symbolCount: analysis.symbols.length, patterns: analysis.patterns.map(p => p.type) }, importance: Math.min(0.5 + (analysis.symbols.length / 100), 1) }); // Add symbol nodes and relationships for (const symbol of analysis.symbols) { const symbolNode = await this.knowledgeGraph.addNode({ type: 'entity', name: symbol.name, content: symbol.signature || symbol.name, metadata: { entityType: 'code-symbol', symbolType: symbol.type, location: symbol.location, docstring: symbol.docstring }, importance: symbol.type === 'class' ? 0.7 : 0.6 }); // Link symbol to code await this.knowledgeGraph.addEdge({ source: codeNode.id, target: symbolNode.id, type: 'contains', weight: 0.8, metadata: { symbolType: symbol.type } }); } // Add dependency relationships for (const dep of analysis.dependencies) { // Create or find dependency node const depNode = await this.knowledgeGraph.addNode({ type: 'entity', name: dep.target, content: `Dependency: ${dep.target}`, metadata: { entityType: 'dependency', dependencyType: dep.type }, importance: 0.4 }); // Link dependency await this.knowledgeGraph.addEdge({ source: codeNode.id, target: depNode.id, type: 'depends_on', weight: 0.6, metadata: { dependencyType: dep.type } }); } return { node: codeNode, analysis }; } /** * Analyze and add an entire codebase */ async analyzeCodebase(rootPath, extensions = ['.js', '.ts', '.jsx', '.tsx', '.py']) { let filesAnalyzed = 0; let nodesCreated = 0; async function* walkDirectory(dir) { const entries = await fs.readdir(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { // Skip common directories if (!['node_modules', '.git', 'dist', 'build'].includes(entry.name)) { yield* walkDirectory(fullPath); } } else if (entry.isFile()) { const ext = path.extname(entry.name); if (extensions.includes(ext)) { yield fullPath; } } } } // Analyze all files for await (const filePath of walkDirectory(rootPath)) { try { const { node } = await this.analyzeAndAddCode(filePath); filesAnalyzed++; nodesCreated++; logger.debug(`Analyzed ${filePath}`); } catch (error) { logger.error(`Failed to analyze ${filePath}:`, error); } } // Build relationships between files based on imports // This would require a second pass to match imports with actual files return { filesAnalyzed, nodesCreated }; } /** * Search the cognitive memory */ async search(options) { return this.knowledgeGraph.search(options); } /** * Get related memories and concepts */ async getRelated(nodeId, depth = 2) { const searchResult = await this.knowledgeGraph.search({ query: nodeId, includeRelated: true, depth, limit: 20 }); return searchResult; } /** * Build a context from multiple searches */ async buildContext(queries) { const allNodes = new Map(); const allEdges = new Map(); const relevanceScores = new Map(); // Perform searches for (const query of queries) { const result = await this.search({ query, includeRelated: true, limit: 10 }); // Merge results for (const node of result.nodes) { if (!allNodes.has(node.id)) { allNodes.set(node.id, node); } } for (const edge of result.edges) { if (!allEdges.has(edge.id)) { allEdges.set(edge.id, edge); } } for (const [nodeId, score] of result.relevanceScores) { const existing = relevanceScores.get(nodeId) || 0; relevanceScores.set(nodeId, Math.max(existing, score)); } } // Build subgraph const subgraph = { nodes: allNodes, edges: allEdges, nodeIndex: new Map(), edgeIndex: new Map() }; // Rebuild indices for (const node of allNodes.values()) { if (!subgraph.nodeIndex.has(node.type)) { subgraph.nodeIndex.set(node.type, new Set()); } subgraph.nodeIndex.get(node.type).add(node.id); } for (const edge of allEdges.values()) { if (!subgraph.edgeIndex.has(edge.source)) { subgraph.edgeIndex.set(edge.source, new Set()); } subgraph.edgeIndex.get(edge.source).add(edge.id); } return { nodes: Array.from(allNodes.values()), edges: Array.from(allEdges.values()), subgraph, relevanceScores }; } /** * Get memory statistics */ getStats() { return this.knowledgeGraph.getStats(); } /** * Export knowledge graph for visualization */ exportForVisualization() { return this.knowledgeGraph.exportForVisualization(); } /** * Clear all memory */ async clear() { this.knowledgeGraph = new KnowledgeGraphManager(this.config); await this.knowledgeGraph.initialize(this.embeddingProvider); logger.info('Cognitive memory cleared'); } } //# sourceMappingURL=cognitive-memory.js.map