UNPKG

jay-code

Version:

Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability

196 lines (172 loc) 6.43 kB
/** * System Requirements Detection for Jay-Code * Detects VRAM, RAM, and determines optimal model configuration */ import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); export interface SystemCapabilities { totalVRAM: number; // MB availableVRAM: number; // MB totalRAM: number; // MB availableRAM: number; // MB gpuCount: number; gpuModels: string[]; canRunLocal: boolean; recommendedModel: 'local' | 'api'; platform: 'linux' | 'darwin' | 'win32'; } export class SystemDetector { async detectCapabilities(): Promise<SystemCapabilities> { const platform = process.platform as 'linux' | 'darwin' | 'win32'; const [vramInfo, ramInfo, gpuInfo] = await Promise.all([ this.detectVRAM(platform), this.detectRAM(platform), this.detectGPUs(platform) ]); const totalVRAM = vramInfo.total; const availableVRAM = vramInfo.available; const canRunLocal = totalVRAM >= 40000; // 40GB minimum return { totalVRAM, availableVRAM, totalRAM: ramInfo.total, availableRAM: ramInfo.available, gpuCount: gpuInfo.count, gpuModels: gpuInfo.models, canRunLocal, recommendedModel: canRunLocal ? 'local' : 'api', platform }; } private async detectVRAM(platform: string): Promise<{ total: number; available: number }> { try { if (platform === 'linux') { // Try nvidia-smi first try { const { stdout } = await execAsync('nvidia-smi --query-gpu=memory.total,memory.free --format=csv,noheader,nounits'); const lines = stdout.trim().split('\n'); let totalVRAM = 0; let availableVRAM = 0; for (const line of lines) { const [total, free] = line.split(', ').map(Number); totalVRAM += total; availableVRAM += free; } return { total: totalVRAM, available: availableVRAM }; } catch (nvidiaError) { // Try ROCm for AMD GPUs try { const { stdout } = await execAsync('rocm-smi --showmeminfo vram'); // Parse ROCm output - this is simplified const vramMatch = stdout.match(/(\d+)\s*MB/); if (vramMatch) { const total = parseInt(vramMatch[1]); return { total, available: Math.floor(total * 0.8) }; } } catch (rocmError) { // Fallback to system detection return this.detectVRAMFallback(); } } } else if (platform === 'darwin') { // macOS - check for Apple Silicon unified memory try { const { stdout } = await execAsync('system_profiler SPHardwareDataType | grep "Memory:"'); const memMatch = stdout.match(/(\d+)\s*GB/); if (memMatch) { const totalGB = parseInt(memMatch[1]); // On Apple Silicon, treat as shared VRAM (conservative estimate) const vramMB = Math.floor(totalGB * 1024 * 0.6); // 60% of RAM as potential VRAM return { total: vramMB, available: Math.floor(vramMB * 0.8) }; } } catch (macError) { return this.detectVRAMFallback(); } } return this.detectVRAMFallback(); } catch (error) { console.warn('VRAM detection failed, using fallback'); return this.detectVRAMFallback(); } } private async detectVRAMFallback(): Promise<{ total: number; available: number }> { // Conservative fallback - assume no dedicated VRAM return { total: 0, available: 0 }; } private async detectRAM(platform: string): Promise<{ total: number; available: number }> { try { const totalBytes = require('os').totalmem(); const freeBytes = require('os').freemem(); return { total: Math.floor(totalBytes / 1024 / 1024), // Convert to MB available: Math.floor(freeBytes / 1024 / 1024) }; } catch (error) { return { total: 8192, available: 4096 }; // 8GB fallback } } private async detectGPUs(platform: string): Promise<{ count: number; models: string[] }> { try { if (platform === 'linux') { const { stdout } = await execAsync('lspci | grep -i "vga\\|3d\\|display"'); const lines = stdout.trim().split('\n').filter(line => line.length > 0); const models = lines.map(line => { const match = line.match(/: (.+)$/); return match ? match[1] : 'Unknown GPU'; }); return { count: models.length, models }; } else if (platform === 'darwin') { const { stdout } = await execAsync('system_profiler SPDisplaysDataType | grep "Chipset Model:"'); const models = stdout.split('\n') .filter(line => line.includes('Chipset Model:')) .map(line => line.split(':')[1]?.trim() || 'Unknown GPU'); return { count: models.length, models }; } return { count: 0, models: [] }; } catch (error) { return { count: 0, models: [] }; } } async checkOllamaCompatibility(): Promise<boolean> { const capabilities = await this.detectCapabilities(); if (!capabilities.canRunLocal) { console.log(`Insufficient VRAM: ${capabilities.totalVRAM}MB (requires 40GB)`); return false; } if (capabilities.totalRAM < 64000) { console.log(`Insufficient RAM: ${capabilities.totalRAM}MB (requires 64GB)`); return false; } return true; } async generateModelConfig(): Promise<any> { const capabilities = await this.detectCapabilities(); if (capabilities.canRunLocal) { return { type: 'local', primary: { type: 'ollama', model: 'llama3.3:70b-instruct', endpoint: 'http://localhost:11434' }, fallback: { type: 'anthropic', model: 'claude-3-5-sonnet-20241022', apiKey: '${ANTHROPIC_API_KEY}' }, recommendation: 'Using local Llama 3.3 70B for optimal performance' }; } else { return { type: 'api', primary: { type: 'anthropic', model: 'claude-3-5-sonnet-20241022', apiKey: '${ANTHROPIC_API_KEY}' }, recommendation: `Insufficient VRAM (${capabilities.totalVRAM}MB < 40GB), using Claude API` }; } } }