UNPKG

recoder-shared

Version:

Shared types, utilities, and configurations for Recoder

420 lines (418 loc) 17.3 kB
"use strict"; /** * Shared AI Provider Integration for Recoder.xyz Ecosystem * * Provides consistent AI provider access across CLI, Web Platform, and VS Code Extension */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createExtensionAIProvider = exports.createWebAIProvider = exports.createCLIAIProvider = exports.SharedAIProviderManager = exports.GroqProvider = exports.ClaudeProvider = void 0; const unified_config_1 = require("../config/unified-config"); const session_manager_1 = require("../session/session-manager"); /** * Claude AI Provider Implementation */ class ClaudeProvider { constructor() { this.name = 'claude'; this.displayName = 'Claude (Anthropic)'; this.models = ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022']; this.useCases = ['complex-logic', 'architecture', 'security', 'code-review']; } async isAvailable() { const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); return config.getAIProviders()['claude'].enabled; } async testConnection() { try { const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); const claudeConfig = config.getAIProviders()['claude']; if (!claudeConfig.apiKey) { return false; } const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': claudeConfig.apiKey, 'anthropic-version': '2023-06-01' }, body: JSON.stringify({ model: 'claude-3-5-haiku-20241022', max_tokens: 10, messages: [{ role: 'user', content: 'Hello' }] }) }); return response.ok; } catch (error) { return false; } } async generateCode(request) { const startTime = Date.now(); const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); const claudeConfig = config.getAIProviders()['claude']; if (!claudeConfig.apiKey) { throw new Error('Claude API key not configured'); } const enhancedPrompt = this.buildProductionPrompt(request); const model = request.options?.model || this.models[0]; try { const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': claudeConfig.apiKey, 'anthropic-version': '2023-06-01' }, body: JSON.stringify({ model, max_tokens: request.options?.maxTokens || 4000, temperature: request.options?.temperature || 0.1, messages: [{ role: 'user', content: enhancedPrompt }] }) }); if (!response.ok) { throw new Error(`Claude API error: ${response.status}`); } const data = await response.json(); const endTime = Date.now(); return this.parseResponse(data, request, startTime, endTime); } catch (error) { throw new Error(`Claude generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } buildProductionPrompt(request) { const systemPrompt = `You are Recoder, an AI that generates REAL, PRODUCTION-READY code. Never create mock implementations. CRITICAL REQUIREMENTS: - Generate ACTUAL working code with real functionality - Include proper error handling and validation - Use real API integrations and database operations - Include comprehensive TypeScript types - Generate working implementations, not placeholders - Add proper security measures - Use environment variables for configuration ${request.options?.includeTests ? '- Include comprehensive test suites' : ''} ${request.options?.includeDocs ? '- Include detailed documentation' : ''}`; let contextInfo = ''; if (request.context) { contextInfo = `\n\nProject Context: - Language: ${request.context.language || 'typescript'} - Framework: ${request.context.framework || 'Not specified'} - Project Type: ${request.context.projectType || 'General'} - Files: ${request.context.files?.length || 0} files in context`; } return `${systemPrompt}${contextInfo}\n\nUser Request: ${request.prompt}\n\nGenerate complete, production-ready code:`; } parseResponse(data, request, startTime, endTime) { const content = data.content[0]?.text || ''; const code = this.extractCodeFromResponse(content); return { code, explanation: this.extractExplanation(content), confidence: 0.9, provider: 'claude', model: request.options?.model || this.models[0], tokens: { input: data.usage?.input_tokens || 0, output: data.usage?.output_tokens || 0, total: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0) }, metadata: { language: request.context?.language || 'typescript', framework: request.context?.framework, dependencies: this.extractDependencies(code), realFunctionality: true, qualityScore: 0.9, securityScore: 0.85 }, timing: { startTime, endTime, duration: endTime - startTime } }; } extractCodeFromResponse(response) { const codeBlockRegex = /```(?:\w+)?\n([\s\S]*?)\n```/g; const matches = response.match(codeBlockRegex); if (matches && matches.length > 0) { return matches .map(match => match.replace(/```(?:\w+)?\n/, '').replace(/\n```$/, '')) .sort((a, b) => b.length - a.length)[0]; } return response; } extractExplanation(response) { const lines = response.split('\n'); const explanationStart = lines.findIndex(line => line.includes('## Explanation')); const codeStart = lines.findIndex(line => line.includes('```')); if (explanationStart >= 0 && codeStart > explanationStart) { return lines.slice(explanationStart + 1, codeStart).join('\n').trim(); } return 'Code generated successfully with Claude AI'; } extractDependencies(code) { const dependencies = []; const importRegex = /import.*from ['"]([^'"]+)['"]/g; let match; while ((match = importRegex.exec(code)) !== null) { const packageName = match[1]; if (!packageName.startsWith('.') && !packageName.startsWith('/')) { dependencies.push(packageName.split('/')[0]); } } return [...new Set(dependencies)]; } } exports.ClaudeProvider = ClaudeProvider; /** * Groq AI Provider Implementation */ class GroqProvider { constructor() { this.name = 'groq'; this.displayName = 'Groq'; this.models = ['llama-3.1-70b-versatile', 'llama-3.1-8b-instant']; this.useCases = ['fast-generation', 'api-endpoints', 'prototyping', 'react']; } async isAvailable() { const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); return config.getAIProviders()['groq'].enabled; } async testConnection() { try { const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); const groqConfig = config.getAIProviders()['groq']; if (!groqConfig.apiKey) { return false; } const response = await fetch('https://api.groq.com/openai/v1/models', { headers: { 'Authorization': `Bearer ${groqConfig.apiKey}` } }); return response.ok; } catch (error) { return false; } } async generateCode(request) { const startTime = Date.now(); const config = unified_config_1.UnifiedConfigManager.getInstance('cli'); const groqConfig = config.getAIProviders()['groq']; if (!groqConfig.apiKey) { throw new Error('Groq API key not configured'); } const model = request.options?.model || this.models[0]; try { const response = await fetch('https://api.groq.com/openai/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${groqConfig.apiKey}` }, body: JSON.stringify({ model, messages: [ { role: 'system', content: 'You are Recoder, an AI that generates real, production-ready code. Never create mock implementations.' }, { role: 'user', content: request.prompt } ], temperature: request.options?.temperature || 0.2, max_tokens: request.options?.maxTokens || 4000 }) }); if (!response.ok) { throw new Error(`Groq API error: ${response.status}`); } const data = await response.json(); const endTime = Date.now(); return this.parseResponse(data, request, startTime, endTime); } catch (error) { throw new Error(`Groq generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } } parseResponse(data, request, startTime, endTime) { const content = data.choices[0]?.message?.content || ''; const code = this.extractCodeFromResponse(content); return { code, explanation: 'Fast code generation with Groq LLaMA', confidence: 0.8, provider: 'groq', model: request.options?.model || this.models[0], tokens: { input: data.usage?.prompt_tokens || 0, output: data.usage?.completion_tokens || 0, total: data.usage?.total_tokens || 0 }, metadata: { language: request.context?.language || 'typescript', framework: request.context?.framework, dependencies: this.extractDependencies(code), realFunctionality: true, qualityScore: 0.8, securityScore: 0.75 }, timing: { startTime, endTime, duration: endTime - startTime } }; } extractCodeFromResponse(response) { const codeBlockRegex = /```(?:\w+)?\n([\s\S]*?)\n```/g; const matches = response.match(codeBlockRegex); if (matches && matches.length > 0) { return matches[0].replace(/```(?:\w+)?\n/, '').replace(/\n```$/, ''); } return response; } extractDependencies(code) { // Similar implementation to Claude return []; } } exports.GroqProvider = GroqProvider; /** * Shared AI Provider Manager */ class SharedAIProviderManager { constructor(platform) { this.providers = new Map(); this.config = unified_config_1.UnifiedConfigManager.getInstance(platform); this.sessionManager = session_manager_1.SessionManager.getInstance(platform); this.initializeProviders(); } static getInstance(platform) { if (!SharedAIProviderManager.instance) { SharedAIProviderManager.instance = new SharedAIProviderManager(platform); } return SharedAIProviderManager.instance; } initializeProviders() { this.providers.set('claude', new ClaudeProvider()); this.providers.set('groq', new GroqProvider()); // Additional providers would be added here } async generateCode(request) { // Intelligent provider selection if not specified const provider = request.options?.provider || await this.selectOptimalProvider(request); const aiProvider = this.providers.get(provider); if (!aiProvider) { throw new Error(`Provider ${provider} not found`); } if (!(await aiProvider.isAvailable())) { throw new Error(`Provider ${provider} is not available`); } try { const result = await aiProvider.generateCode(request); // Log to session if available if (request.metadata?.sessionId) { this.sessionManager.setCurrentSession(request.metadata.sessionId); this.sessionManager.addMessage(request.prompt, 'user'); this.sessionManager.addMessage(result.code, 'assistant', { provider: result.provider, model: result.model, tokens: result.tokens.total, confidence: result.confidence }); } // Validate code quality if enabled if (this.config.getConfig().qualityValidation) { await this.validateCodeQuality(result); } return result; } catch (error) { // Try fallback provider const fallbackProvider = await this.getFallbackProvider(provider); if (fallbackProvider) { console.warn(`Primary provider failed, falling back to ${fallbackProvider.name}`); return await fallbackProvider.generateCode(request); } throw error; } } async selectOptimalProvider(request) { const enabledProviders = this.config.getEnabledProviders(); if (enabledProviders.length === 0) { throw new Error('No AI providers enabled'); } // Analyze prompt for best provider selection const promptLower = request.prompt.toLowerCase(); // Complex logic, security -> Claude if (promptLower.includes('security') || promptLower.includes('auth') || promptLower.includes('complex') || promptLower.includes('architecture')) { const claude = enabledProviders.find(p => p.name === 'claude'); if (claude) return 'claude'; } // Fast prototyping, APIs -> Groq if (promptLower.includes('api') || promptLower.includes('endpoint') || promptLower.includes('fast') || promptLower.includes('react')) { const groq = enabledProviders.find(p => p.name === 'groq'); if (groq) return 'groq'; } // Default to first enabled provider return enabledProviders[0].name; } async getFallbackProvider(failedProvider) { const enabledProviders = this.config.getEnabledProviders(); const fallback = enabledProviders.find(p => p.name !== failedProvider); if (fallback) { return this.providers.get(fallback.name) || null; } return null; } async validateCodeQuality(result) { const mockIndicators = [ 'TODO:', 'placeholder', 'mock implementation', 'not implemented', 'throw new Error("Not implemented")' ]; const lowerCode = result.code.toLowerCase(); const hasMockImplementation = mockIndicators.some(indicator => lowerCode.includes(indicator.toLowerCase())); if (hasMockImplementation) { throw new Error('Generated code contains mock implementations. Recoder only generates real, production-ready code.'); } } getAvailableProviders() { return Array.from(this.providers.values()); } async testAllProviders() { const results = {}; for (const [name, provider] of this.providers) { try { results[name] = await provider.testConnection(); } catch (error) { results[name] = false; } } return results; } } exports.SharedAIProviderManager = SharedAIProviderManager; // Export factory functions for each platform const createCLIAIProvider = () => SharedAIProviderManager.getInstance('cli'); exports.createCLIAIProvider = createCLIAIProvider; const createWebAIProvider = () => SharedAIProviderManager.getInstance('web'); exports.createWebAIProvider = createWebAIProvider; const createExtensionAIProvider = () => SharedAIProviderManager.getInstance('extension'); exports.createExtensionAIProvider = createExtensionAIProvider; exports.default = SharedAIProviderManager; //# sourceMappingURL=shared-ai-provider.js.map