recoder-shared
Version:
Shared types, utilities, and configurations for Recoder
420 lines (418 loc) • 17.3 kB
JavaScript
/**
* 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
;