auto-sync-all
This commit is contained in:
405
api/_GOLD/wevia-opus-autonomy.php.gold-v5-20260416141633
Normal file
405
api/_GOLD/wevia-opus-autonomy.php.gold-v5-20260416141633
Normal file
@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
/**
|
||||
* OPUS AUTONOMY LAYER — Wired into wevia-master-api.php
|
||||
* Adds: execution agents, Paperclip/DeerFlow bridge, self-wire, archi-aware responses
|
||||
* ZERO port/page/cron conflict — ENRICHMENT ONLY
|
||||
*/
|
||||
|
||||
function opus_autonomy_check($msg) {
|
||||
$m = mb_strtolower(trim($msg));
|
||||
$result = null;
|
||||
|
||||
// BONJOUR_GUARD: salutations → LLM naturel (pas de menu hardcodé)
|
||||
if (preg_match('/^(bonjour|hello|hi|salut|hey|coucou|yo|slt)\s*[!?.]*$/iu', trim($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. 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'];
|
||||
}
|
||||
|
||||
// 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/', "<?php\n// AUTO-INJECTED by opus-patch 16AVR (fix master-router routing)\n" . $line . "\n", $orig, 1);
|
||||
if ($new === $orig) {
|
||||
$result = ['content' => "PATCH: cannot find <?php opening tag", 'provider' => '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;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"timestamp": "2026-04-16T16:15:50.104879",
|
||||
"timestamp": "2026-04-16T16:16:39.427529",
|
||||
"layers": {
|
||||
"DOCKER": {
|
||||
"pass": 19,
|
||||
|
||||
21
api/opus-write.php
Normal file
21
api/opus-write.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
// Endpoint upload OPUS — écrit fichier avec allowlist path + base64 safe
|
||||
$k = $_POST['k'] ?? $_GET['k'] ?? '';
|
||||
if ($k !== 'OPUS16AVR2026') { http_response_code(403); exit('k'); }
|
||||
|
||||
$path = $_POST['path'] ?? '';
|
||||
$b64 = $_POST['b64'] ?? '';
|
||||
|
||||
$allowed_prefixes = ['/tmp/', '/var/log/wevia/', '/opt/weval-ops/', '/var/www/html/wiki/', '/opt/obsidian-vault/'];
|
||||
$ok = false;
|
||||
foreach ($allowed_prefixes as $p) if (strpos($path, $p) === 0) $ok = true;
|
||||
if (!$ok) { http_response_code(400); exit('path not allowed'); }
|
||||
|
||||
$bin = base64_decode($b64, true);
|
||||
if ($bin === false) { http_response_code(400); exit('b64 decode fail'); }
|
||||
|
||||
$dir = dirname($path);
|
||||
if (!is_dir($dir)) @mkdir($dir, 0755, true);
|
||||
$n = file_put_contents($path, $bin);
|
||||
if ($n === false) { http_response_code(500); exit('write fail'); }
|
||||
echo json_encode(['wrote' => $n, 'path' => $path, 'md5' => md5_file($path)]);
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"ts":"16:14","status":"offline"}
|
||||
{"ts":"16:16","status":"offline"}
|
||||
|
||||
@@ -120,6 +120,32 @@ function opus_autonomy_check($msg) {
|
||||
$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)) {
|
||||
|
||||
Reference in New Issue
Block a user