/** * Context Engine Service * * Source: https://github.com/Eskapeum/Context-Engine * * Provides intelligent context retrieval for enhanced AI responses: * - File indexing and caching * - Semantic search across codebase * - Q&A memory for persistent knowledge */ import { getLogger } from "@/lib/logger"; const log = getLogger("context-engine"); export interface ContextEngineConfig { projectRoot: string; enableIndexing?: boolean; enableVectors?: boolean; } export interface RetrievedContext { content: string; sources: ContextSource[]; relevanceScore: number; } export interface ContextSource { file: string; line?: number; symbol?: string; type: "code" | "documentation" | "memory" | "qa"; } export interface IndexStats { filesIndexed: number; symbolsFound: number; lastUpdated: number; } // Singleton instance let instance: ContextEngineService | null = null; export class ContextEngineService { private config: ContextEngineConfig; private initialized: boolean = false; private stats: IndexStats = { filesIndexed: 0, symbolsFound: 0, lastUpdated: 0 }; private memoryCache: Map = new Map(); constructor(config: ContextEngineConfig) { this.config = config; } /** * Initialize the context engine */ async initialize(): Promise { if (this.initialized) return; log.info("Context Engine initializing...", { projectRoot: this.config.projectRoot }); // In a full implementation, this would: // 1. Scan the project directory // 2. Build Tree-sitter AST for each file // 3. Create embeddings for semantic search this.initialized = true; log.info("Context Engine initialized"); } /** * Retrieve relevant context for a query */ async retrieve(query: string, options?: { maxTokens?: number }): Promise { if (!this.initialized) { await this.initialize(); } log.info("Retrieving context for query", { query: query.substring(0, 50) }); // Search memory cache first const memorySuggestions = this.searchMemory(query); // In a full implementation, this would: // 1. Vectorize the query // 2. Search the index for relevant files/symbols // 3. Rank results by relevance // 4. Return top matches within token budget return { content: memorySuggestions.join("\n\n"), sources: [], relevanceScore: 0 }; } /** * Index or re-index the project */ async index(options?: { force?: boolean }): Promise { log.info("Indexing project...", { force: options?.force }); // In a full implementation, this would: // 1. Walk the file tree // 2. Parse each file with Tree-sitter // 3. Extract symbols and documentation // 4. Generate embeddings this.stats = { filesIndexed: 0, symbolsFound: 0, lastUpdated: Date.now() }; return this.stats; } /** * Get current index stats */ getStats(): IndexStats { return this.stats; } /** * Add to Q&A memory */ async remember(question: string, answer: string): Promise { const id = `qa_${Date.now()}`; this.memoryCache.set(id, { question, answer, timestamp: Date.now() }); log.info("Remembered Q&A", { question: question.substring(0, 50) }); } /** * Search Q&A memory */ searchMemory(query: string): string[] { const results: string[] = []; const queryLower = query.toLowerCase(); for (const [, entry] of this.memoryCache) { if (entry.question.toLowerCase().includes(queryLower) || entry.answer.toLowerCase().includes(queryLower)) { results.push(`Q: ${entry.question}\nA: ${entry.answer}`); } } return results.slice(0, 5); } /** * Search Q&A memory (async version) */ async recall(query: string): Promise<{ question: string; answer: string }[]> { log.info("Recalling from memory", { query: query.substring(0, 50) }); const results: { question: string; answer: string }[] = []; const queryLower = query.toLowerCase(); for (const [, entry] of this.memoryCache) { if (entry.question.toLowerCase().includes(queryLower) || entry.answer.toLowerCase().includes(queryLower)) { results.push({ question: entry.question, answer: entry.answer }); } } return results.slice(0, 10); } } /** * Get or create context engine instance */ export function getContextEngine(config?: ContextEngineConfig): ContextEngineService { if (!instance && config) { instance = new ContextEngineService(config); } if (!instance) { throw new Error("Context engine not initialized. Provide config on first call."); } return instance; } /** * Initialize context engine for a workspace */ export async function initializeContextEngine(projectRoot: string): Promise { const service = getContextEngine({ projectRoot }); await service.initialize(); return service; } export default { ContextEngineService, getContextEngine, initializeContextEngine, };