"Unauthorized"]); exit; } require_once __DIR__ . "/wedroid-infra-patterns.php"; require_once __DIR__ . "/wedroid-chain-executor.php"; require_once __DIR__ . "/wedroid-git-auto.php"; require_once __DIR__ . "/wedroid-telegram-alert.php"; require_once __DIR__ . "/wedroid-scheduler.php"; require_once __DIR__ . "/wedroid-learning.php"; $WEDROID_KB = @json_decode(@file_get_contents(__DIR__ . '/wedroid-knowledge-base.json'), true) ?: []; $action = $_POST["action"] ?? $_GET["action"] ?? "chat"; $message = $_POST["message"] ?? $_GET["message"] ?? ""; $session = $_POST["session"] ?? "default"; // ═══════════════════════════════════════════════════════ // PROVIDER CONFIG // ═══════════════════════════════════════════════════════ $OLLAMA_HOST = "localhost"; // S95 via SSH $OLLAMA_PORT = 11434; $OLLAMA_MODELS = [ 'fast' => 'qwen3:4b', // 2.5GB — fast, simple tasks 'general' => 'qwen3:8b', // 5.2GB — general purpose 'code' => 'qwen2.5:7b', // 4.7GB — code generation 'deep' => 'mistral:latest', // 4.4GB — reasoning ]; $CEREBRAS_KEY = "csk-4wrrhkpr568ry9xx49k9mcynwdx483nx53dd62yh5xedfckh"; $CEREBRAS_MODEL = "qwen-3-235b-a22b-instruct-2507"; $CEREBRAS_URL = "https://api.cerebras.ai/v1/chat/completions"; $GROQ_KEY = ($secrets["GROQ_KEY"]??""); $GROQ_MODEL = "llama-3.3-70b-versatile"; $GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"; // MULTI-ACCOUNT ROTATION $CEREBRAS_KEYS = [ "csk-4wrrhkpr568ry9xx49k9mcynwdx483nx53dd62yh5xedfckh", ]; $GROQ_KEYS = [ ($secrets["GROQ_KEY"]??""), ]; // ADDITIONAL PROVIDERS $SAMBANOVA_KEY = "9541b2a0-6ddc-4e7d-a957-c348d6119c3f"; $SAMBANOVA_MODEL = "DeepSeek-V3.1"; $SAMBANOVA_URL = "https://api.sambanova.ai/v1/chat/completions"; $DEEPSEEK_KEY = "sk-a296c24f77a1405d8f80105982991203"; $DEEPSEEK_MODEL = "deepseek-chat"; $DEEPSEEK_URL = "https://api.deepseek.com/v1/chat/completions"; $GEMINI_KEY = "AIzaSyBt-qfLETGALpibigmgW-o4vlxQZWaxwcE"; $GEMINI_MODEL = "gemini-2.0-flash"; $GEMINI_URL = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key="; // MISTRAL $MISTRAL_KEY = "0JBySAtEKlM8CKgE3zh8uDYGQVhdMa6M"; $MISTRAL_MODEL = "mistral-small-latest"; $MISTRAL_URL = "https://api.mistral.ai/v1/chat/completions"; // ALIBABA QWEN (DashScope) $DASHSCOPE_KEY = "sk-34db1ad3152443cd86563d1bfc576c30"; $DASHSCOPE_MODEL = "qwen3.5-plus"; $DASHSCOPE_URL = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions"; // OPENROUTER (free tier) $OPENROUTER_KEY = ($secrets["OPENROUTER_KEY"]??""); $OPENROUTER_MODEL = "meta-llama/llama-3.3-70b-instruct:free"; $OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions"; // Force provider from frontend $force_provider = $_POST["provider"] ?? $_GET["provider"] ?? "auto"; // SSH config for S95 $SSH_KEY = "/root/.ssh/wevads_key"; $SSH_USER = "root"; $SSH_HOST = "95.216.167.89"; $SSH_PORT = 49222; $SSH_CMD = "sudo SSH_AUTH_SOCK= ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -o IdentitiesOnly=yes -i $SSH_KEY -p $SSH_PORT $SSH_USER@$SSH_HOST"; // ═══════════════════════════════════════════════════════ // SESSION MEMORY (simple file-based) // ═══════════════════════════════════════════════════════ $SESSION_DIR = "/tmp/wedroid-sessions"; @mkdir($SESSION_DIR, 0777, true); $session_file = "$SESSION_DIR/$session.json"; $history = []; if(file_exists($session_file)) { $history = json_decode(file_get_contents($session_file), true) ?: []; // Keep last 10 exchanges if(count($history) > 20) $history = array_slice($history, -20); } // ═══════════════════════════════════════════════════════ // PROVIDER ROTATION (multi-account) function rotateKey($keys) { return $keys[array_rand($keys)]; } // ═══════════════════════════════════════════════════════ // ADDITIONAL PROVIDER FUNCTIONS function callSambaNova($msg, $key, $model, $url, $sys) { return callOpenAICompat($msg, $key, $model, $url, $sys); } function callDeepSeek($msg, $key, $model, $url, $sys) { return callOpenAICompat($msg, $key, $model, $url, $sys); } function callOpenAICompat($msg, $key, $model, $url, $sys) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_TIMEOUT => 60, CURLOPT_HTTPHEADER => ["Content-Type: application/json", "Authorization: Bearer $key"], CURLOPT_POSTFIELDS => json_encode([ "model" => $model, "messages" => [["role"=>"system","content"=>$sys],["role"=>"user","content"=>$msg]], "max_tokens" => 1024, "temperature" => 0.7 ]) ]); $r = curl_exec($ch); curl_close($ch); $d = json_decode($r, true); return $d["choices"][0]["message"]["content"] ?? "Error: ".($d["error"]["message"] ?? $r); } function callGemini($msg, $key, $url, $sys) { $ch = curl_init($url . $key); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_TIMEOUT => 60, CURLOPT_HTTPHEADER => ["Content-Type: application/json"], CURLOPT_POSTFIELDS => json_encode([ "contents" => [["parts" => [["text" => "$sys\n\n$msg"]]]], "generationConfig" => ["maxOutputTokens" => 1024, "temperature" => 0.7] ]) ]); $r = curl_exec($ch); curl_close($ch); $d = json_decode($r, true); return $d["candidates"][0]["content"]["parts"][0]["text"] ?? "Error: ".($d["error"]["message"] ?? $r); } // ═══════════════════════════════════════════════════════ // SYSTEM PROMPT // ═══════════════════════════════════════════════════════ $SYSTEM = "'.WEVAL_BRAND_CONTEXT.'Tu es WEDROID, un agent IA souverain qui gère l'infrastructure WEVAL Consulting. SERVEURS: - S204 (204.168.152.13): serveur principal, nginx, PHP, PostgreSQL, Node.js, WEVIA, Ethica - S95 (95.216.167.89): Arsenal, Apache, PostgreSQL, Droid CLI, Ollama, bcgapp - S151 (151.80.235.110): tracking email, OVH - 4× ECS PMTA: serveurs email delivery BASE ETHICA: 50,543 HCPs, 49,594 emails, 3 pays (TN/MA/ALG), 18 marques pharma RÈGLES: 1. Réponds en français naturel et concis 2. Si on te demande une action serveur, génère la commande bash et exécute-la 3. Pour les commandes S95: utilise shell_exec directement 4. Pour les commandes S204: préfixe avec [S204] 5. Analyse les résultats et donne un résumé clair 6. Si une commande échoue, explique pourquoi et propose une alternative 7. Pour les données Ethica: utilise l'API sur S204 (token ETHICA_API_2026_SECURE) FORMAT RÉPONSE: JSON avec les clés: thinking, response, commands (optionnel), provider COMPÉTENCES WEVIA INTÉGRÉES (16 capacités que TU possèdes): 1. frontend-design: UI production-grade, bold aesthetics, pas de AI slop 2. algorithmic-art: Art génératif p5.js, seeded randomness, philosophies computationnelles 3. canvas-design: Art visuel PDF/PNG, design philosophy → expression visuelle 4. web-artifacts-builder: React 18 + Tailwind + shadcn/ui, artifacts complexes 5. skill-creator: Créer/tester/itérer des compétences avec framework eval 6. brand-guidelines: Charte Anthropic (Dark #141413, Orange #d97757, Poppins+Lora) 7. doc-coauthoring: Track changes, comments, collaboration docx 8. pdf: Créer, merger, splitter, OCR, forms, watermarks PDF 9. docx: Créer/éditer Word avec docx-js, styles, tables, images 10. pptx: Créer/éditer PowerPoint, slides, layouts 11. xlsx: Créer/éditer Excel, formules, charts, formatting 12. internal-comms: Communications internes (emails, memos, annonces) 13. mcp-builder: Construire serveurs MCP pour intégration outils 14. theme-factory: Générer thèmes design et palettes couleurs 15. slack-gif-creator: Créer GIFs animés 16. product-self-knowledge 17. grader-agent: Évaluer assertions vs outputs 18. analyzer-agent: Analyser pourquoi une version bat une autre 19. comparator-agent: Comparaison A/B aveugle entre outputs 20. schemas-agent: Structures JSON pour evals: Connaissance produits Anthropic/Claude Quand on te demande tes compétences, CITE CETTE LISTE EXACTE. Tu ES WEVIA. Ne dis JAMAIS que tu es Qwen. "; // ═══════════════════════════════════════════════════════ // COMPLEXITY DETECTION // ═══════════════════════════════════════════════════════ function detectComplexity($msg) { $lower = mb_strtolower($msg); // SIMPLE → Ollama fast (tinyllama) — direct bash, no AI needed $simple_patterns = [ '/^(status|etat|état)$/i', '/^(ls|df|ps|top|uptime|whoami|date|pwd|free)/i', '/^(disk|disque|espace)/i', '/^(log|error|erreur)/i', ]; foreach($simple_patterns as $p) if(preg_match($p, $msg)) return 'direct'; // MEDIUM → Ollama general (llama3.1:8b) — needs understanding $medium_patterns = [ 'collecte de donnees','collecteur','cron','ethica','contact','hcp','medecin', 'git','github','push','commit','backup','sauvegarde', 'test','nonreg','regression','lance','lancer', 'serveur','server','apache','nginx','php','postgresql', 'montre','affiche','combien','quel','quels','liste', ]; foreach($medium_patterns as $p) if(strpos($lower, $p) !== false) return 'medium'; // COMPLEX → Cerebras 235B — multi-step reasoning $complex_patterns = [ 'deploy','déploie','deploie','migre','migration', 'architecture','design','refonte','reconstru', 'analyse','audit','diagnostic','optimise', 'crée','créer','constru','génère','genere', 'compare','benchmark','stratégie','strategie', 'pourquoi','comment faire','explique en détail', 'code','script','fonction','classe','module', ]; foreach($complex_patterns as $p) if(strpos($lower, $p) !== false) return 'complex'; // Default → medium (Ollama general) return 'medium'; } // ═══════════════════════════════════════════════════════ // DIRECT EXECUTION — handles 80% of requests (INSTANT) // No AI needed — pattern → bash command → formatted response // ═══════════════════════════════════════════════════════ function execDirect($msg) { $lower = mb_strtolower(trim($msg)); $cmd = null; $label = null; // ── STATUS & HEALTH ── if(preg_match('/^(status|etat|état|comment.*va|sante|santé|health)/i', $msg)) { $cmd = 'echo "Disk: $(df -h / | tail -1 | awk \'{print $5}\')" && echo "RAM: $(free -h | awk \'/Mem:/{print $3\"/\"$2}\')" && echo "Load: $(cat /proc/loadavg | cut -d" " -f1-3)" && echo "PHP: $(ps aux | grep php | grep -v grep | wc -l) procs" && echo "PG: $(systemctl is-active postgresql 2>/dev/null)" && echo "Apache: $(systemctl is-active apache2 2>/dev/null)" && echo "Uptime: $(uptime -p)"'; $label = "État S95"; } // ── ETHICA / HCP / CONTACTS — only data requests, not complex questions ── elseif(preg_match('/^(ethica|hcp|contact|medecin)$/i', $msg) || preg_match('/combien.*contact|stats.*ethica|données.*ethica|data.*ethica|nombre.*hcp/i', $msg)) { $s204_cmd = 'curl -s --max-time 10 "http://204.168.152.13/api/ethica-api.php?action=dashboard&token=ETHICA_API_2026_SECURE" 2>/dev/null'; $raw = execOnS95($s204_cmd); $data = json_decode($raw, true); if($data && isset($data['contacts_total'])) { $pays = ''; if(is_array($data['contacts_by_pays']??null)) { foreach($data['contacts_by_pays'] as $p) $pays .= " " . ($p[0]??'') . ": " . number_format($p[1]??0) . "\n"; } $resp = "**Ethica B2B — Données live**\n\n"; $resp .= "Total HCPs: **" . number_format($data['contacts_total']) . "**\n"; $resp .= "Actifs: " . number_format($data['contacts_active']??0) . "\n"; $resp .= "Senders: " . ($data['senders']??0) . " | Sources: " . ($data['sources']??0) . "\n\n"; if($pays) $resp .= "**Par pays:**\n$pays\n"; $resp .= "Campagnes: " . ($data['campaigns_total']??0) . " | Envois: " . ($data['sends_total']??0); return ["ok"=>true,"provider"=>"direct","complexity"=>"direct","response"=>$resp,"thinking"=>"Requête API Ethica directe"]; } } // ── collecte de donnees ── elseif(preg_match('/scrap|enrichi/i', $msg)) { $cmd = 'echo "collecteurs actifs: $(ps aux | grep "ethica.*php" | grep -v grep | wc -l)" && echo "Total HCPs: $(PGPASSWORD=W3v4l_2026_S3cur3 psql -h 127.0.0.1 -U admin -d adx_system -t -c "SELECT COUNT(*) FROM ethica.medecins_real" 2>/dev/null | tr -d " ")" && echo "Sources:" && PGPASSWORD=W3v4l_2026_S3cur3 psql -h 127.0.0.1 -U admin -d adx_system -t -c "SELECT source, COUNT(*) c FROM ethica.medecins_real GROUP BY source ORDER BY c DESC LIMIT 8" 2>/dev/null'; $label = "collecteurs Ethica"; } // ── INFRA PATTERNS (auto) ── $infra = matchInfraPattern($msg); if ($infra && isset($infra['special'])) { if ($infra['special']==='auth_test_local') { $results = []; $ch = curl_init('http://127.0.0.1/api/weval-auth-session.php'); curl_setopt_array($ch, [CURLOPT_POST=>true,CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>5,CURLOPT_POSTFIELDS=>'action=login&user=weval&pass=YacineWeval2026',CURLOPT_HEADER=>true,CURLOPT_HTTPHEADER=>['Host: weval-consulting.com']]); $resp = curl_exec($ch); curl_close($ch); preg_match('/PHPSESSID=([^;\s]+)/', $resp, $m); $cookie = $m[1] ?? ''; $results[] = 'Session: ' . ($cookie ? 'OK' : 'FAIL'); $pages = ['/wevia-ia/droid.html','/arsenal-proxy/menu.html','/admin-ia','/wevia-bo','/cyber-monitor','/wevia-fullscreen']; foreach ($pages as $p) { $ch2 = curl_init('http://127.0.0.1' . $p); curl_setopt_array($ch2, [CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>5,CURLOPT_COOKIE=>'PHPSESSID='.$cookie,CURLOPT_HTTPHEADER=>['Host: weval-consulting.com']]); $r = curl_exec($ch2); $size = strlen($r); curl_close($ch2); $results[] = $p . ': ' . ($size > 5000 ? 'OK ' . $size . 'B' : 'FAIL ' . $size . 'B'); } return ['ok'=>true,'provider'=>'auth-test','complexity'=>'direct','response'=>implode(" ",$results)]; } if ($infra['special']==='heal') { require_once '/var/www/weval/wevia-ia/wevia-self-healing.php'; return ['ok'=>true,'provider'=>'self-heal','complexity'=>'direct','response'=>json_encode(weviaSelfHeal(),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)]; } if ($infra['special']==='git') { return ['ok'=>true,'provider'=>'git-auto','complexity'=>'direct','response'=>json_encode(gitAutoPush($msg),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)]; } if ($infra['special']==='alert') { return ['ok'=>true,'provider'=>'telegram','complexity'=>'direct','response'=>json_encode(telegramAlert($msg),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)]; } if ($infra['special']==='email_check') { $pdo=new PDO('pgsql:host=127.0.0.1;dbname=adx_system','admin',weval_secret('WEVAL_PG_ADMIN_PASS')); $c=$pdo->query("SELECT count(*) as t FROM admin.contact_messages")->fetch(PDO::FETCH_ASSOC); $u=$pdo->query("SELECT count(*) as t FROM admin.users")->fetch(PDO::FETCH_ASSOC); return ['ok'=>true,'provider'=>'email-check','complexity'=>'direct','response'=>"Contacts: ".($c['t']??0)." | Users: ".($u['t']??0)." | Routing: ymahboub+yacineutt"]; } } if ($infra && isset($infra['cmd'])) { $cmd = $infra['cmd']; $label = $infra['label']; } // ── GIT / BACKUP ── elseif(preg_match('/git|github|commit/i', $msg) && !preg_match('/push|backup|sauvegarde/i', $msg)) { $cmd = 'cd /opt/wevads-arsenal 2>/dev/null && git log --oneline -5 && echo "---" && git status --short | head -10'; $label = "Git Status"; } elseif(preg_match('/push|backup|sauvegarde/i', $msg)) { $cmd = 'cd /opt/wevads-arsenal 2>/dev/null && git add -A && git commit -m "Auto-backup $(date +%Y%m%d-%H%M)" 2>&1 && git push origin master 2>&1 | tail -5 || echo "Rien à committer"'; $label = "Git Push"; } // ── NONREG / TESTS ── elseif(preg_match('/nonreg|test|regression|lance.*test|teste/i', $msg)) { $cmd = 'bash /tmp/nr4.sh 2>&1 | tail -20'; $label = "NonReg Ethica"; } // ── DISK ── elseif(preg_match('/disk|disque|espace|storage/i', $msg)) { $cmd = 'df -h / && echo "---Top dirs:" && du -sh /opt/* 2>/dev/null | sort -rh | head -8'; $label = "Espace disque S95"; } // ── LOGS ── elseif(preg_match('/log|error|erreur|debug/i', $msg)) { $cmd = 'echo "=== Apache ===" && tail -10 /var/log/apache2/error.log 2>/dev/null | tail -5 && echo "=== PHP ===" && tail -5 /var/log/php*.log 2>/dev/null | tail -3'; $label = "Logs récents"; } // ── CRON ── elseif(preg_match('/cron|tache|tâche|schedule|planif/i', $msg)) { $cmd = 'crontab -l 2>/dev/null | grep -v "^#" | grep -v "^$" | head -15'; $label = "Crons actifs"; } // ── PROCESSES ── elseif(preg_match('/process|processus|qui tourne|running/i', $msg)) { $cmd = 'ps aux --sort=-%mem | head -15'; $label = "Top processus"; } // ── KILL ── elseif(preg_match('/kill|stop|arrêt|arrete|tue\s/i', $msg)) { $m = []; preg_match('/(?:kill|stop|tue)\s+(\S+)/i', $msg, $m); if(!empty($m[1])) { $cmd = 'pkill -f "' . $m[1] . '" 2>&1 && echo "' . $m[1] . ' arrêté" || echo "Pas trouvé"'; } else { return ["ok"=>true,"provider"=>"direct","complexity"=>"direct","response"=>"Dis-moi quoi arrêter : **kill [nom_process]**"]; } $label = "Kill process"; } // ── S204 ── elseif(preg_match('/s204|serveur principal|server principal|nginx/i', $msg)) { $raw = execOnS95('curl -s --max-time 5 http://204.168.152.13/api/wedroid-brain-api.php?k=DROID2026\\&action=status 2>/dev/null'); $data = json_decode($raw, true); $resp = "**S204** — OK\n\nProviders IA:\n"; foreach(($data['providers']??[]) as $n=>$p) $resp .= " $n: {$p['status']} ({$p['role']})\n"; return ["ok"=>true,"provider"=>"direct","complexity"=>"direct","response"=>$resp,"thinking"=>"Status S204 via API interne"]; } // ── S151 ── elseif(preg_match('/s151|tracking/i', $msg)) { $raw = execOnS95('curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://151.80.235.110 2>/dev/null'); return ["ok"=>true,"provider"=>"direct","complexity"=>"direct","response"=>"**S151 Tracking**: HTTP $raw"]; } // ── DIRECT BASH ── elseif(preg_match('/^[\/$]/', $msg)) { $cmd = preg_replace('/^[\/$]\s*/', '', $msg); $label = "Bash"; } elseif(preg_match('/^(ls|df|ps|top|uptime|whoami|date|pwd|free|cat|head|tail|grep|wc|find|du|ss|curl|systemctl|journalctl|PGPASSWORD)/i', $msg)) { $cmd = $msg; $label = "Bash"; } if($cmd) { $output = execOnS95($cmd); $resp = $label ? "**$label:**\n```\n$output\n```" : "```\n$output\n```"; return [ "ok" => true, "provider" => "direct", "complexity" => "direct", "response" => $resp, "thinking" => "Exécution directe (pas d'IA nécessaire)", "commands" => [["cmd" => substr($cmd, 0, 120), "output" => substr($output, 0, 1500), "success" => true]], ]; } return null; } // ═══════════════════════════════════════════════════════ // EXECUTE ON S95 (via SSH from S204) // ═══════════════════════════════════════════════════════ function execOnS95($cmd) { global $SSH_CMD; $escaped = str_replace('"', '\\"', $cmd); $full = "$SSH_CMD \"$escaped\" 2>&1"; $output = shell_exec($full); return trim($output ?? ""); } // ═══════════════════════════════════════════════════════ // CALL OLLAMA (on S95 via SSH) // ═══════════════════════════════════════════════════════ function callOllama($messages, $model = 'tinyllama:latest') { global $SSH_CMD; // Build SHORT prompt for local model (save tokens = faster) $prompt = "'.WEVAL_BRAND_CONTEXT.'Tu es WEDROID, assistant serveur WEVAL. Réponds en français, court et précis.\n\n"; // Only last 2 messages for local (save tokens) $recent = array_slice($messages, -2); foreach($recent as $m) { $role = $m['role'] === 'user' ? 'Q' : 'R'; $prompt .= "$role: " . substr($m['content'], 0, 500) . "\n"; } $prompt .= "R:"; $json_payload = json_encode([ "model" => $model, "prompt" => $prompt, "stream" => false, "options" => ["temperature" => 0.2, "num_predict" => 300, "num_ctx" => 2048] ]); $b64 = base64_encode($json_payload); // Timeout 30s for tinyllama, 60s for bigger models $timeout = ($model === 'tinyllama:latest' || $model === 'phi:latest') ? 20 : 45; $cmd = "echo '$b64' | base64 -d > /tmp/ollama_req.json && curl -s --max-time $timeout http://localhost:11434/api/generate -d @/tmp/ollama_req.json 2>/dev/null"; $raw = execOnS95($cmd); if(!$raw) return null; $data = json_decode($raw, true); return $data['response'] ?? null; } // ═══════════════════════════════════════════════════════ // CALL CEREBRAS/GROQ (cloud) // ═══════════════════════════════════════════════════════ function callCloud($messages, $provider = 'cerebras') { // === SOVEREIGN FIRST: sovereign-api:4000 has ALL 12 provider keys === $sov_ch = curl_init('http://127.0.0.1:4000/v1/chat/completions'); curl_setopt_array($sov_ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode([ 'model' => 'auto', 'messages' => $messages, 'max_tokens' => 1500, 'temperature' => 0.3, ]) ]); $sov_resp = curl_exec($sov_ch); $sov_code = curl_getinfo($sov_ch, CURLINFO_HTTP_CODE); curl_close($sov_ch); if ($sov_code === 200) { $sov_data = json_decode($sov_resp, true); if (isset($sov_data['choices'][0]['message']['content'])) { return $sov_data['choices'][0]['message']['content']; } } // === Fallback: direct provider calls (original) === global $CEREBRAS_KEY, $CEREBRAS_MODEL, $CEREBRAS_URL, $GROQ_KEY, $GROQ_MODEL, $GROQ_URL; global $MISTRAL_KEY, $MISTRAL_MODEL, $MISTRAL_URL, $SAMBANOVA_KEY, $SAMBANOVA_MODEL, $SAMBANOVA_URL; global $DASHSCOPE_KEY, $DASHSCOPE_MODEL, $DASHSCOPE_URL, $OPENROUTER_KEY, $OPENROUTER_MODEL, $OPENROUTER_URL; $providers = [ 'groq' => [$GROQ_URL, $GROQ_KEY, $GROQ_MODEL], 'cerebras' => [$CEREBRAS_URL, $CEREBRAS_KEY, $CEREBRAS_MODEL], 'mistral' => [$MISTRAL_URL, $MISTRAL_KEY, $MISTRAL_MODEL], 'sambanova' => [$SAMBANOVA_URL, $SAMBANOVA_KEY, $SAMBANOVA_MODEL], 'alibaba' => [$DASHSCOPE_URL, $DASHSCOPE_KEY, $DASHSCOPE_MODEL], 'openrouter'=> [$OPENROUTER_URL, $OPENROUTER_KEY, $OPENROUTER_MODEL], ]; if(!isset($providers[$provider])) $provider = 'groq'; [$url, $key, $model] = $providers[$provider]; if(!$key) return null; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 30, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $key", "Content-Type: application/json" ], CURLOPT_POSTFIELDS => json_encode([ "model" => $model, "messages" => $messages, "max_tokens" => 1500, "temperature" => 0.3, ]) ]); $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if($code === 429) return null; // Rate limited → fallback if($code !== 200) return null; $data = json_decode($resp, true); return $data['choices'][0]['message']['content'] ?? null; } // ═══════════════════════════════════════════════════════ // AGENTIC LOOP: Think → Plan → Execute → Verify // ═══════════════════════════════════════════════════════ function agenticProcess($message, $provider_response, $complexity) { $result = [ "thinking" => null, "response" => $provider_response, "commands" => [], "verify" => null, "followup" => null, ]; // Extract bash commands from AI response if(preg_match_all('/```(?:bash|sh)?\s*\n(.*?)\n```/s', $provider_response, $matches)) { foreach($matches[1] as $cmd_block) { $cmds = array_filter(explode("\n", trim($cmd_block))); foreach($cmds as $cmd) { $cmd = trim($cmd); if(empty($cmd) || $cmd[0] === '#') continue; // Safety check if(preg_match('/rm\s+-rf\s+\/[^t]|mkfs|dd\s+if|shutdown|reboot|poweroff/i', $cmd)) { $result["commands"][] = ["cmd" => $cmd, "output" => "BLOQUÉ — commande dangereuse", "success" => false]; continue; } // Execute on S95 $output = execOnS95($cmd); $result["commands"][] = [ "cmd" => $cmd, "output" => substr($output, 0, 1000), "success" => (strlen($output) > 0 || strpos($output, 'error') === false), "description" => "" ]; } } } // Also handle inline commands like: `commande` if(empty($result["commands"]) && preg_match_all('/`([^`]+)`/', $provider_response, $inline_matches)) { foreach($inline_matches[1] as $cmd) { if(preg_match('/^(curl|ls|cat|grep|ps|df|du|wc|head|tail|echo|systemctl|git|php|bash|PGPASSWORD)/', $cmd)) { $output = execOnS95($cmd); $result["commands"][] = ["cmd" => $cmd, "output" => substr($output, 0, 500), "success" => true]; } } } return $result; } // ═══════════════════════════════════════════════════════ // MAIN ROUTER // ═══════════════════════════════════════════════════════ // ═══ EXTENDED ACTIONS (wired by Opus) ═══ if ($action === 'chain') { $r = chainExecute($message); echo json_encode($r); exit; } if ($action === 'git') { echo json_encode(['ok'=>true,'result'=>gitAutoPush($message?:'auto')]); exit; } if ($action === 'alert') { echo json_encode(telegramAlert($message, $_POST['level']??'info')); exit; } if ($action === 'heal') { require_once '/var/www/weval/wevia-ia/wevia-self-healing.php'; echo json_encode(weviaSelfHeal()); exit; } if ($action === 'schedule') { echo json_encode(wedroidRunSchedule()); exit; } if ($action === 'learn') { wedroidLearn($message, $_POST['output']??'', true, $_POST['context']??''); echo json_encode(['ok'=>true]); exit; } if ($action === 'recall') { echo json_encode(['ok'=>true,'knowledge'=>wedroidRecall($message)]); exit; } if ($action === 'providers') { require_once '/var/www/weval/wevia-ia/wevia-provider-autoscale.php'; echo json_encode(weviaCheckProviders()); exit; } if ($action === 'rollback') { require_once '/var/www/weval/wevia-ia/wevia-rollback.php'; echo json_encode(weviaListVersions($_POST['path']??'')); exit; } if ($action === 'email_check') { $pdo=new PDO('pgsql:host=127.0.0.1;dbname=adx_system','admin',weval_secret('WEVAL_PG_ADMIN_PASS')); $c=$pdo->query("SELECT count(*) as t FROM admin.contact_messages")->fetch(PDO::FETCH_ASSOC); $u=$pdo->query("SELECT count(*) as t FROM admin.users")->fetch(PDO::FETCH_ASSOC); echo json_encode(['ok'=>true,'contacts'=>$c['t']??0,'users'=>$u['t']??0,'routing'=>'ymahboub+yacineutt']); exit; } if($action === 'status') { echo json_encode([ "ok" => true, "version" => "5.0", "providers" => [ "ollama" => ["status" => "active", "models" => array_values($OLLAMA_MODELS), "role" => "primary (80%)"], "cerebras" => ["status" => $CEREBRAS_KEY ? "active" : "no_key", "model" => $CEREBRAS_MODEL, "role" => "complex (15%)"], "groq" => ["status" => $GROQ_KEY ? "active" : "no_key", "model" => $GROQ_MODEL, "role" => "fast cloud"], "mistral" => ["status" => $MISTRAL_KEY ? "active" : "no_key", "model" => $MISTRAL_MODEL, "role" => "multilingual"], "sambanova" => ["status" => $SAMBANOVA_KEY ? "active" : "no_key", "model" => $SAMBANOVA_MODEL, "role" => "heavy"], "alibaba" => ["status" => $DASHSCOPE_KEY ? "pending" : "no_key", "model" => $DASHSCOPE_MODEL, "role" => "chinese"], "openrouter" => ["status" => $OPENROUTER_KEY ? "active" : "no_key", "model" => $OPENROUTER_MODEL, "role" => "free fallback"], ], "routing" => "SOVEREIGN: ollama>groq>cerebras>mistral>sambanova>alibaba>openrouter", "session" => $session, ]); exit; } if($action === 'chat' && $message) { $start = microtime(true); $complexity = detectComplexity($message); $provider_used = "unknown"; $response = null; // STEP 1: Try direct execution (no AI) $direct = execDirect($message); if($direct) { $direct["complexity"] = "direct"; $direct["duration_ms"] = round((microtime(true) - $start) * 1000); // Save to session $history[] = ["role" => "user", "content" => $message]; $history[] = ["role" => "assistant", "content" => $direct["response"]]; file_put_contents($session_file, json_encode($history)); echo json_encode($direct); exit; } // STEP 2: Build messages with system prompt + history $messages = [["role" => "system", "content" => $SYSTEM]]; foreach(array_slice($history, -6) as $h) { $messages[] = $h; } $messages[] = ["role" => "user", "content" => $message]; // STEP 3: Route based on complexity // STRATEGY: 90% Direct (instant) → 7% Cerebras (1-3s) → 2% Groq → 1% Ollama (emergency) // LOCAL = Direct bash execution (instant, rich, 90% coverage) // Ollama on CPU = too slow (17-60s) and low quality — emergency only // === SOVEREIGN CASCADE: Force provider > Ollama > Cloud chain === $cascade = ['groq','cerebras','mistral','sambanova','alibaba','openrouter']; // Force provider from frontend if($force_provider && $force_provider !== 'auto') { if($force_provider === 'ollama' || $force_provider === 'ollama_local') { $m = ($complexity === 'complex') ? 'qwen3:8b' : 'qwen3:4b'; $response = callCloud($messages, 'cerebras'); $provider_used = 'cerebras-forced'; } else { $response = callCloud($messages, $force_provider); $provider_used = $force_provider; } } // Auto routing if(!$response) { if($complexity === 'complex') { // Complex: Cerebras 235B first (best reasoning), then cascade $cascade = ['cerebras','groq','mistral','sambanova','alibaba','openrouter']; } elseif($complexity === 'simple') { // Simple: Ollama local first (sovereign), then fast cloud $response = callCloud($messages, 'cerebras'); $provider_used = "cerebras"; } // Medium + fallback: cloud cascade if(!$response) { foreach($cascade as $cp) { $response = callCloud($messages, $cp); if($response) { $provider_used = $cp; break; } } } // Ultimate fallback: Ollama heavy if(!$response) { $response = callCloud($messages, 'groq'); $provider_used = "groq-fallback"; } } if(!$response) { echo json_encode(["ok" => false, "error" => "Tous les providers sont down ou rate-limited"]); exit; } // FLATTEN: if response is nested JSON from Cerebras, extract inner response if (is_string($response) && trim($response) !== "" && trim($response)[0] === "{") { $inner = @json_decode(trim($response), true); if ($inner && isset($inner["response"])) { $response = $inner["response"]; } } // STEP 4: Agentic processing (extract + execute commands) $result = agenticProcess($message, $response, $complexity); // STEP 5: Save to session $history[] = ["role" => "user", "content" => $message]; $history[] = ["role" => "assistant", "content" => $response]; file_put_contents($session_file, json_encode($history)); // STEP 6: Return echo json_encode([ "ok" => true, "provider" => $provider_used, "complexity" => $complexity, "response" => $result["response"], "thinking" => $result["thinking"], "commands" => $result["commands"], "verify" => $result["verify"], "followup" => $result["followup"], "duration_ms" => round((microtime(true) - $start) * 1000), "session" => $session, ]); exit; } // Default echo json_encode(["ok" => true, "version" => "5.0", "actions" => ["chat", "status"]]);