UNPKG

giga-code

Version:

A personal AI CLI assistant powered by Grok for local development.

343 lines 14.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RAGContextService = void 0; const rag_service_1 = require("./rag-service"); const chunking_service_1 = require("./chunking-service"); const rag_config_1 = require("../utils/rag-config"); const prompt_enhancer_1 = require("../utils/prompt-enhancer"); const path = __importStar(require("path")); class RAGContextService { constructor(projectPath = process.cwd()) { this.initialized = false; this.projectPath = projectPath; const config = rag_config_1.RAGConfigManager.loadConfig(projectPath); this.ragService = new rag_service_1.RAGService(projectPath, config); this.chunkingService = new chunking_service_1.ChunkingService(projectPath, config); } async initialize() { if (this.initialized) { return; } try { await this.ragService.initialize(); this.initialized = true; } catch (error) { // Don't throw - allow GIGA to work without RAG this.initialized = false; } } async enrichUserPrompt(userPrompt, recentBashOutput, conversationHistory) { // Check if RAG is enabled const config = rag_config_1.RAGConfigManager.loadConfig(this.projectPath); if (!config.enabled) { return { shouldEnrich: false, enhancedPrompt: userPrompt, relevantContext: '', searchResults: [], confidence: 0, processedOriginal: { originalPrompt: userPrompt, enhancedPrompt: userPrompt, extractedFiles: [], extractedKeywords: [], detectedIntent: prompt_enhancer_1.PromptEnhancer.extractMainTopic(userPrompt), suggestedSearchQueries: [], confidence: 0 } }; } try { await this.initialize(); // If RAG initialization failed, return without enrichment if (!this.initialized) { const enhanced = prompt_enhancer_1.PromptEnhancer.enhancePrompt(userPrompt, recentBashOutput); return { shouldEnrich: false, enhancedPrompt: enhanced.enhancedPrompt, relevantContext: '', searchResults: [], confidence: enhanced.confidence, processedOriginal: enhanced }; } // Process and enhance the prompt const enhanced = prompt_enhancer_1.PromptEnhancer.enhancePrompt(userPrompt, recentBashOutput); // Determine if we should enrich based on various factors const shouldEnrich = this.shouldEnrichPrompt(enhanced, conversationHistory); if (!shouldEnrich) { return { shouldEnrich: false, enhancedPrompt: enhanced.enhancedPrompt, relevantContext: '', searchResults: [], confidence: enhanced.confidence, processedOriginal: enhanced }; } // Perform semantic search using the enhanced queries const searchResults = await this.performContextualSearch(enhanced); // Generate relevant context from search results const relevantContext = this.generateRelevantContext(searchResults, enhanced); // Create final enriched prompt const finalEnhancedPrompt = this.createContextEnrichedPrompt(enhanced.enhancedPrompt, relevantContext, enhanced); return { shouldEnrich: true, enhancedPrompt: finalEnhancedPrompt, relevantContext, searchResults, confidence: Math.max(enhanced.confidence, searchResults.length > 0 ? 0.7 : 0.3), processedOriginal: enhanced }; } catch (error) { console.error('Failed to enrich prompt with context:', error); // Fallback to basic enhancement const enhanced = prompt_enhancer_1.PromptEnhancer.enhancePrompt(userPrompt, recentBashOutput); return { shouldEnrich: false, enhancedPrompt: enhanced.enhancedPrompt, relevantContext: '', searchResults: [], confidence: enhanced.confidence, processedOriginal: enhanced }; } } shouldEnrichPrompt(enhanced, conversationHistory) { // Always enrich if we have high confidence in the intent if (enhanced.confidence >= 0.7) { return true; } // Enrich if we found specific files or technical keywords if (enhanced.extractedFiles.length > 0 || enhanced.extractedKeywords.length >= 2) { return true; } // Always enrich search queries - they need RAG context if (enhanced.detectedIntent === 'search') { return true; } // Enrich if the prompt seems to be about code analysis or error fixing if (enhanced.detectedIntent === 'code_analysis' || enhanced.detectedIntent === 'error_fixing') { return true; } // Enrich if the prompt is very short and might benefit from context if (enhanced.originalPrompt.trim().split(' ').length <= 5) { return true; } // Don't enrich for very general conversations if (enhanced.detectedIntent === 'general' && enhanced.extractedFiles.length === 0) { return false; } return false; } async performContextualSearch(enhanced) { const allResults = []; const seenChunks = new Set(); // Search using original prompt const originalResults = await this.ragService.search(enhanced.originalPrompt, 3); for (const result of originalResults) { if (!seenChunks.has(result.chunk.id)) { allResults.push(result); seenChunks.add(result.chunk.id); } } // Search using suggested queries for (const query of enhanced.suggestedSearchQueries.slice(0, 3)) { // Limit to first 3 try { const queryResults = await this.ragService.search(query, 2); for (const result of queryResults) { if (!seenChunks.has(result.chunk.id)) { allResults.push(result); seenChunks.add(result.chunk.id); } } } catch (error) { } } // Search for specific files mentioned for (const file of enhanced.extractedFiles.slice(0, 2)) { // Limit to first 2 try { const fileName = path.basename(file); const fileResults = await this.ragService.search(fileName, 2); for (const result of fileResults) { if (!seenChunks.has(result.chunk.id)) { allResults.push(result); seenChunks.add(result.chunk.id); } } } catch (error) { } } // Sort by score and return top results return allResults .sort((a, b) => b.score - a.score) .slice(0, 5); // Limit total results } generateRelevantContext(searchResults, enhanced) { if (searchResults.length === 0) { return ''; } const contextParts = []; // For search queries, show clean RAG results with percentages if (enhanced.detectedIntent === 'search') { contextParts.push(`🔍 RAG Search Results for "${enhanced.originalPrompt}":\n`); for (let i = 0; i < Math.min(searchResults.length, 5); i++) { const result = searchResults[i]; const chunk = result.chunk; const percentage = Math.round(result.score * 100); const filePath = path.relative(this.projectPath, chunk.filePath); // Format: ├── 📄 file:line (95% match) const icon = i === searchResults.length - 1 || i === 4 ? '└──' : '├──'; contextParts.push(`${icon} 📄 ${filePath}${chunk.startLine ? `:${chunk.startLine}` : ''} (${percentage}% match)`); // Show a preview of the code const preview = chunk.content.length > 100 ? chunk.content.substring(0, 100).trim() + '...' : chunk.content.trim(); contextParts.push(`│ ├── Code: ${preview.split('\n')[0]}`); contextParts.push(`│ └── Context: ${chunk.type}${chunk.name ? ` "${chunk.name}"` : ''}`); if (i < Math.min(searchResults.length - 1, 4)) { contextParts.push('│'); } } return contextParts.join('\n') + '\n'; } // For non-search queries, use the existing detailed format contextParts.push('## Relevant Code Context\n'); // Group results by file for better organization const resultsByFile = new Map(); for (const result of searchResults) { const filePath = result.chunk.filePath; if (!resultsByFile.has(filePath)) { resultsByFile.set(filePath, []); } resultsByFile.get(filePath).push(result); } // Add context for each file let contextLength = 0; const maxContextLength = 3000; // Limit total context length for (const [filePath, results] of resultsByFile.entries()) { if (contextLength >= maxContextLength) break; contextParts.push(`### ${path.relative(this.projectPath, filePath)}\n`); for (const result of results.slice(0, 2)) { // Max 2 chunks per file if (contextLength >= maxContextLength) break; const chunk = result.chunk; const preview = chunk.content.length > 500 ? chunk.content.substring(0, 500) + '...' : chunk.content; contextParts.push(`**${chunk.type}${chunk.name ? ` "${chunk.name}"` : ''}** (Score: ${result.score.toFixed(2)})`); contextParts.push('```' + (chunk.metadata.language || 'text')); contextParts.push(preview); contextParts.push('```\n'); contextLength += preview.length; } } return contextParts.join('\n'); } createContextEnrichedPrompt(enhancedPrompt, relevantContext, enhanced) { if (!relevantContext.trim()) { return enhancedPrompt; } const parts = []; // Add the original enhanced prompt parts.push(enhancedPrompt); // Add a separator parts.push('\n---\n'); // Add the relevant context parts.push(relevantContext); // Add instructions for using the context parts.push('\n**Instructions:**'); parts.push('- Use the above code context to provide more accurate and specific responses'); parts.push('- Reference specific files, functions, or code patterns when relevant'); parts.push('- If the context doesn\'t seem relevant, feel free to ignore it and respond based on your general knowledge'); return parts.join('\n'); } async indexProject() { try { await this.initialize(); const { chunks, stats } = await this.chunkingService.chunkProject(); if (chunks.length === 0) { return; } await this.ragService.indexChunks(chunks); if (stats.errors.length > 0) { } } catch (error) { console.error('Failed to index project:', error); throw error; } } async searchCode(query, maxResults = 5) { try { await this.initialize(); return await this.ragService.search(query, maxResults); } catch (error) { console.error('Failed to search code:', error); return []; } } async getIndexInfo() { try { await this.initialize(); const info = await this.ragService.getCollectionInfo(); return { count: info.count, enabled: info.config.enabled }; } catch (error) { console.error('Failed to get index info:', error); return { count: 0, enabled: false }; } } async clearIndex() { try { await this.initialize(); await this.ragService.clearCollection(); } catch (error) { console.error('Failed to clear index:', error); throw error; } } updateConfig(updates) { const newConfig = rag_config_1.RAGConfigManager.updateConfig(updates, this.projectPath); this.ragService.updateConfig(newConfig); this.chunkingService.updateConfig(newConfig); } isEnabled() { return rag_config_1.RAGConfigManager.isRAGEnabled(this.projectPath); } } exports.RAGContextService = RAGContextService; //# sourceMappingURL=rag-context-service.js.map