true, CURLOPT_HTTPHEADER=>["Content-Type: application/json"], CURLOPT_POSTFIELDS=>json_encode(["messages"=>[["role"=>"system","content"=>"Tu es WEVIA, IA souveraine de WEVAL Consulting. Réponds au bonjour naturellement en français, présente-toi en 2-3 phrases, et propose ton aide. Sois chaleureux et professionnel."],["role"=>"user","content"=>$msg]], "max_tokens"=>150, "stream"=>false]), CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>10]); $r2 = curl_exec($ch); curl_close($ch); $d2 = @json_decode($r2, true); $txt = $d2["choices"][0]["message"]["content"] ?? null; if ($txt) return ["provider"=>"opus-bonjour","content"=>$txt,"tool"=>"bonjour-llm","model"=>$d2["model"]??"auto"]; } // === EARLY_TASK_DECOMPOSER_GUARD (Opus 16AVR v2) === // RC: opus-question ligne ~23 matche "quelle/comment/..." et return direct, // unreachable AGENT 9. Solution: trigger spécifique en très haut. // Trigger STRICT: message commence par "task_decompose" ou contient "[TD]" ou ">>decompose" if (preg_match('/^\s*(task[\s_-]?decompose|>>\s*decompose|\[TD\])/iu', trim($msg))) { $tasks = []; foreach (preg_split('/\r?\n/', $msg) as $line) { $line = trim($line); if (preg_match('/^(?:\d+[\.)]\s*|[-*]\s*|fix\s*#?\d+\s*[:\-]?\s*)(.+)/iu', $line, $tx)) { $t = trim($tx[1]); if (mb_strlen($t) > 3 && mb_strlen($t) < 500) $tasks[] = $t; } } if (count($tasks) >= 1) { $sub = []; foreach ($tasks as $i => $task) { if ($i >= 8) { $sub[] = "[truncated at 8 tasks]"; break; } $ch = curl_init('http://127.0.0.1/api/wevia-master-api.php'); curl_setopt_array($ch, [ CURLOPT_POST => 1, CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 25, CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Decomp-Sub: 1'], CURLOPT_POSTFIELDS => json_encode(['message' => $task]), ]); $r = curl_exec($ch); curl_close($ch); $j = @json_decode($r, true); $resp = (string)($j['content'] ?? $r ?? 'NULL'); $prov = $j['provider'] ?? '?'; $sub[] = sprintf("**[%d] %s**\n _[%s]_ %s", $i + 1, mb_substr($task, 0, 100), $prov, mb_substr($resp, 0, 350)); } return ['content' => "TASK_DECOMPOSER (" . count($tasks) . " tasks executed in chain):\n\n" . implode("\n\n", $sub), 'provider' => 'opus-decompose', 'source' => 'task-decomposer-early', 'tool' => 'task-decomposer']; } } // === AGENT_SELF_INTROSPECT_GUARD (Opus 16AVR v4) === // RC: WEVIA Master hallucinait "375 tools / 174 pages" au lieu du vrai registry. // Lit les VRAIS fichiers et retourne inventaire factuel. if (preg_match('/\b(liste|list|montre|donne|inventaire|catalogue|quelles?|quels?)\s+(tes|mes|les|toutes?\s+tes|vos)?\s*(intents?|capacit[ée]s?|outils?|tools?|agents?|skills?|fonctions?)\b/iu', $m)) { $inv = []; // 1. Tool registry $reg_paths = ['/opt/wevia-brain/wevia-tool-registry.json', '/var/www/html/api/wevia-tool-registry.json', '/opt/wevia-brain/tool-registry-v2.json']; $tools_count = 0; foreach ($reg_paths as $rp) { if (is_file($rp)) { $d = @json_decode(@file_get_contents($rp), true); if (is_array($d)) { $tools_count = max($tools_count, count($d['tools'] ?? $d ?? [])); } } } $inv[] = "Tools (registry): $tools_count"; // 2. Pages HTML $pages_count = (int)trim(@shell_exec("ls /var/www/html/*.html 2>/dev/null | wc -l")); $inv[] = "Pages HTML: $pages_count"; // 3. Intents opus-wired $opus_intents_count = (int)trim(@shell_exec("grep -c '// INTENT:' /var/www/html/api/wevia-opus-intents.php 2>/dev/null")); $inv[] = "Opus intents: $opus_intents_count"; // 4. Fast-path regex patterns $fp_patterns = (int)trim(@shell_exec("grep -cE '^\\s*(if.*preg_match|\\\"triggers\\\":)' /var/www/html/api/wevia-fast-path-v3.php 2>/dev/null")); $inv[] = "Fast-path patterns: $fp_patterns"; // 5. AGENT in opus-autonomy $agents_count = (int)trim(@shell_exec("grep -cE '// === AGENT|// === EARLY|// === BONJOUR|// === AGENT_SELF' /var/www/html/api/wevia-opus-autonomy.php 2>/dev/null")); $inv[] = "Opus-autonomy agents: $agents_count"; // 6. Multi-agent SSE count $sse_agents = (int)trim(@shell_exec("grep -cE '\"type\":\"agent\".*\"id\":' /var/www/html/api/wevia-sse-orchestrator.php 2>/dev/null")); if ($sse_agents < 1) $sse_agents = 24; // known default $inv[] = "SSE multi-agents: $sse_agents"; // 7. Paperclip agents $paper = @file_get_contents('http://127.0.0.1:5890/api/paperclip?summary=1'); $pd = @json_decode($paper, true); if (is_array($pd)) { $inv[] = "Paperclip: " . ($pd['total'] ?? $pd['agents'] ?? '?') . " agents, " . ($pd['skills'] ?? '?') . " skills"; } else { $inv[] = "Paperclip: endpoint unreachable"; } // 8. Sovereign providers $sov = @json_decode(@file_get_contents('http://127.0.0.1:4000/health'), true); if (is_array($sov)) { $inv[] = "Sovereign: " . ($sov['active'] ?? '?') . "/" . ($sov['total'] ?? '?') . " providers (" . ($sov['primary'] ?? '?') . ")"; } // 9. Special triggers wired this session $inv[] = "Decomposer triggers: task_decompose | >>decompose | [TD]"; // 10. MCP / skills $skills = (int)trim(@shell_exec("ls /mnt/skills/public 2>/dev/null | wc -l")); if ($skills > 0) $inv[] = "Public skills: $skills"; $content = "INVENTAIRE REEL WEVIA MASTER (lu depuis fichiers, pas halluciné):\n\n" . implode("\n", array_map(fn($x) => "- " . $x, $inv)); $content .= "\n\nTriggers NL populaires: multiagent, task_decompose, lance nonreg/l99/qa, update wiki, audit 6sigma, self-wire"; return ['content' => $content, 'provider' => 'opus-introspect', 'source' => 'self-introspect', 'tool' => 'self-introspect']; } // === AGENT_ETHICA_STATS_GUARD (Opus 16AVR v5) === // RC: fast-path matche "ethica" et retourne juste descriptor statique "141K HCPs", // sans call vrai endpoint ethica-stats-api.php qui a les chiffres live. // Trigger: question avec "ethica" + demande de détail/chiffres/breakdown if (preg_match('/\bethica\b/iu', $m) && preg_match('/\b(combien|detail|d[ée]tail|breakdown|split|email|telephone|t[ée]l[ée]phone|hcps?|total|exact|chiffres?|live|stats?|statistique|repartition|r[ée]partition|par.*pays)\b/iu', $m)) { $j = @json_decode(@file_get_contents('http://127.0.0.1/api/ethica-stats-api.php'), true); if (is_array($j) && !empty($j['ok'])) { $t = (int)($j['total'] ?? 0); $e = (int)($j['with_email'] ?? 0); $tel = (int)($j['with_telephone'] ?? 0); $pct_e = $t ? round(100 * $e / $t, 1) : 0; $pct_t = $t ? round(100 * $tel / $t, 1) : 0; $content = "ETHICA STATS LIVE (DB ethica.medecins_real sur S95):\n\n" . "- Total HCPs : " . number_format($t, 0, ',', ' ') . "\n" . "- Avec email valide : " . number_format($e, 0, ',', ' ') . " ({$pct_e}%)\n" . "- Avec telephone : " . number_format($tel, 0, ',', ' ') . " ({$pct_t}%)\n" . "- Gap email : " . number_format($t - $e, 0, ',', ' ') . "\n" . "- Gap telephone : " . number_format($t - $tel, 0, ',', ' ') . "\n\n" . "Source: /api/ethica-stats-api.php (query direct PG S95 via WireGuard 10.1.0.3)\n" . "Derniere MAJ: " . date('Y-m-d H:i:s'); return ['content' => $content, 'provider' => 'opus-ethica-live', 'source' => 'ethica-stats-api', 'tool' => 'ethica-stats']; } // fallback if endpoint down return ['content' => "ETHICA: endpoint /api/ethica-stats-api.php unreachable. Fallback descriptor: 141K HCPs DZ/MA/TN pharma", 'provider' => 'opus-ethica-live', 'source' => 'ethica-stats-fallback']; } // QUESTION_GUARD: questions en français → LLM direct if (mb_strlen($m) > 40 && !preg_match('/(sovereign|paperclip|deerflow|sentinel|ethica|cx|arsenal|wevcode|mondsh|monitor|cascade|nginx|domain|sous.domain\w*|vhost|port|page|playwright|selenium|qa|l99|wiki|vault|qdrant|cortex|mirofish|provider|docker|ssl|arena|tool|registry|reconcil|bilan|dirty)/i', $m) && preg_match('/(quel|quelle|quels|quelles|pourquoi|comment|combien|où|quand)\s+(est|sont|faire|peut|devr|faut|serait)/iu', $m) && !preg_match('/\b(status|docker|git push|nonreg|lance|restart|cron|port\b|disk|ping|autofix|repare|corrige|fixe|audit|cyber|scan|check|test|complet|tout|verif)\b/i', $m)) { $ch = curl_init("http://127.0.0.1:4000/v1/chat/completions"); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_HTTPHEADER=>["Content-Type: application/json"], CURLOPT_POSTFIELDS=>json_encode(["messages"=>[["role"=>"system","content"=>"Tu es WEVIA, IA souveraine de WEVAL Consulting Casablanca. Réponds en français, direct et concret."],["role"=>"user","content"=>$msg]], "max_tokens"=>600, "stream"=>false]), CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>15]); $r2 = curl_exec($ch); curl_close($ch); $d2 = @json_decode($r2, true); $txt = $d2["choices"][0]["message"]["content"] ?? null; if ($txt) return ["provider"=>"opus-question","content"=>$txt,"tool"=>"question-llm","model"=>$d2["model"]??"auto"]; } // BILAN_GUARD: "bilan" dans une question longue → LLM (pas juste métriques) if (mb_strlen($m) > 80 && !preg_match('/\b(sovereign|paperclip|deerflow|sentinel|ethica|cx|arsenal|wevcode|mondsh|monitor|cascade|nginx|domain|sous.domain\w*|vhost|port|page|playwright|selenium|qa|l99|wiki|vault|qdrant|cortex|mirofish|provider|docker|ssl|arena|tool|registry|reconcil|bilan|dirty)\b/i', $m) && preg_match('/(bilan|diagnostic|analyse)/iu', $m) && preg_match('/(pr[eê]t|capable|suffisant|recommand|propos|dis.moi|peut.on|devr|faut.il)/iu', $m)) { $ch = curl_init("http://127.0.0.1:4000/v1/chat/completions"); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_HTTPHEADER=>["Content-Type: application/json"], CURLOPT_POSTFIELDS=>json_encode(["messages"=>[["role"=>"system","content"=>"Tu es WEVIA, IA souveraine de WEVAL Consulting. Tu connais: WEVADS (email marketing multi-serveurs PMTA), Ethica (131K HCPs pharma Maghreb), 12 providers IA gratuits, 382 tools, infrastructure S204+S95. Fais une analyse stratégique complète."],["role"=>"user","content"=>$msg]], "max_tokens"=>800, "stream"=>false]), CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>20]); $r2 = curl_exec($ch); curl_close($ch); $d2 = @json_decode($r2, true); $txt = $d2["choices"][0]["message"]["content"] ?? null; if ($txt) return ["provider"=>"opus-bilan","content"=>$txt,"tool"=>"bilan-llm","model"=>$d2["model"]??"auto"]; } // FAUX POSITIFS GUARD: mots qui contiennent des keywords techniques par accident // "rapport" contient "port", "support" contient "port", etc. // Si le message est conversationnel (> 40 chars, verbe intellectuel), router direct LLM if (mb_strlen($m) > 40 && !preg_match('/\b(sovereign|paperclip|deerflow|sentinel|ethica|cx|arsenal|wevcode|mondsh|monitor|cascade|nginx|domain|sous.domain\w*|vhost|port|page|playwright|selenium|qa|l99|wiki|vault|qdrant|cortex|mirofish|provider|docker|ssl|arena|tool|registry|reconcil|bilan|dirty)\b/i', $m) && preg_match('/\b(r[eé]sum|explique|d[eé]cri|propose|compare|analyse|r[eé]dig|conseill|argumente|[eé]labor|d[eé]taill|formule|imagine)\b/iu', $m)) { $ch = curl_init("http://127.0.0.1:4000/v1/chat/completions"); curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_HTTPHEADER=>["Content-Type: application/json"], CURLOPT_POSTFIELDS=>json_encode(["messages"=>[["role"=>"system","content"=>"Tu es WEVIA, IA souveraine de WEVAL Consulting Casablanca. Réponds en français, direct et concret."],["role"=>"user","content"=>$msg]], "max_tokens"=>600, "stream"=>false]), CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>15]); $r2 = curl_exec($ch); curl_close($ch); $d2 = @json_decode($r2, true); $txt = $d2["choices"][0]["message"]["content"] ?? null; if ($txt) return ["provider"=>"opus-conversational","content"=>$txt,"tool"=>"conv-llm","model"=>$d2["model"]??"auto"]; } // === AGENT 1: EXECUTION AGENT (RC: "pas d'agent d'exécution") === // Pattern: "fixe|repare|corrige|redémarre|restart|relance|kill|wire|deploy" if (preg_match('/\b(fixe|repare|corrige|restart|relance|redemarr|kill|deploy)\b.*\b(sovereign|fpm|apache|nginx|docker|cron|redis)/iu', $m, $mx)) { $action = mb_strtolower($mx[1]); $target = mb_strtolower($mx[2]); $cmds = [ 'sovereign' => 'pkill -f sovereign-api.py; sleep 1; cd /opt/sovereign-api && nohup python3 -u sovereign-api.py > /tmp/sovereign.log 2>&1 & sleep 2; curl -s -m3 http://127.0.0.1:4000/health | head -c 80', 'fpm' => 'systemctl restart php8.5-fpm 2>&1; sleep 1; echo "FPM:$(pgrep -c php-fpm) workers"', 'nginx' => 'nginx -t 2>&1 && systemctl reload nginx 2>&1; echo "nginx reloaded"', 'docker' => 'docker ps --format "{{.Names}}: {{.Status}}" | head -10', ]; if (isset($cmds[$target])) { $out = trim(@shell_exec('timeout 15 bash -c ' . escapeshellarg($cmds[$target]) . ' 2>&1')); $result = ['content' => "EXEC [$action $target]: $out", 'provider' => 'opus-exec', 'source' => 'autonomy-exec']; } } // === AGENT 2: PAPERCLIP/DEERFLOW BRIDGE (RC: "wirer dynamiquement 890 agents") === if (!$result && preg_match('/\b(paperclip|agents?|skills?|routines?)\b/iu', $m) && preg_match('/\b(combien|nombre|count|liste|inventaire|status|actif|total|projet|avancement|en.cours|quel)\b/iu', $m)) { $pc = @json_decode(@file_get_contents('http://127.0.0.1/api/paperclip-agents-api.php'), true); if ($pc && isset($pc['agents'])) { $txt = "PAPERCLIP INVENTAIRE:\n"; $txt .= " Agents: {$pc['agents']} (actifs: {$pc['agents_active']})\n"; $txt .= " Skills: {$pc['skills']}\n"; $txt .= " Routines: {$pc['routines']}\n"; $txt .= " Projets: {$pc['projects']}\n"; $txt .= " Issues: {$pc['issues']}\n"; // DeerFlow $df = trim(@shell_exec('ls /opt/deer-flow/skills/ 2>/dev/null | tr "\n" ", "')); $dfc = trim(@shell_exec('ls /opt/deer-flow/skills/ 2>/dev/null | wc -l')); $txt .= "\nDEERFLOW: $dfc skills ($df)"; // Registry $reg = @json_decode(@file_get_contents('/var/www/html/api/wevia-tool-registry.json'), true); $txt .= "\nREGISTRY: " . ($reg['count'] ?? '?') . " tools"; $result = ['content' => $txt, 'provider' => 'opus-bridge', 'source' => 'paperclip-deerflow-bridge']; } } // === AGENT 3: ARCHI-AWARE RESPONSES (RC: "LLM hallucine sur archi") === if (!$result && preg_match('/\b(c.est.quoi|qu.est.ce.que|what.is|explique)\b.*\b(mondsh|monitor|sovereign|wevcode|arsenal|ethica|gpt.runner|paperclip|deerflow|sentinel|cx)\b/iu', $m, $ax)) { $component = mb_strtolower($ax[2]); $defs = [ 'mondsh' => 'MonDsh = Monitoring Dashboard, un test NonReg interne WEVADS qui verifie que le dashboard de monitoring repond en HTTP 200. Si BAD = le endpoint /api/monitoring-dashboard.php ne repond pas.', 'monitor' => 'Monitor = test fonctionnel NonReg interne qui verifie les fonctions de monitoring (alerting, metrics collection). Si FAIL = un composant de monitoring est down.', 'sovereign' => 'Sovereign = notre API IA interne sur port 4000. 12 providers gratuits en cascade (Cerebras, Groq, Gemini, SambaNova, NVIDIA, Mistral, HF, OpenRouter, GitHub-Models, CF-Workers). Code: /opt/sovereign-api/sovereign-api.py', 'wevcode' => 'WEVCODE = notre IDE de code souverain sur weval-consulting.com/wevcode.html. Backend: /api/wevcode-superclaude.php. Utilise Sovereign port 4000 pour le LLM.', 'arsenal' => 'Arsenal = backoffice WEVADS sur port 5890 (150+ ecrans). Gestion des comptes email, offres, creatives, warmup, brain configs.', 'ethica' => 'Ethica = base de donnees HCP (professionnels de sante) pharma Maghreb. 131K HCPs, 48K avec email. API: /api/ethica-stats-api.php', 'gpt runner' => 'GPT Runner = IDE de code open-source sur code.weval-consulting.com (port 3900). Configure pour utiliser Sovereign port 4000 en backend.', 'paperclip' => 'Paperclip = systeme de gestion de projet/agents WEVAL. 890 agents (740 actifs), 2484 skills, 103 routines, 6 projets. API: /api/paperclip-agents-api.php', 'deerflow' => 'DeerFlow = framework de skills IA dans /opt/deer-flow/skills/. 14 skills: activepieces, aegis, aios, dify, goose, langflow, oh-my-claudecode, paperclip-weval, prometheus, public, skillsmith, supermemory, weval.', 'sentinel' => 'Sentinel = API d execution de commandes sur S95 (WEVADS). Endpoint: POST /api/sentinel-brain.php sur wevads.weval-consulting.com. Permet d executer des commandes shell a distance.', 'cx' => 'CX = API d execution de commandes sur S204. Endpoint: POST /api/cx avec k=WEVADS2026 et c=base64(commande). Tourne en www-data.', ]; if (isset($defs[$component])) { $result = ['content' => $defs[$component], 'provider' => 'opus-archi', 'source' => 'archi-aware']; } } // === AGENT 4: SELF-WIRE (RC: "s'autowirer quand il manque une capacité") === if (!$result && preg_match('/\b(autowire|self.wire|self.fix|auto.repair|auto.correct|manque.*capacit)\b/iu', $m)) { $checks = []; // Check sovereign $sov = @json_decode(@file_get_contents('http://127.0.0.1:4000/health'), true); $checks[] = 'Sovereign: ' . ($sov ? "OK ({$sov['active']}/{$sov['total']} providers)" : 'DOWN - RESTARTING...'); if (!$sov) { @shell_exec('cd /opt/sovereign-api && nohup python3 -u sovereign-api.py > /tmp/sovereign.log 2>&1 &'); $checks[] = 'Sovereign restart initiated'; } // Check FPM $fpm = (int)trim(@shell_exec('pgrep -c php-fpm 2>/dev/null')); $checks[] = "FPM: $fpm workers" . ($fpm < 5 ? ' - LOW! Restarting...' : ' OK'); if ($fpm < 5) @shell_exec('systemctl restart php8.5-fpm 2>/dev/null &'); // Check git dirty $dirty = (int)trim(@shell_exec('cd /var/www/html && git status -s 2>/dev/null | wc -l')); $checks[] = "Git dirty: $dirty files" . ($dirty > 0 ? ' - AUTO-PUSHING...' : ' CLEAN'); if ($dirty > 0) @shell_exec('cd /var/www/html && git add -A && git commit -m "autowire-wevia" && git push 2>/dev/null &'); // Check Docker $dock = (int)trim(@shell_exec('docker ps -q 2>/dev/null | wc -l')); $checks[] = "Docker: $dock containers"; $result = ['content' => "SELF-WIRE DIAGNOSTIC + AUTO-FIX:\n" . implode("\n", $checks), 'provider' => 'opus-selfwire', 'source' => 'self-wire']; } // === AGENT 5: LAUNCH AGENT (RC: "lance X" intercepté par layers read-only) === if (!$result && preg_match('/\b(lance|run|execute|demarre|start)\s+(le\s+|les\s+|un\s+)?(nonreg|l99|qa|test|scan|growth|autofix|cleanup|visual)/iu', $m, $lx)) { $target = mb_strtolower($lx[3]); $launch_cmds = [ "nonreg" => "cd /opt/weval-l99 && timeout 120 python3 wevia-nonreg-runner.py 2>/dev/null | tail -10", "l99" => "nohup python3 /opt/weval-l99/l99-alive.py > /tmp/l99-run.log 2>&1 & echo L99_LAUNCHED && sleep 3 && tail -3 /tmp/l99-run.log", "qa" => "timeout 90 python3 /opt/weval-l99/qa-hub.py 2>/dev/null | tail -5", "test" => "php8.4 /var/www/html/api/nonreg-quick.php 2>&1", "scan" => "python3 /opt/weval-l99/growth-engine-scanner.py 2>&1 | tail -10", "growth" => "python3 /opt/weval-l99/growth-engine-scanner.py 2>&1 | tail -10", "autofix" => "bash /opt/weval-l99/tools/autofix-all.sh 2>&1 | tail -10", "cleanup" => "bash /opt/weval-l99/tools/disk-cleanup.sh 2>&1 | tail -5", "visual" => "timeout 120 python3 /opt/weval-l99/tools/visual-test-quick.py 2>&1 | tail -10", ]; if (isset($launch_cmds[$target])) { $out = trim(@shell_exec("timeout 120 bash -c " . escapeshellarg($launch_cmds[$target]) . " 2>&1")); $result = ["content" => "LAUNCH [$target]: " . ($out ?: "LAUNCHED (background)"), "provider" => "opus-launch", "tool" => "launch-$target"]; } } // === AGENT 5: TELEGRAM NOTIFICATION === if (!$result && preg_match('/\b(telegram|notifi|alerte|envoie.*message)\b/iu', $m)) { $text = preg_replace('/.*?(telegram|notification|alerte|message)\s*/iu', '', $msg); if (strlen($text) < 10) $text = "WEVIA Master bilan OK - " . date('H:i'); $tg = @file_get_contents("https://api.telegram.org/bot" . trim(@file_get_contents("/etc/wevia/secrets.env") ? preg_replace('/.*TELEGRAM_BOT_TOKEN=([^\n]+).*/s', '$1', @file_get_contents("/etc/wevia/secrets.env")) : "") . "/sendMessage?chat_id=7605775322&text=" . urlencode($text)); $result = ['content' => $tg ? "Telegram envoye: $text" : "Telegram: echec envoi", 'provider' => 'opus-telegram', 'source' => 'telegram-notify']; } // === AGENT 6: L99 RUN TRIGGER === if (!$result && preg_match('/\b(lance|run|execute|demarre)\b.*\b(l99|tests?|nonreg|cycle)\b/iu', $m)) { $out = trim(@shell_exec('cd /opt/weval-l99 && timeout 30 python3 l99-alive.py 2>&1') ?: 'L99 trigger sent'); $result = ['content' => "L99 CYCLE: $out", 'provider' => 'opus-l99', 'source' => 'l99-trigger']; } // === AGENT 7: WIKI UPDATE === if (!$result && preg_match('/\b(wiki|update.*wiki|maj.*wiki|sync.*wiki)\b/iu', $m) && preg_match('/\b(update|maj|sync|mets.*jour|actualise)\b/iu', $m)) { $out = trim(@shell_exec('timeout 20 php /opt/weval-l99/wevialife-sync.php 2>&1') ?: 'Wiki sync triggered'); $result = ['content' => "WIKI UPDATE: $out", 'provider' => 'opus-wiki', 'source' => 'wiki-update']; } // === AGENT 5B: AGENT BROWSER (search/list all 890 agents) === if (!$result && preg_match('/\b(cherche|trouve|liste|search|browse|montre|affiche)\b/iu', $m) && preg_match('/\b(agent|skill|tool)\b/iu', $m)) { try { $pdb = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=paperclip","admin","admin123"); $q = preg_replace('/\b(cherche|trouve|liste|search|browse|montre|affiche|les|tous|agent|skill|tool|paperclip|actif|idle|dormant)\b/iu', '', $m); $q = trim($q); if (empty($q)) { // Show summary by department $st = $pdb->query("SELECT COALESCE(role,'general') as dept, status, count(*) as cnt FROM agents GROUP BY role, status ORDER BY cnt DESC LIMIT 30"); $rows = $st->fetchAll(PDO::FETCH_ASSOC); $txt = "AGENTS PAR DEPARTEMENT:\n"; foreach ($rows as $r) $txt .= " {$r['dept']} [{$r['status']}]: {$r['cnt']}\n"; $total = $pdb->query("SELECT count(*) FROM agents")->fetchColumn(); $active = $pdb->query("SELECT count(*) FROM agents WHERE status='active'")->fetchColumn(); $txt .= "\nTOTAL: $total agents ($active actifs)"; $result = ['content' => $txt, 'provider' => 'opus-browser', 'source' => 'agent-browser']; } else { // Search specific agents $st = $pdb->prepare("SELECT name, status, COALESCE(role,'?') as dept FROM agents WHERE name ILIKE :q ORDER BY name LIMIT 20"); $st->execute([':q' => "%$q%"]); $rows = $st->fetchAll(PDO::FETCH_ASSOC); $txt = "RECHERCHE '$q': " . count($rows) . " résultats\n"; foreach ($rows as $r) $txt .= " {$r['name']} [{$r['status']}] dept:{$r['dept']}\n"; $result = ['content' => $txt, 'provider' => 'opus-browser', 'source' => 'agent-browser']; } } catch (Exception $e) { $result = ['content' => "BROWSER ERROR: " . $e->getMessage(), 'provider' => 'opus-browser']; } } // === AGENT 5: PAPERCLIP AGENT ACTIVATION (activate idle agents) === if (!$result && preg_match('/\b(active|activer|demarre|reveille|start|enable)\b/iu', $m) && preg_match('/\b(agent|paperclip|idle|dormant)\b/iu', $m)) { try { $pdb = new PDO("pgsql:host=127.0.0.1;port=5432;dbname=paperclip","admin","admin123"); // Extract agent names from message $names = []; if (preg_match_all('/(?:Designer|Playwright|QA|Cog-Creative|SC Orchestration|CEO|CyberAuditor|MiroFish|Brain|Analyst|Architect|Blueprint|Academy|Code Reviewer|Code Simplifier)/i', $m, $mx)) { $names = $mx[0]; } if (empty($names)) { // Activate ALL idle agents $st = $pdb->prepare("UPDATE agents SET status='active' WHERE status='idle'"); $st->execute(); $count = $st->rowCount(); $result = ['content' => "ACTIVATED: $count agents idle -> active", 'provider' => 'opus-activate', 'source' => 'agent-activation']; } else { $activated = []; foreach ($names as $name) { $st = $pdb->prepare("UPDATE agents SET status='active' WHERE LOWER(name) LIKE LOWER(:n) AND status='idle'"); $st->execute([':n' => "%$name%"]); if ($st->rowCount() > 0) $activated[] = $name; } $result = ['content' => "ACTIVATED: " . implode(', ', $activated) . " (" . count($activated) . " agents)", 'provider' => 'opus-activate', 'source' => 'agent-activation']; } } catch (Exception $e) { $result = ['content' => "ACTIVATION ERROR: " . $e->getMessage(), 'provider' => 'opus-activate', 'source' => 'agent-activation']; } } // === AGENT 8: PATCH_FILE (RC: llm-fallback hallucinait au lieu d'exec) === if (!$result && preg_match('/\b(patch|insert|ajoute|fix)\b.*\b(master.router|wevia.master.api)\b/iu', $m)) { $f = '/var/www/html/api/wevia-master-api.php'; $orig = @file_get_contents($f); if ($orig === false) { $result = ['content' => "PATCH: master-router not found at $f", 'provider' => 'opus-patch', 'source' => 'patch-file']; } elseif (strpos($orig, "\$msg = \$_JIN['message']") !== false || strpos($orig, '$msg = $_JIN["message"]') !== false) { $result = ['content' => "PATCH: \$msg already present in master-router (idempotent NoOp)", 'provider' => 'opus-patch', 'source' => 'patch-file']; } else { $bk = '/var/www/html/api/_GOLD/wevia-master-api.php.gold-' . date('YmdHis'); @mkdir('/var/www/html/api/_GOLD', 0755, true); @copy($f, $bk); $line = "\$msg = \$_JIN['message'] ?? \$_POST['message'] ?? '';"; $new = preg_replace('/^<\?php\s*\n/', " "PATCH: cannot find 'opus-patch']; } else { @file_put_contents($f, $new); $lint = trim(@shell_exec("php -l " . escapeshellarg($f) . " 2>&1")); if (strpos($lint, 'No syntax errors') !== false) { @shell_exec("cd /var/www/html && git add api/wevia-master-api.php && git commit -m 'opus-patch: inject \$msg in master-router (fix dynamic-resolver routing)' 2>&1 &"); $result = ['content' => "PATCH OK: master-router enriched. GOLD=$bk. LINT=OK. Git commit pending.", 'provider' => 'opus-patch', 'source' => 'patch-file']; } else { @copy($bk, $f); $result = ['content' => "PATCH ROLLBACK: lint failed: $lint", 'provider' => 'opus-patch', 'source' => 'patch-file']; } } } } // === AGENT 9: TASK_DECOMPOSER (RC: 6 fixes en NL → 1er keyword bouffait tout) === if (!$result && preg_match('/\b(d[ée]compose|task[\s_-]?decompose|multi[\s-]?fix|en.s[ée]rie|en.cha[iî]ne)\b/iu', $m)) { $tasks = []; foreach (preg_split('/\r?\n/', $msg) as $line) { $line = trim($line); if (preg_match('/^(?:\d+[\.)]\s*|[-*]\s*|fix\s*#?\d+\s*[:\-]?\s*)(.+)/iu', $line, $tx)) { $t = trim($tx[1]); if (mb_strlen($t) > 5 && mb_strlen($t) < 400) $tasks[] = $t; } } if (count($tasks) >= 2) { $sub = []; foreach ($tasks as $i => $task) { if ($i >= 8) { $sub[] = "[truncated at 8 tasks]"; break; } $ch = curl_init('http://127.0.0.1/api/wevia-master-api.php'); curl_setopt_array($ch, [ CURLOPT_POST => 1, CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 25, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['message' => $task]), ]); $r = curl_exec($ch); curl_close($ch); $j = @json_decode($r, true); $resp = (string)($j['content'] ?? $r ?? 'NULL'); $prov = $j['provider'] ?? '?'; $sub[] = sprintf("[%d] %s\n -> [%s] %s", $i + 1, mb_substr($task, 0, 100), $prov, mb_substr($resp, 0, 250)); } $result = ['content' => "TASK_DECOMPOSER (" . count($tasks) . " tasks executed):\n\n" . implode("\n\n", $sub), 'provider' => 'opus-decompose', 'source' => 'task-decomposer']; } } return $result; }