UNPKG

memory-engineering-mcp

Version:

🧠 AI Memory System powered by MongoDB Atlas & Voyage AI - Autonomous memory management with zero manual work

232 lines β€’ 9.4 kB
/** * Auto Index Manager - Ensures all indexes are created automatically * This runs in the background to guarantee users have all indexes without manual setup */ import { logger } from './logger.js'; // Track if we've already ensured indexes this session let indexesEnsured = false; /** * Automatically ensures all required indexes exist * Called during init and periodically in background */ export async function ensureAllIndexes(memoryCollection, codeCollection) { if (indexesEnsured) { logger.debug('♾️ INDEXES CACHED - Already optimized this session'); return; } try { logger.info('⚑ AUTO-CREATING ALL INDEXES - Brain synapses forming...'); // Standard MongoDB indexes for memories const memoryIndexes = [ { keys: { projectId: 1, memoryName: 1 }, name: 'project_memory_unique', unique: true }, { keys: { projectId: 1, 'metadata.lastModified': -1 }, name: 'project_modified' }, { keys: { content: 'text' }, name: 'content_text' } ]; for (const index of memoryIndexes) { try { await memoryCollection.createIndex(index.keys, { name: index.name, ...(index.unique && { unique: index.unique }) }); } catch (error) { if (error.code !== 85 && error.code !== 86) { // Ignore "already exists" errors logger.warn(`⚠️ INDEX WARNING: ${error.message}`); } } } // Standard MongoDB indexes for code const codeIndexes = [ { keys: { projectId: 1, filePath: 1 }, name: 'project_file' }, { keys: { projectId: 1, 'chunk.type': 1 }, name: 'project_chunk_type' }, { keys: { projectId: 1, 'metadata.patterns': 1 }, name: 'project_patterns' }, { keys: { 'chunk.name': 'text', 'chunk.signature': 'text', searchableText: 'text' }, name: 'code_text' } ]; for (const index of codeIndexes) { try { await codeCollection.createIndex(index.keys, { name: index.name }); } catch (error) { if (error.code !== 85 && error.code !== 86) { logger.warn(`⚠️ INDEX WARNING: ${error.message}`); } } } // Atlas Search indexes - try to create, fail gracefully if not Atlas try { await ensureAtlasSearchIndexes(memoryCollection, codeCollection); } catch (error) { logger.debug('πŸ“¦ ATLAS OFFLINE - Fallback to standard text search'); } indexesEnsured = true; logger.info('πŸŽ‰ ALL INDEXES READY - Search speed MAXIMIZED!'); } catch (error) { logger.error('πŸ’€ INDEX SETUP EXPLOSION!', error); // Don't throw - let the system work with whatever indexes exist } } /** * Creates Atlas Search indexes if on MongoDB Atlas */ async function ensureAtlasSearchIndexes(memoryCollection, codeCollection) { try { // Check what exists const memorySearchIndexes = await memoryCollection.listSearchIndexes().toArray(); const codeSearchIndexes = await codeCollection.listSearchIndexes().toArray(); // Memory vector search if (!memorySearchIndexes.some(idx => idx.name === 'memory_vector_search')) { await memoryCollection.createSearchIndex({ name: 'memory_vector_search', type: 'vectorSearch', definition: { fields: [ { type: 'vector', path: 'contentVector', numDimensions: 1024, similarity: 'cosine' }, { type: 'filter', path: 'projectId' }, { type: 'filter', path: 'memoryName' } ] } }); logger.info('🧠 MEMORY VECTOR INDEX CREATED - Semantic search online!'); } // Memory text search if (!memorySearchIndexes.some(idx => idx.name === 'memory_text_search' || idx.name === 'memory_text')) { await memoryCollection.createSearchIndex({ name: 'memory_text_search', type: 'search', definition: { mappings: { dynamic: false, fields: { projectId: { type: 'token', normalizer: 'lowercase' }, memoryName: { type: 'token', normalizer: 'lowercase' }, content: { type: 'string', analyzer: 'lucene.standard' } } } } }); logger.info('πŸ“– MEMORY TEXT INDEX CREATED - Keyword search ready!'); } // Code vector search if (!codeSearchIndexes.some(idx => idx.name === 'code_vector_search')) { await codeCollection.createSearchIndex({ name: 'code_vector_search', type: 'vectorSearch', definition: { fields: [ { type: 'vector', path: 'contentVector', numDimensions: 1024, similarity: 'cosine' }, { type: 'filter', path: 'projectId' }, { type: 'filter', path: 'chunk.type' } ] } }); logger.info('πŸ” CODE VECTOR INDEX CREATED - Code intelligence activated!'); } // Code text search if (!codeSearchIndexes.some(idx => idx.name === 'code_text_search')) { await codeCollection.createSearchIndex({ name: 'code_text_search', type: 'search', definition: { mappings: { dynamic: false, fields: { projectId: { type: 'token', normalizer: 'lowercase' }, 'chunk.name': { type: 'string', analyzer: 'lucene.standard' }, 'chunk.signature': { type: 'string', analyzer: 'lucene.standard' }, searchableText: { type: 'string', analyzer: 'lucene.standard' }, 'chunk.type': { type: 'token', normalizer: 'lowercase' }, 'metadata.patterns': { type: 'token', normalizer: 'lowercase' } } } } }); logger.info('πŸ“ CODE TEXT INDEX CREATED - Symbol search enabled!'); } logger.info('πŸš€ ATLAS SEARCH FULLY OPERATIONAL - Maximum intelligence!'); } catch (error) { if (error.message?.includes('listSearchIndexes')) { throw new Error('Not MongoDB Atlas'); } logger.warn('⚠️ ATLAS INDEX WARNING:', error.message); } } /** * Background task to ensure indexes after a delay * This catches any indexes that might have failed during init */ export function startIndexBackgroundTask(memoryCollection, codeCollection) { // Check after 30 seconds setTimeout(async () => { try { logger.debug('πŸ”„ BACKGROUND INDEX CHECK - Ensuring persistence...'); await ensureAllIndexes(memoryCollection, codeCollection); } catch (error) { logger.debug('⚠️ Background check failed (non-critical):', error); } }, 30000); // Check again after 2 minutes (for Atlas indexes that take time) setTimeout(async () => { try { logger.debug('πŸ” SECOND INDEX CHECK - Double ensuring...'); indexesEnsured = false; // Force recheck await ensureAllIndexes(memoryCollection, codeCollection); } catch (error) { logger.debug('⚠️ Second check failed (non-critical):', error); } }, 120000); } //# sourceMappingURL=auto-index-manager.js.map