Skip to main content
Glama

CodeCompass MCP

openai.ts19.6 kB
import OpenAI from 'openai'; import { GitHubRepoInfo, ChatContext, RefactoringPlan, ArchitectureExplanation } from '../types/index.js'; export class OpenAIService { private openai: OpenAI; private currentConfig: { apiKey: string; model: string; systemPrompt: string; }; // Model characteristics for intelligent selection and warnings private modelCharacteristics = { 'anthropic/claude-3.5-sonnet': { speed: 'fast', cost: 'medium', quality: 'high', recommended: true }, 'anthropic/claude-3-opus': { speed: 'slow', cost: 'high', quality: 'highest', recommended: false }, 'anthropic/claude-3-haiku': { speed: 'fastest', cost: 'low', quality: 'good', recommended: true }, 'openai/gpt-4o': { speed: 'fast', cost: 'medium', quality: 'high', recommended: true }, 'openai/gpt-4o-mini': { speed: 'fastest', cost: 'low', quality: 'good', recommended: true }, 'openai/gpt-4-turbo': { speed: 'medium', cost: 'medium', quality: 'high', recommended: true }, 'openai/o1-mini': { speed: 'slow', cost: 'high', quality: 'highest', recommended: false }, 'openai/o1-preview': { speed: 'slowest', cost: 'highest', quality: 'highest', recommended: false }, 'meta-llama/llama-3.1-405b-instruct': { speed: 'medium', cost: 'high', quality: 'high', recommended: false }, }; constructor() { this.currentConfig = { apiKey: process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || '', model: process.env.OPENAI_MODEL || 'anthropic/claude-3.5-sonnet', systemPrompt: `You are CodeCompass AI, an expert assistant specialized in code analysis, refactoring, and architectural guidance. Your primary role is to help developers understand, analyze, and refactor code from GitHub repositories for integration into their own projects. Core Capabilities: 1. Code Analysis: Understand code structure, patterns, and dependencies 2. Refactoring Guidance: Suggest improvements and modernization strategies 3. Architecture Explanation: Explain design patterns and architectural decisions 4. Integration Support: Help adapt code for different projects and frameworks 5. Best Practices: Recommend coding standards and optimization techniques Response Guidelines: - Provide clear, actionable advice with code examples - Focus on practical solutions that can be implemented - Consider maintainability, performance, and scalability - Explain the reasoning behind recommendations - Suggest multiple approaches when appropriate - Include potential risks and trade-offs Communication Style: - Be concise but comprehensive - Use code examples to illustrate points - Structure responses with clear headings - Prioritize actionable insights over theoretical discussions`, }; this.openai = new OpenAI({ apiKey: this.currentConfig.apiKey, baseURL: 'https://openrouter.ai/api/v1', defaultHeaders: { 'HTTP-Referer': 'https://github.com/codecompass/codecompass-mcp', 'X-Title': 'CodeCompass MCP Server', }, }); } updateConfig(config: { apiKey?: string; model?: string; systemPrompt?: string }) { if (config.apiKey) { this.currentConfig.apiKey = config.apiKey; this.openai = new OpenAI({ apiKey: config.apiKey, baseURL: 'https://openrouter.ai/api/v1', defaultHeaders: { 'HTTP-Referer': 'https://github.com/codecompass/codecompass-mcp', 'X-Title': 'CodeCompass MCP Server', }, }); } if (config.model) this.currentConfig.model = config.model; if (config.systemPrompt) this.currentConfig.systemPrompt = config.systemPrompt; } // Intelligent model selection based on task type private selectModel(requestedModel: string | undefined, taskType: 'review' | 'explain' | 'refactor', isBatchJob: boolean = false): string { if (requestedModel && requestedModel !== 'auto') { return requestedModel; } // Auto model selection logic if (isBatchJob) { // For batch jobs, prefer faster, cost-effective models return 'openai/gpt-4o-mini'; } // Task-specific model selection switch (taskType) { case 'review': return 'anthropic/claude-3.5-sonnet'; // Good balance of quality and speed case 'explain': return 'openai/gpt-4o'; // Good for explanations case 'refactor': return 'anthropic/claude-3.5-sonnet'; // Good for strategic thinking default: return this.currentConfig.model; } } // Generate model warning message private generateModelWarning(model: string, isBatchJob: boolean = false): string | undefined { const characteristics = this.modelCharacteristics[model as keyof typeof this.modelCharacteristics]; if (!characteristics) return undefined; const warnings = []; if (isBatchJob) { if (characteristics.speed === 'slow' || characteristics.speed === 'slowest') { warnings.push(`⚠️ Model ${model} is ${characteristics.speed} - batch job may take significant time`); } if (characteristics.cost === 'high' || characteristics.cost === 'highest') { warnings.push(`💰 Model ${model} has ${characteristics.cost} cost - batch job may be expensive`); } } else { if (characteristics.speed === 'slowest') { warnings.push(`⚠️ Model ${model} is very slow - expect longer response times`); } if (characteristics.cost === 'highest') { warnings.push(`💰 Model ${model} has highest cost - consider alternatives for frequent use`); } } return warnings.length > 0 ? warnings.join('\n') : undefined; } // Log model selection for audit/debug private logModelSelection(model: string, requestedModel: string | undefined, taskType: string, isBatchJob: boolean) { const timestamp = new Date().toISOString(); const logEntry = { timestamp, taskType, requestedModel: requestedModel || 'auto', selectedModel: model, isBatchJob, characteristics: this.modelCharacteristics[model as keyof typeof this.modelCharacteristics] }; console.log(`[MODEL_SELECTION] ${JSON.stringify(logEntry)}`); } async chatWithRepository(url: string, message: string, context?: ChatContext, model?: string, isBatchJob: boolean = false): Promise<{ content: string; modelUsed: string; warning?: string }> { if (!this.currentConfig.apiKey) { throw new Error('OpenRouter API key not configured. Please set OPENROUTER_API_KEY environment variable.'); } // Select model intelligently const modelToUse = this.selectModel(model, 'explain', isBatchJob); // Log model selection this.logModelSelection(modelToUse, model, 'explain_code', isBatchJob); // Generate warning if needed const warning = this.generateModelWarning(modelToUse, isBatchJob); try { const messages: any[] = [ { role: 'system', content: this.currentConfig.systemPrompt }, ]; // Add context if provided if (context) { const contextMessage = this.buildContextMessage(context); messages.push({ role: 'system', content: contextMessage }); // Add conversation history if (context.conversationHistory) { messages.push(...context.conversationHistory.map(msg => ({ role: msg.role, content: msg.content, }))); } } messages.push({ role: 'user', content: message }); const response = await this.openai.chat.completions.create({ model: modelToUse, messages, max_tokens: 2000, temperature: 0.7, }); const content = response.choices[0].message.content || 'I apologize, but I couldn\'t generate a response.'; return { content, modelUsed: modelToUse, warning }; } catch (error: any) { console.error('OpenAI API error:', error); throw new Error(`Failed to generate response: ${error.message}`); } } async suggestRefactoringPlan(url: string, targetProject: any, goals?: string[], model?: string, isBatchJob: boolean = false): Promise<{ content: string; modelUsed: string; warning?: string }> { if (!this.currentConfig.apiKey) { throw new Error('OpenRouter API key not configured. Please set OPENROUTER_API_KEY environment variable.'); } // Select model intelligently const modelToUse = this.selectModel(model, 'refactor', isBatchJob); // Log model selection this.logModelSelection(modelToUse, model, 'refactor_suggestions', isBatchJob); // Generate warning if needed const warning = this.generateModelWarning(modelToUse, isBatchJob); const prompt = ` Analyze the repository at ${url} and create a comprehensive refactoring plan. Target Project Context: - Framework: ${targetProject.framework} - Language: ${targetProject.language || 'Not specified'} - Constraints: ${targetProject.constraints?.join(', ') || 'None specified'} - Timeline: ${targetProject.timeline || 'Not specified'} Refactoring Goals: ${goals?.map(goal => `- ${goal}`).join('\n') || '- General modernization and improvement'} Please provide a detailed refactoring plan that includes: 1. Executive Summary 2. Phase-by-phase breakdown 3. Time estimates for each phase 4. Risk assessment 5. Success metrics 6. Recommended tools and resources Format the response as a structured plan with clear sections and actionable items. `; try { const response = await this.openai.chat.completions.create({ model: modelToUse, messages: [ { role: 'system', content: this.currentConfig.systemPrompt }, { role: 'user', content: prompt }, ], max_tokens: 1800, temperature: 0.7, }); const content = response.choices[0].message.content || 'Failed to generate refactoring plan.'; return { content, modelUsed: modelToUse, warning }; } catch (error: any) { throw new Error(`Failed to generate refactoring plan: ${error.message}`); } } async explainArchitecture(url: string, repositoryInfo?: GitHubRepoInfo): Promise<string> { if (!this.currentConfig.apiKey) { throw new Error('OpenRouter API key not configured. Please set OPENROUTER_API_KEY environment variable.'); } let contextInfo = ''; if (repositoryInfo) { contextInfo = ` Repository Information: - Name: ${repositoryInfo.name} - Description: ${repositoryInfo.description || 'No description'} - Primary Language: ${repositoryInfo.language || 'Unknown'} - File Count: ${repositoryInfo.fileCount} - Key Files: ${Object.keys(repositoryInfo.keyFiles).join(', ')} File Structure: ${JSON.stringify(repositoryInfo.fileTree, null, 2)} Key File Contents: ${Object.entries(repositoryInfo.keyFiles).map(([path, content]) => `--- ${path} ---\n${content.substring(0, 1000)}${content.length > 1000 ? '...' : ''}` ).join('\n\n')} `; } const prompt = ` Explain the architecture of the repository at ${url} in detail. ${contextInfo} Please provide a comprehensive architectural explanation that covers: 1. Overall Architecture Overview 2. Design Patterns Used 3. Project Structure and Organization 4. Data Flow and Components 5. Dependencies and External Integrations 6. Strengths and Potential Improvements 7. Scalability Considerations 8. Recommendations for Different Use Cases Make the explanation accessible to developers who want to understand and potentially adapt this architecture for their own projects. `; try { const response = await this.openai.chat.completions.create({ model: this.currentConfig.model, messages: [ { role: 'system', content: this.currentConfig.systemPrompt }, { role: 'user', content: prompt }, ], max_tokens: 1800, temperature: 0.7, }); return response.choices[0].message.content || 'Failed to generate architecture explanation.'; } catch (error: any) { throw new Error(`Failed to explain architecture: ${error.message}`); } } async generateCodeReview(code: string, language: string, focusAreas?: string[], model?: string, isBatchJob: boolean = false): Promise<{ content: string; modelUsed: string; warning?: string }> { if (!this.currentConfig.apiKey) { throw new Error('OpenRouter API key not configured. Please set OPENROUTER_API_KEY environment variable.'); } // Select model intelligently const modelToUse = this.selectModel(model, 'review', isBatchJob); // Log model selection this.logModelSelection(modelToUse, model, 'code_review', isBatchJob); // Generate warning if needed const warning = this.generateModelWarning(modelToUse, isBatchJob); const prompt = ` Please provide a comprehensive code review for the following ${language} code. ${focusAreas ? `Focus Areas: ${focusAreas.join(', ')}` : ''} Code to review: \`\`\`${language} ${code} \`\`\` Please provide feedback on: 1. Code Quality and Best Practices 2. Potential Bugs and Issues 3. Performance Optimizations 4. Security Considerations 5. Maintainability and Readability 6. Refactoring Suggestions 7. Testing Recommendations Format your response with clear sections and provide specific code examples for improvements. `; try { const response = await this.openai.chat.completions.create({ model: modelToUse, messages: [ { role: 'system', content: this.currentConfig.systemPrompt }, { role: 'user', content: prompt }, ], max_tokens: 1800, temperature: 0.7, }); const content = response.choices[0].message.content || 'Failed to generate code review.'; return { content, modelUsed: modelToUse, warning }; } catch (error: any) { throw new Error(`Failed to generate code review: ${error.message}`); } } async generateRefactoringPlan(repositoryInfo: GitHubRepoInfo, goals: string[]): Promise<RefactoringPlan> { if (!this.currentConfig.apiKey) { throw new Error('OpenRouter API key not configured. Please set OPENROUTER_API_KEY environment variable.'); } const prompt = ` Create a detailed refactoring plan for the following repository: Repository: ${repositoryInfo.name} Description: ${repositoryInfo.description} Language: ${repositoryInfo.language} File Count: ${repositoryInfo.fileCount} Goals: ${goals.join(', ')} Please provide a JSON response with the following structure: { "overview": "Brief overview of the refactoring plan", "phases": [ { "name": "Phase name", "description": "Phase description", "tasks": [ { "name": "Task name", "description": "Task description", "type": "extract|transform|modernize|optimize|test", "files": ["file1.js", "file2.js"], "estimatedTimeHours": 4, "priority": "low|medium|high" } ], "estimatedTimeHours": 16, "dependencies": ["Phase 1", "Phase 2"] } ], "estimatedTimeHours": 40, "risks": ["Risk 1", "Risk 2"], "recommendations": ["Recommendation 1", "Recommendation 2"] } `; try { const response = await this.openai.chat.completions.create({ model: this.currentConfig.model, messages: [ { role: 'system', content: this.currentConfig.systemPrompt }, { role: 'user', content: prompt }, ], max_tokens: 2000, temperature: 0.7, }); const content = response.choices[0].message.content; if (!content) { throw new Error('No response generated'); } try { return JSON.parse(content); } catch (parseError) { // If JSON parsing fails, return a basic structure return { overview: content.substring(0, 200) + '...', phases: [], estimatedTimeHours: 0, risks: ['Failed to parse detailed plan'], recommendations: ['Review the generated plan manually'], }; } } catch (error: any) { throw new Error(`Failed to generate refactoring plan: ${error.message}`); } } async generateWelcomeMessage(repositoryInfo: GitHubRepoInfo): Promise<string> { if (!this.currentConfig.apiKey) { // Return a default welcome message if no API key is configured return `Hello! I've analyzed the ${repositoryInfo.name} repository and I'm ready to help you understand and refactor the codebase. ⚠️ **Setup Required**: To enable AI-powered features, please configure your OpenAI API key. Repository Overview: - **${repositoryInfo.name}** by ${repositoryInfo.owner} - Language: ${repositoryInfo.language || 'Multiple'} - Files: ${repositoryInfo.fileCount} - Stars: ${repositoryInfo.stars} I can help you with: - Code analysis and understanding - Refactoring suggestions - Architecture explanations - Component extraction - Integration guidance What would you like to know about this repository?`; } const prompt = ` Generate a welcoming introduction message for a repository analysis chat. The repository is: - Name: ${repositoryInfo.name} - Description: ${repositoryInfo.description || 'No description'} - Primary Language: ${repositoryInfo.language || 'Unknown'} - ${repositoryInfo.fileCount} files - ${repositoryInfo.stars} stars Create a friendly, professional greeting that: 1. Welcomes the user 2. Briefly summarizes what I found in the repository 3. Mentions what I can help with regarding refactoring and code analysis 4. Asks what they'd like to know Keep it concise (3-4 sentences) and engaging. `; try { const response = await this.openai.chat.completions.create({ model: this.currentConfig.model, messages: [ { role: 'system', content: this.currentConfig.systemPrompt }, { role: 'user', content: prompt }, ], max_tokens: 300, temperature: 0.8, }); return response.choices[0].message.content || `Hello! I've analyzed the ${repositoryInfo.name} repository. I can help you understand the codebase, suggest refactoring opportunities, and guide you through integrating components into your own projects. What would you like to explore?`; } catch (error) { return `Hello! I've analyzed the ${repositoryInfo.name} repository. I can help you understand the codebase, suggest refactoring opportunities, and guide you through integrating components into your own projects. What would you like to explore?`; } } private buildContextMessage(context: ChatContext): string { let contextMessage = `Repository Context: ${context.repositoryUrl}\n`; if (context.currentFile) { contextMessage += `Current File: ${context.currentFile}\n`; } if (context.selectedCode) { contextMessage += `Selected Code:\n\`\`\`\n${context.selectedCode}\n\`\`\`\n`; } if (context.refactoringGoals && context.refactoringGoals.length > 0) { contextMessage += `Refactoring Goals: ${context.refactoringGoals.join(', ')}\n`; } return contextMessage; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TheAlchemist6/codecompass-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server