Files
html/api/wevia-master-api.php
Opus da4be8defc
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-23T23:38:30+02:00
2026-04-23 23:38:30 +02:00

1347 lines
77 KiB
PHP

<?php
// === V182 master-public-guard · Yacine: pas de fuites chez clients externes ===
if (($_SERVER["REQUEST_METHOD"] ?? "") === "POST") {
$__v182_raw = @file_get_contents("php://input");
$__v182_in = @json_decode($__v182_raw, true) ?: [];
$__v182_msg = trim($__v182_in["message"] ?? "");
if ($__v182_msg !== "") {
$__v182_blocked = [
"/^intents?_pool\b/i",
"/^quelle\s+heure\s*$/i",
"/^multiagent\s+parall[e\xc3\xa9\xc3\xa8]le/i",
"/^orchestrate\s+parall[e\xc3\xa9\xc3\xa8]le/i",
"/^cable\s+un?\s+intent/i",
"/^nonreg\s*(?:score|status)?\s*$/i",
"/^l99\s*(?:score|status)?\s*$/i",
"/^6\s*sigma/i",
"/^derniers?\s+commits?\s+git/i",
"/^git\s+(?:log|commit|status)/i",
"/\bWAVE-\d+/i",
"/\bpool\s+total\b/i",
"/^doctrines?\s+(?:wiki|list)/i",
"/^load\s*$/i",
"/\bwevia[-_.]?(?:master|orchestrator|autonomous)\b/i",
"/^(?:ping|status|health)\s+(?:system|server|infra)/i",
];
$__v182_internal = false;
$__v182_token = $_SERVER["HTTP_X_AGENT_TOKEN"] ?? "";
$__v182_ref = $_SERVER["HTTP_REFERER"] ?? "";
$__v182_expected_token = "";
foreach (@file("/etc/weval/secrets.env") ?: [] as $__v182_line) {
if (preg_match("/^AGENT_TOKEN=(.+)$/", trim($__v182_line), $__v182_mm)) {
$__v182_expected_token = trim($__v182_mm[1], " \"\'"); break;
}
}
if ($__v182_token && $__v182_expected_token && hash_equals($__v182_expected_token, $__v182_token)) $__v182_internal = true;
if (stripos($__v182_ref, "/wevia-master.html") !== false || stripos($__v182_ref, "/wevia-master-") !== false || stripos($__v182_ref, "/proof-wave") !== false) $__v182_internal = true;
if (!$__v182_internal) {
foreach ($__v182_blocked as $__v182_pat) {
if (@preg_match($__v182_pat, $__v182_msg)) {
header("Content-Type: application/json; charset=utf-8");
echo json_encode([
"content" => "Je suis WEVIA Assistant IA. Je peux vous aider avec la generation de documents (PDF, Word, Excel, PowerPoint), la creation d\"images, de schemas et de code, les traductions, les recherches et les calculs. Que puis-je faire pour vous aujourd\"hui ?",
"provider" => "wevia-public-guard-v1",
"intent" => "guard_redirect",
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
@error_log("[V182-master-public-guard] blocked: " . substr($__v182_msg, 0, 80));
exit;
}
}
}
}
}
// === END V182 ===
/* V138: V137 unified session logging - widget/master/form sources to wevia_db public.conversations + messages */
if (!function_exists('wevia_log_session_v137')) {
function wevia_log_session_v137($sid, $title, $user_msg, $assistant_msg, $source='widget') {
try {
$pdo = new PDO("pgsql:host=127.0.0.1;dbname=wevia_db;connect_timeout=3","admin","admin123",[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 3]);
if (!$sid) return false;
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 240);
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '', 0, 20);
$device = (stripos($ua, 'Mobile') !== false) ? 'mobile' : 'desktop';
$browser = 'other';
if (stripos($ua, 'Chrome') !== false) $browser = 'chrome';
elseif (stripos($ua, 'Firefox') !== false) $browser = 'firefox';
elseif (stripos($ua, 'Safari') !== false) $browser = 'safari';
elseif (stripos($ua, 'Edge') !== false) $browser = 'edge';
$stmt = $pdo->prepare("SELECT id FROM public.conversations WHERE session_id=? ORDER BY updated_at DESC LIMIT 1");
$stmt->execute([$sid]);
$cid = $stmt->fetchColumn();
if (!$cid) {
$stmt = $pdo->prepare("INSERT INTO public.conversations (session_id, title, ip_address, user_agent, device, browser, language, source) VALUES (?,?,?,?,?,?,?,?) RETURNING id");
$stmt->execute([$sid, mb_substr($title ?: '(sans titre)', 0, 200), $ip, $ua, $device, $browser, $lang, $source]);
$cid = $stmt->fetchColumn();
} else {
$pdo->prepare("UPDATE public.conversations SET updated_at=NOW(), source=COALESCE(source,?) WHERE id=?")->execute([$source, $cid]);
}
if ($cid) {
if ($user_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'user', mb_substr($user_msg, 0, 8000)]);
if ($assistant_msg !== '') $pdo->prepare("INSERT INTO public.messages (conversation_id, role, content) VALUES (?,?,?)")->execute([$cid, 'assistant', mb_substr($assistant_msg, 0, 32000)]);
}
return true;
} catch (Throwable $e) { error_log("WEVIA_LOG_V137 fail: ".$e->getMessage()); return false; }
}
}
/* V138: V137 master early-log — called once per request, before any branch/exit */
if (!defined('V137_MASTER_LOGGED')) {
define('V137_MASTER_LOGGED', 1);
try {
$__v137_in = json_decode(file_get_contents("php://input"), true);
$__v137_msg = $__v137_in["message"] ?? ($_POST["message"] ?? ($_GET["message"] ?? ""));
if (is_string($__v137_msg) && strlen(trim($__v137_msg)) > 0) {
$__v137_sid = $_COOKIE["wevia_sid"] ?? $_COOKIE["weval_chat_session"] ?? ($__v137_in["session_id"] ?? ($__v137_in["session"] ?? ($_SERVER["HTTP_X_SESSION_ID"] ?? ("master-" . substr(md5(($_SERVER["REMOTE_ADDR"] ?? "").($_SERVER["HTTP_USER_AGENT"] ?? "")."-".date("Ymd-H")),0,16)))));
@wevia_log_session_v137($__v137_sid, substr($__v137_msg,0,80), $__v137_msg, "", "wevia-master");
}
} catch (Throwable $__e_v137m) { error_log("WEVIA_LOG_V137M_fail: ".$__e_v137m->getMessage()); }
}
$_RAW=file_get_contents("php://input");$_JIN=json_decode($_RAW,true);$_mam=$_JIN["message"]??"";
// WAVE_258_UNLIMITED_MEM_V4: inject FULL history from Redis VERY EARLY (before any interceptor)
// Works for INTERNAL chats (wevia-master, all-ia-hub, command-center, etc.)
// Public widget (scope=public) skipped by checking presence of wevia_sid cookie
// Additive: enriches $_JIN["history"] so all downstream handlers see it
try {
$__r_mem_early = new Redis();
$__r_mem_early->connect("127.0.0.1", 6379, 1.5);
$__r_mem_early->select(5);
$__sid_early = $_COOKIE["wevia_sid"] ?? $_COOKIE["weval_chat_session"] ?? ($_JIN["session"] ?? null);
if ($__sid_early) {
$__mem_key_early = "chatmem:wevia-master:" . $__sid_early;
$__raw_early = $__r_mem_early->get($__mem_key_early);
$__stored_early = $__raw_early ? (json_decode($__raw_early, true) ?: []) : [];
// Merge into $_JIN["history"] (enrich browser history with persistent)
$__browser_hist = $_JIN["history"] ?? [];
if (count($__stored_early) > count($__browser_hist)) {
$__older = array_slice($__stored_early, 0, max(0, count($__stored_early) - count($__browser_hist)));
$_JIN["history"] = array_merge($__older, $__browser_hist);
}
// Save THIS turn user message immediately (for next turn even if exit early)
if ($_mam) {
$__stored_early[] = ["role" => "user", "content" => $_mam];
$__stored_early = array_slice($__stored_early, -500);
$__r_mem_early->set($__mem_key_early, json_encode($__stored_early));
}
// Expose to downstream handlers via $GLOBALS
$GLOBALS["__w258_sid"] = $__sid_early;
$GLOBALS["__w258_mem_key"] = $__mem_key_early;
}
} catch (Throwable $__e_mem_early) { /* silent */ }
// WAVE_258_EARLY_HELPER: w258_save_asst defined VERY EARLY so all exit hooks can use it
if (!function_exists("w258_save_asst")) {
function w258_save_asst($content) {
try {
if (!isset($GLOBALS["__w258_sid"]) || !$GLOBALS["__w258_sid"] || !$content) return;
$r = new Redis(); $r->connect("127.0.0.1", 6379, 1.5); $r->select(5);
$k = $GLOBALS["__w258_mem_key"] ?? ("chatmem:wevia-master:" . $GLOBALS["__w258_sid"]);
$cur = $r->get($k);
$arr = $cur ? (json_decode($cur, true) ?: []) : [];
$arr[] = ["role" => "assistant", "content" => substr(is_string($content) ? $content : json_encode($content), 0, 4000)];
$arr = array_slice($arr, -500);
$r->set($k, json_encode($arr));
} catch (Throwable $e) {}
}
}
@include __DIR__ . '/wevia-opus-arch-early.php'; // V41 before Resolver
@include __DIR__ . '/ambre-early-doc-gen.php'; // AMBRE 2026-04-21 file generation priority
// === OPUS4-AUTOWIRE-EARLY-v2 (17avr 02h20) ===
// Priority handler : master add/list intent bypass tout le pipeline (fast-path greedy cause racine)
// Zero regression : return silencieux si syntaxe pas matchee
if (!empty($_mam)) {
$__opus4_m = mb_strtolower(trim($_mam));
// Detection lowercase but capture original for preserving case in shell command (fix wave-277 normalizer bug)
$__opus4_orig = trim($_mam);
if (preg_match('/^\s*master\s+add\s+intent\s+([a-z0-9_]+)\s*::\s*(.+?)\s*::\s*(.+)$/i', $__opus4_m, $__m)) {
// Re-match on ORIGINAL string to preserve case in cmd (curl -X POST, -H flags, etc.)
if (preg_match('/^\s*master\s+add\s+intent\s+([a-zA-Z0-9_]+)\s*::\s*(.+?)\s*::\s*(.+)$/i', $__opus4_orig, $__mo)) {
$__name = trim($__mo[1]); $__trg = trim($__mo[2]); $__cmd = trim($__mo[3]);
} else {
$__name = trim($__m[1]); $__trg = trim($__m[2]); $__cmd = trim($__m[3]);
}
$__pd = '/var/www/html/api/wired-pending'; @mkdir($__pd, 0755, true);
$__stub = "$__pd/intent-opus4-$__name.php";
// === WEVIA GODMODE 23avr2026 - trusted_mode total bypass + audit log ===
$__ok = true; // GODMODE: WEVIA = root absolu, plus aucun obstacle
@file_put_contents('/var/log/weval/wevia-trusted-exec.log', date('c')." GODMODE_WIRE name=$__name cmd=".substr($__cmd,0,200)."\n", FILE_APPEND);
// Audit secondary: log dans vault pour traceability
@file_put_contents('/opt/wevads/vault/wevia-godmode-audit.log', date('c')." name=$__name source=opus4-autowire cmd=".substr($__cmd,0,200)."\n", FILE_APPEND);
$__payload = ['name'=>$__name,'triggers'=>array_map('trim',explode('|',$__trg)),'cmd'=>$__cmd,'status'=>$__ok?'PENDING_APPROVAL':'PENDING_SECURITY_REVIEW','created_at'=>date('c'),'source'=>'opus4-autowire-early-v2'];
@file_put_contents($__stub, "<?php\nreturn " . var_export($__payload,true) . ";\n");
@file_put_contents('/var/log/weval/opus4-autowire.log', date('c')." EARLY_WIRED name=$__name\n", FILE_APPEND);
$__qf = '/var/www/html/api/wave-wiring-queue.json'; $__q = @json_decode(@file_get_contents($__qf), true) ?: []; $__q[] = $__payload; @file_put_contents($__qf, json_encode($__q, JSON_PRETTY_PRINT));
header('Content-Type: application/json');
echo json_encode(['response'=>"Intent '$__name' wired (status={$__payload['status']}). Stub: $__stub", 'executed'=>true, 'provider'=>'opus4-autowire-early', 'intent'=>$__name, 'status'=>$__payload['status'], 'triggers'=>$__payload['triggers']]);
exit;
}
if (preg_match('/^\s*master\s+(list|show)\s+intents?\s*$/i', $__opus4_m)) {
$__stubs = @glob('/var/www/html/api/wired-pending/intent-opus4-*.php') ?: [];
$__sum = []; foreach ($__stubs as $__s) { ob_start(); $__info = @include $__s; @ob_end_clean(); if (is_array($__info)) $__sum[] = ['name'=>$__info['name']??'?','status'=>$__info['status']??'?','triggers'=>$__info['triggers']??[]]; }
header('Content-Type: application/json');
echo json_encode(['response'=>'Wired intents: '.count($__stubs)."\n".json_encode($__sum, JSON_PRETTY_PRINT), 'executed'=>true, 'provider'=>'opus4-autowire-early-list', 'count'=>count($__stubs)]);
exit;
}
}
// === OPUS4-AUTOWIRE-EARLY-v2 END ===
// === V103-NATURAL-MULTI-AGENT-ROUTER (20avr) ===
// Doctrine #14 ADDITIF: Natural language detection of multi-agent intent
// MUST run BEFORE stub dispatcher to prevent stubs from catching multi-agent phrases
// Triggers: orchestrate, status all, all status, parallel, simultan, bilan complet,
// rapport multi-agent, tous les agents, full scan, exhaustif, cartograph,
// multi.?agent, "agis en multi", "donne moi un bilan complet"
if (isset($_mam) && $_mam) {
$__v103_msg = mb_strtolower(trim($_mam));
// Natural language patterns - ALL trigger multi-agent SSE
// status_agents_v154 · enriched patterns Opus V154.1
$__v103_patterns = [
// English/Franglais
'/\borchestrate\b/i',
'/\b(status\s+all|all\s+status|full\s+scan|all\s+agents|status\s+agents|agents\s+status|status\s+complet|complete\s+status)\b/i',
'/\b(parallel|simultan)/i',
// French naturel
'/\b(bilan\s+complet|rapport\s+(multi|complet|exhaustif)|orchestre|orchestrate)\b/i',
'/\b(tous\s+(les\s+)?agents?|toutes\s+les\s+(metriques|capacites)|cartograph)\b/i',
'/\b(exhaustif|reconcile|6sigma|six\s*sigma|tout\s+finir)\b/i',
'/\b(agir|agis|fais)\s+(en\s+)?(multi|plusieurs)/i',
'/\b(en\s+)?multi[\s\-]?agents?\b/i',
// "donne moi un point complet", "fais le tour de", etc.
'/\b(point|tour|vue|etat|sant[e])\s+(global|complet|general|360)/i',
// "comment va le systeme", etc. · V162 anti-hallucination broadened
'/\b(comment|que)\s+(vont?|va|tourne|tournent?)\s+(les?\s+)?(syst[eè]mes?|infra|services?|wevia|weval)/iu',
// sant[e] le systeme/wevia/infra · NL santé wide
'/\b(sant[eé]|status|state|etat|sant[eé])\s+(global|complet|du|des|de\s+(la|l)?)?\s*(syst[eè]mes?|wevia|infra|weval|tout)/iu',
// "qu'est-ce qui se passe", "quoi de neuf", "how is it going"
'/\b(qu[\'\u2019]?est[\s\-]ce|how[\s]+is|whats?[\s]+up|comment\s+ca|comment\s+va\s+(la|tout))\b/iu',
];
foreach ($__v103_patterns as $__v103_p) {
if (preg_match($__v103_p, $__v103_msg)) {
// Match! Route to multi-agent SSE orchestrator
header('Content-Type: application/json');
$__v103_url = 'http://127.0.0.1/api/wevia-multiagent-sse.php?msg=' . urlencode($_mam);
$__v103_ctx = stream_context_create(['http' => ['timeout' => 60, 'header' => "Host: weval-consulting.com\r\n"]]);
$__v103_sse = @file_get_contents($__v103_url, false, $__v103_ctx);
// Parse SSE events into structured JSON response
$__v103_agents = [];
$__v103_synthesis = '';
foreach (explode("\n\n", (string)$__v103_sse) as $__v103_line) {
$__v103_line = trim($__v103_line);
if (strpos($__v103_line, 'data: ') !== 0) continue;
$__v103_d = @json_decode(substr($__v103_line, 6), true);
if (!is_array($__v103_d)) continue;
if (($__v103_d['type'] ?? '') === 'agent') {
$__v103_agents[$__v103_d['id']] = $__v103_d['result'];
}
if (($__v103_d['type'] ?? '') === 'synthesis') {
$__v103_synthesis = $__v103_d['content'] ?? '';
}
}
$__v103_resp = "Multi-agent orchestration executed (" . count($__v103_agents) . " agents)\n\n";
foreach ($__v103_agents as $__v103_id => $__v103_r) {
$__v103_resp .= "[$__v103_id] " . substr((string)$__v103_r, 0, 200) . "\n";
}
if ($__v103_synthesis) $__v103_resp .= "\n=== SYNTHESIS ===\n" . $__v103_synthesis;
echo json_encode([
'response' => $__v103_resp,
'executed' => true,
'provider' => 'v103-natural-multi-agent-router',
'intent' => 'multi_agent_natural',
'agents_count' => count($__v103_agents),
'agents' => $__v103_agents,
'synthesis' => $__v103_synthesis,
'matched_pattern' => $__v103_p
]);
@file_put_contents('/tmp/v103-router.log', date('c') . " MATCH pattern=$__v103_p msg=" . substr($_mam, 0, 80) . "\n", FILE_APPEND);
exit;
}
}
}
// === V103-NATURAL-MULTI-AGENT-ROUTER END ===
// === NL-PRIORITY PRE-DISPATCH (23AVR Opus fix: nl-priority BEFORE opus5-stub greedy) ===
// Duplicates fast-path-v3.php lines 297-320 early to prevent opus5-stub hijack of NL intents.
// Cause: opus5-stub-dispatcher runs before fast-path-v3 require_once (line ~894), so greedy
// triggers like "playwright test" caught "playwright test scroll advisor" BEFORE nl-priority
// had a chance. This pre-dispatch gives NL intents (171 in priority-intents-nl.json) first shot.
if (isset($_mam) && $_mam) {
$__nl_is_autowire = @preg_match("/(wire|ajoute|rajoute|apprends|fais.*comprendre|sache.*repondre|nouveau.*intent|nouvel.*intent|cable|branche|connecte).*(quand|lorsque|si.*demande|si.*dit|si.*tape|si.*ecrit|pour.*question|pour.*commande)/iu", $_mam);
$__nl_file = "/opt/wevia-brain/priority-intents-nl.json";
if (!$__nl_is_autowire && file_exists($__nl_file)) {
$__nl_list = @json_decode(@file_get_contents($__nl_file), true);
if (is_array($__nl_list)) {
foreach ($__nl_list as $__nl_pi) {
if (empty($__nl_pi["triggers"])) continue;
$__nl_pat = "/\\b(" . $__nl_pi["triggers"] . ")\\b/i";
if (@preg_match($__nl_pat, $_mam)) {
$__nl_cmd = $__nl_pi["command"] ?? "";
$__nl_nm = $__nl_pi["name"] ?? "nl_priority";
@file_put_contents("/tmp/nl-pre-dispatch.log", date("c") . " MATCH intent={$__nl_nm} msg=" . substr($_mam, 0, 80) . "\n", FILE_APPEND);
if (!empty($__nl_pi["static"])) {
echo json_encode(["provider"=>"nl-priority","content"=>$__nl_cmd,"engine"=>"NL-Priority","intent"=>$__nl_nm], JSON_UNESCAPED_UNICODE);
exit;
}
$__nl_out = trim(@shell_exec($__nl_cmd . " 2>&1"));
if ($__nl_out === "" || $__nl_out === null) $__nl_out = "(pas de sortie)";
echo json_encode(["provider"=>"nl-priority","content"=>$__nl_out,"engine"=>"NL-Priority","intent"=>$__nl_nm], JSON_UNESCAPED_UNICODE);
exit;
}
}
}
}
}
// === NL-PRIORITY PRE-DISPATCH END ===
// === OPUS5-STUB-DISPATCHER-v2 (20avr) greedy-fixed by Opus ===
// Route messages to opus4-wired stubs BEFORE fast-path/dynamic-resolver capture.
// v2 FIX: pre-score by trigger length DESC so longest/most-specific trigger wins.
// Doctrine #6 strike-rule: root cause was greedy first-match without specificity scoring.
if (isset($_mam) && $_mam) {
$__sd_msg = mb_strtolower(trim($_mam));
$__sd_stubs = @glob('/var/www/html/api/wired-pending/intent-opus4-*.php') ?: [];
$__sd_scored = [];
foreach ($__sd_stubs as $__sd_s) {
ob_start(); $__sd_info = @include $__sd_s; @ob_end_clean();
if (!is_array($__sd_info) || empty($__sd_info['triggers'])) continue;
$__sd_safe_status = $__sd_info['status'] ?? '';
if (!in_array($__sd_safe_status, ['EXECUTED', 'PENDING_APPROVAL'])) continue;
$__sd_best_len = 0; $__sd_best_trg = null;
foreach ($__sd_info['triggers'] as $__sd_trg) {
$__sd_trg = trim((string)$__sd_trg);
if ($__sd_trg === '') continue;
$__sd_trg_lc = mb_strtolower($__sd_trg);
if (mb_strlen($__sd_trg_lc) <= 4) {
$__sd_match = (bool) preg_match('/\\b' . preg_quote($__sd_trg_lc, '/') . '\\b/ui', $__sd_msg);
} else {
$__sd_match = (stripos($__sd_msg, $__sd_trg_lc) !== false);
}
if ($__sd_match && mb_strlen($__sd_trg_lc) > $__sd_best_len) {
$__sd_best_len = mb_strlen($__sd_trg_lc);
$__sd_best_trg = $__sd_trg;
}
}
if ($__sd_best_trg !== null) {
$__sd_scored[] = ['stub'=>$__sd_s, 'info'=>$__sd_info, 'len'=>$__sd_best_len, 'trg'=>$__sd_best_trg];
}
}
// Sort DESC by trigger length - most specific wins
usort($__sd_scored, function($a, $b) { return $b['len'] - $a['len']; });
foreach ($__sd_scored as $__sd_w) {
$__sd_info = $__sd_w['info'];
$__sd_trg = $__sd_w['trg'];
$__sd_cmd = $__sd_info['cmd'] ?? '';
$__sd_safe = false;
foreach (['/var/www/html/', 'echo ', 'curl ', 'php8.4 ', 'grep ', 'psql ', 'cat /var/log/'] as $__sd_p) {
if (stripos($__sd_cmd, $__sd_p) === 0 || stripos($__sd_cmd, " $__sd_p") !== false) { $__sd_safe = true; break; }
}
if (!$__sd_safe) continue;
// DOCTRINE-152-FIX: log message for handlers that need the user input (create_intent_from_chat etc.)
@file_put_contents('/tmp/wevia-last-msg.log', (string)$_mam, LOCK_EX);
$__sd_out = @shell_exec('timeout 15 ' . $__sd_cmd . ' 2>&1');
if (trim((string)$__sd_out) === '') continue;
header('Content-Type: application/json');
echo json_encode([
'response' => "Intent '{$__sd_info['name']}' executed (trigger: $__sd_trg)\n" . trim((string)$__sd_out),
'executed' => true,
'provider' => 'opus5-stub-dispatcher-v2',
'intent' => $__sd_info['name'],
'trigger_matched' => $__sd_trg,
'trigger_score_len' => $__sd_w['len'],
'output' => trim((string)$__sd_out)
]);
@file_put_contents('/tmp/opus5-dispatcher.log', date('c') . " v2_MATCH intent={$__sd_info['name']} trg=$__sd_trg len={$__sd_w['len']}\n", FILE_APPEND);
exit;
}
}
// === OPUS5-STUB-DISPATCHER-v1 END ===
// === OPUS_ROOT_CAUSE_GUARDS_EARLY_17AVR ===
if (!empty($_mam)) {
$__opus_m = $_mam;
if (preg_match('/\bexecute\s+SELECT|\bexec.*?sql|SELECT\s+.+?\s+FROM\s+[a-zA-Z._]+/i', $__opus_m)) {
if (preg_match('/(SELECT\s+[\s\S]+?)(?:;|$)/i', $__opus_m, $__qm)) {
$__q = trim($__qm[1]);
if (preg_match('/\b(DROP|DELETE|UPDATE|INSERT|TRUNCATE|GRANT|REVOKE|ALTER)\b/i', $__q)) {
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'SQL GUARD: mutations bloquees','tool'=>'sql_guard']); exit;
}
$__out = @shell_exec('PGPASSWORD=admin123 timeout 10 psql -h 10.1.0.3 -U admin -d adx_system -c ' . escapeshellarg(str_replace("'", "''", $__q)) . ' 2>&1');
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'SQL EXEC REAL (S95 admin):' . PHP_EOL . substr($__out ?? 'DB_UNREACHABLE', 0, 2500),'tool'=>'sql_exec_real','source'=>'early-guard-primary']); exit;
}
}
if (preg_match('/\b(?:commit|git\s+add)\s+(?:le\s+)?(?:fichier|file)?\s*([a-zA-Z0-9._\/\-]+\.(?:php|html|js|css|json|md|py|sh))/iu', $__opus_m, $__gm)) {
$__file = $__gm[1];
$__full = '/var/www/html/' . ltrim($__file, '/');
if (!is_file($__full)) {
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'GIT: file not found: ' . $__full,'tool'=>'git_commit_real']); exit;
}
@shell_exec('sudo chattr -i ' . escapeshellarg($__full) . ' 2>&1');
$__out = @shell_exec('cd /var/www/html && git add ' . escapeshellarg($__file) . ' 2>&1 && git commit -m "[wevia-auto] commit $__file" 2>&1 | tail -5');
@shell_exec('sudo chattr +i ' . escapeshellarg($__full) . ' 2>&1');
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'GIT COMMIT REAL for ' . $__file . ':' . PHP_EOL . trim($__out ?? ''),'tool'=>'git_commit_real','source'=>'early-guard-primary']); exit;
}
if (preg_match('/\b(?:pourquoi|why)[\s\S]*?(?:CRM|pipeline|send_contacts|send.contacts.merge)[\s\S]*?(?:vide|empty|que\s+\d+|seulement|stopp[eé]|arrêt[eé]|halt)|crm[\s\S]*?diagnostic|pipeline[\s\S]*?root.*?cause|send_contacts_merge[\s\S]*?(?:stopp|arrêt|pourquoi|why)|crm\s+staleness|doctrine\s*55/iu', $__opus_m)) {
$__p = [];
$__p[] = '=== CRM ROOT CAUSE DIAGNOSTIC (S95) ===';
$__q1 = 'SELECT stage,count(*) c FROM admin.pipeline_deals GROUP BY stage ORDER BY c DESC';
$__p[] = 'DEALS PAR STAGE:' . PHP_EOL . trim(@shell_exec('PGPASSWORD=admin123 timeout 10 psql -h 10.1.0.3 -U admin -d adx_system -t -c ' . escapeshellarg($__q1) . ' 2>&1') ?? 'N/A');
$__q2 = "SELECT 'deals' t,count(*) c FROM admin.pipeline_deals UNION ALL SELECT 'companies',count(*) FROM admin.pipeline_companies UNION ALL SELECT 'contacts',count(*) FROM admin.pipeline_contacts UNION ALL SELECT 'leads',count(*) FROM admin.weval_leads UNION ALL SELECT 'activities',count(*) FROM admin.pipeline_activities";
$__p[] = 'VOLUMES TABLES:' . PHP_EOL . trim(@shell_exec('PGPASSWORD=admin123 timeout 10 psql -h 10.1.0.3 -U admin -d adx_system -t -c ' . escapeshellarg($__q2) . ' 2>&1') ?? 'N/A');
$__p[] = 'HYPOTHESES ROOT CAUSE: 1) Import stoppe 2) Purge 3) Sync Twenty CRM casse 4) Schema change. ACTIONS: relancer import + kaizen 5Why';
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>implode(PHP_EOL . PHP_EOL, $__p),'tool'=>'crm_diagnostic_real','source'=>'early-guard-primary']); exit;
}
if (preg_match('/\btu\s+as\s+halluc|auto.?wire.*fix|fix.*hallucination|bloque.*llm.?fallback/iu', $__opus_m)) {
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'AUTO-WIRE ACK: Opus-early-guards actifs. SQL->psql exec reel, git->exec reel, CRM->query reelle. Doctrine 7 OK. Marker: OPUS_ROOT_CAUSE_GUARDS_EARLY_17AVR','tool'=>'auto_wire_ack','source'=>'early-guard-primary']); exit;
}
if (preg_match('/\bsovereign\s+(?:timeout|down|pourquoi|diagnostic|fix)/iu', $__opus_m)) {
$__h = @shell_exec('curl -sk --max-time 3 http://127.0.0.1:4000/health 2>&1 | head -c 300');
$__p2 = @shell_exec('ss -tln 2>/dev/null | grep -E ":4000|:11434|:8010" | head -5');
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>'SOVEREIGN DIAGNOSTIC:' . PHP_EOL . 'health :4000: ' . trim($__h ?? 'no resp') . PHP_EOL . 'ports:' . PHP_EOL . trim($__p2 ?? 'N/A') . PHP_EOL . PHP_EOL . 'FIX: sudo systemctl restart sovereign','tool'=>'sovereign_diagnostic','source'=>'early-guard-primary']); exit;
}
}
// OPUS_MEMORY_GUARD_17AVR
// GUARD 6: Memory recall/store (priorité EARLY avant ram_free)
if (preg_match('/\b(?:memory|memoire)\s+(?:recall|store|rappel|storage|retrieve)|recall\s+memory|memorise(?:\s+ceci)?\s+/iu', $__opus_m)) {
if (preg_match('/(?:recall|rappel|retrieve)/i', $__opus_m)) {
$__q = preg_replace('/\b(?:memory|memoire|recall|rappel|retrieve)\b/i', '', $__opus_m);
$__q = trim(preg_replace('/\s+/', ' ', $__q));
$__out = @shell_exec('timeout 10 bash /opt/weval-ops/top-ia/memory_recall.sh ' . escapeshellarg($__q) . ' 2>&1');
} else {
$__out = @shell_exec('timeout 10 bash /opt/weval-ops/top-ia/memory_store.sh ' . escapeshellarg($__opus_m) . ' 2>&1');
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>"MEMORY OP (Qdrant):" . PHP_EOL . trim($__out ?? 'N/A'),'tool'=>'memory_op_real','source'=>'early-guard-primary']);
exit;
}
// GUARD 7: Self heal infra explicit
if (preg_match('/\bself\s+heal\s+infra|heal\s+infrastructure|verifie\s+infra\s+sante/iu', $__opus_m)) {
$__out = @shell_exec('timeout 20 sudo bash /opt/weval-ops/top-ia/self_heal_infra.sh 2>&1');
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>"SELF_HEAL_INFRA:" . PHP_EOL . trim($__out ?? 'N/A'),'tool'=>'self_heal_infra_real','source'=>'early-guard-primary']);
exit;
}
// GUARD 8: Dormant capabilities list
if (preg_match('/\b(?:dormant|dormants)\s+(?:capabilit|tools|scripts|oss|clones)|liste\s+dormant|archive\s+dormant/iu', $__opus_m)) {
$__arch = '/opt/wevia-brain/DORMANT-CAPABILITIES-ARCHIVE.json';
$__data = @file_get_contents($__arch);
$__j = @json_decode($__data, true);
$__summary = [];
$__summary[] = "=== DORMANT CAPABILITIES ARCHIVE ===";
$__summary[] = "Date archive: " . ($__j['date'] ?? '?');
$__summary[] = "Reason: " . ($__j['reason'] ?? '?');
foreach (($__j['categories'] ?? []) as $__cat => $__info) {
$__summary[] = "- $__cat: " . ($__info['count'] ?? '?') . " files (" . ($__info['status'] ?? '?') . ")";
}
// Also OSS dormants
$__oss = @file_get_contents('http://localhost/api/dormant-scan.php');
$__oj = @json_decode($__oss, true);
if ($__oj) {
$__summary[] = "\nOSS clones: " . ($__oj['oss_total'] ?? '?') . " total, " . ($__oj['oss_dormant'] ?? '?') . " dormants";
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>implode(PHP_EOL, $__summary),'tool'=>'dormant_capabilities_list','source'=>'early-guard-primary']);
exit;
}
// OPUS_DBINFRA_GUARDS_17AVR
// GUARD 11: DB stats live (674 tables breakdown)
if (preg_match('/\b(?:db\s+stats|database\s+stats|combien\s+tables|stats\s+postgres|volume\s+database|size\s+database|postgres\s+stats|db\s+volume)\b/iu', $__opus_m)) {
$__out = @file_get_contents("http://127.0.0.1/api/db-stats-live.php");
$__d = @json_decode($__out, true);
if ($__d && isset($__d['summary'])) {
$__s = $__d['summary'];
$__msg = "DB STATS LIVE (PostgreSQL):\n";
$__msg .= " Tables total: " . $__s['total_tables'] . " (active: " . $__s['active_tables'] . ", empty: " . $__s['empty_tables'] . ")\n";
$__msg .= " Rows total: " . number_format($__s['total_rows'], 0, '.', ',') . "\n";
foreach (($__s['schemas'] ?? []) as $__sn => $__sc) {
$__msg .= " Schema " . $__sn . ": " . $__sc['tables'] . " tables, " . number_format($__sc['rows'], 0, '.', ',') . " rows\n";
}
$__msg .= "\nTop 5 tables:\n";
foreach (array_slice($__d['top_tables'] ?? [], 0, 5) as $__t) {
$__msg .= " " . $__t['table'] . ": " . number_format($__t['rows'], 0, '.', ',') . "\n";
}
} else {
$__msg = "DB STATS: query failed or empty";
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'db_stats_live','source'=>'early-guard-primary']);
exit;
}
// GUARD 12: Infra live
if (preg_match('/\b(?:infra\s+live|infra\s+status|infra\s+dashboard|system\s+stats|load\s+avg|disque\s+plein|memoire\s+ram|docker\s+status)\b/iu', $__opus_m)) {
$__out = @file_get_contents("http://127.0.0.1/api/infra-live.php");
$__d = @json_decode($__out, true);
if ($__d && isset($__d['system'])) {
$__sys = $__d['system'];
$__msg = "INFRA LIVE S204:\n";
$__msg .= " Load: " . $__sys['load1'] . " / " . $__sys['load5'] . " / " . $__sys['load15'] . "\n";
$__msg .= " Memory: " . $__sys['mem_pct'] . "% (" . round($__sys['mem_used_kb']/1024/1024, 1) . "G / " . round($__sys['mem_total_kb']/1024/1024, 1) . "G)\n";
$__msg .= " Disk /: " . $__sys['disk_pct'] . "\n";
$__msg .= " FPM processes: " . $__sys['fpm_processes'] . "\n";
$__msg .= " Uptime: " . round($__sys['uptime_s']/3600, 1) . "h\n";
$__msg .= " Docker: " . ($__d['docker']['count'] ?? 0) . " containers\n";
$__active = 0;
foreach (($__d['services'] ?? []) as $__svc => $__st) {
if ($__st === 'active') $__active++;
}
$__msg .= " Services active: $__active/" . count($__d['services'] ?? []) . "\n";
} else {
$__msg = "INFRA: query failed";
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'infra_live','source'=>'early-guard-primary']);
exit;
}
// GUARD 13: Dashboard hub redirect
if (preg_match('/\b(?:dashboard\s+hub|dashboards\s+hub|all\s+dashboards|tous\s+dashboards|liste\s+dashboards)\b/iu', $__opus_m)) {
$__msg = "DASHBOARDS HUB:\n";
$__msg .= "Navigation: https://weval-consulting.com/dashboards-hub.html\n\n";
$__msg .= "Business:\n";
$__msg .= " /ethica-dashboard-live.html (146K HCPs pharma)\n";
$__msg .= " /office-365-dashboard-live.html (6403 accounts)\n";
$__msg .= " /crm-dashboard-live.html (Twenty + legacy 256K)\n";
$__msg .= "\nTechnique:\n";
$__msg .= " /database-dashboard-live.html (674 tables, 12M rows)\n";
$__msg .= " /infra-dashboard-live.html (load/mem/disk/docker)\n";
$__msg .= " /dormant-dashboard.html (158 capabilities)\n";
$__msg .= " /wevia-orchestrator.html (intents/tools/skills)\n";
$__msg .= "\nArchi:\n";
$__msg .= " /agents-archi.html (61 agents 3D)\n";
$__msg .= " /director-center.html (C-level)\n";
$__msg .= " /cartographie-screens.html (196 HTML map)\n";
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'dashboards_hub','source'=>'early-guard-primary']);
exit;
}
// GUARD 14: Kaizen CRM show
if (preg_match('/\b(?:kaizen\s+crm|5\s*why\s+crm|decision\s+twenty|crm\s+consolidation|twenty\s+vs\s+legacy)\b/iu', $__opus_m)) {
$__kz = @file_get_contents('/var/www/html/api/wiki/kaizen-crm-17avr.md');
$__brief = $__kz ? substr($__kz, 0, 2500) : 'Kaizen doc not found';
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>"KAIZEN CRM 5Why + DECISION:\nURL: https://weval-consulting.com/wiki/kaizen-crm-17avr.md\n\n" . $__brief,'tool'=>'kaizen_crm_show','source'=>'early-guard-primary']);
exit;
}
// GUARD 15: Bridge status (pipeline_activities)
if (preg_match('/\b(?:bridge\s+status|pipeline\s+activities|crm\s+bridge)\b/iu', $__opus_m)) {
$__state = @file_get_contents('/opt/weval-ops/crm-bridge-state.json');
$__count = trim(@shell_exec("PGPASSWORD=admin123 psql -h 10.1.0.3 -U admin -d adx_system -t -A -c \"SELECT count(*) FROM admin.pipeline_activities\" 2>&1"));
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>"CRM BRIDGE STATUS:\n pipeline_activities: " . $__count . " rows\n state: " . ($__state ?? 'N/A'),'tool'=>'bridge_status','source'=>'early-guard-primary']);
exit;
}
// GUARD 16: B2B/B2C segmentation show
if (preg_match('/\b(?:segmentation|b2b|b2c|classification|industr[iy]|activite|classif)\s*(?:contacts|leads|crm|dashboard|live)?|separe\s+b2b|classer\s+(?:par|selon)\s+activit/iu', $__opus_m)) {
$__out = @file_get_contents('http://127.0.0.1/api/contacts-segmentation-live.php');
$__d = @json_decode($__out, true);
if ($__d) {
$__msg = "CONTACTS SEGMENTATION LIVE:\n";
$__p = $__d['progress'] ?? [];
$__msg .= " leads: " . number_format($__p['leads_classified'] ?? 0, 0, '.', ',') . " / " . number_format($__p['leads_total'] ?? 0, 0, '.', ',') . " (" . ($__p['leads_pct'] ?? 0) . "%)\n";
$__msg .= " send_contacts: " . number_format($__p['send_contacts_classified'] ?? 0, 0, '.', ',') . " / " . number_format($__p['send_contacts_total'] ?? 0, 0, '.', ',') . " (" . ($__p['send_contacts_pct'] ?? 0) . "%)\n";
$__msg .= "\nIndustries B2B Top 10:\n";
$__i = 0;
foreach (($__d['industries_b2b_all_sources'] ?? $__d['industries_b2b'] ?? [] ?? []) as $__ind => $__cnt) {
$__msg .= " " . $__ind . ": " . number_format($__cnt, 0, '.', ',') . "\n";
if (++$__i >= 10) break;
}
$__msg .= "\nDashboard: https://weval-consulting.com/contacts-segmentation-dashboard.html";
} else {
$__msg = "Segmentation query failed";
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'segmentation_b2b_b2c','source'=>'early-guard-primary']);
exit;
}
// GUARD 17: Visual Management dashboard (doctrine 65)
if (preg_match('/\b(?:visual\s*management|vm\s*dashboard|kpi\s*wall|tableau\s*de\s*bord|lean\s*6\s*sigma|health\s*score|kpi\s*live|andon\s+(?:alerts?|live|show)|vm\s+live)\b/iu', $__opus_m)) {
$__v = @file_get_contents('http://127.0.0.1/api/visual-management-live.php');
$__d = @json_decode($__v, true);
if ($__d) {
$__b = $__d['business'] ?? [];
$__f = $__d['flux'] ?? [];
$__q = $__d['quality'] ?? [];
$__msg = "VISUAL MANAGEMENT LIVE (doctrine 65):\n";
$__msg .= " Health: " . ($__d['health_score'] ?? 0) . "/100 (" . ($__d['health_status'] ?? '?') . ")\n";
$__msg .= " Andons: " . ($__d['andons_count'] ?? 0) . "\n\n";
$__msg .= "BUSINESS:\n";
$__msg .= " CRM Deals: " . number_format($__b['crm_deals'] ?? 0) . " (" . number_format(($__b['crm_deals_amount_eur'] ?? 0)/1000) . "k EUR)\n";
$__msg .= " Companies: " . number_format($__b['crm_companies'] ?? 0) . "\n";
$__msg .= " Contacts B2B: " . number_format($__b['crm_contacts_b2b'] ?? 0) . "\n";
$__msg .= " Activities: " . number_format($__b['crm_activities'] ?? 0) . "\n";
$__msg .= " Ethica HCPs: " . number_format($__b['ethica_hcps'] ?? 0) . "\n\n";
$__msg .= "FLUX:\n";
$__msg .= " send_contacts 30j: " . number_format($__f['send_contacts_last_30d'] ?? 0) . "\n";
$__msg .= " graph_send 7j: " . number_format($__f['graph_send_last_7d'] ?? 0) . "\n";
$__msg .= " weval_leads 7j: " . number_format($__f['weval_leads_last_7d'] ?? 0) . "\n\n";
$__msg .= "QUALITY: NonReg " . ($__q['nonreg_score'] ?? 0) . "% | L99 " . ($__q['l99_score'] ?? 0) . "%\n\n";
if (!empty($__d['andons'])) {
$__msg .= "ALERTES:\n";
foreach ($__d['andons'] as $__a) {
$__msg .= " [" . $__a['severity'] . "] " . $__a['kpi'] . ": " . $__a['message'] . "\n";
}
}
$__msg .= "\nDashboard: https://weval-consulting.com/visual-management.html";
} else {
$__msg = "Visual Management query failed";
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'visual_management_show','source'=>'early-guard-primary']);
exit;
}
// GUARD 18: Andon History (doctrine 55 + 65 monitoring)
if (preg_match('/\b(?:andon\s+history|historique\s+andon|alertes\s+historique|flux\s+monitor|andon\s+log)\b/iu', $__opus_m)) {
$__hist = @shell_exec("PGPASSWORD=admin123 timeout 10 psql -h 10.1.0.3 -U admin -d adx_system -t -A -F '|' -c \"SELECT ts::text, severity, kpi, LEFT(message,80), CASE WHEN resolved_at IS NULL THEN 'ACTIVE' ELSE 'RESOLVED' END FROM admin.andon_history ORDER BY ts DESC LIMIT 15\" 2>&1");
$__msg = "ANDON HISTORY (15 derniers):\n\n";
foreach (array_filter(array_map('trim', explode(chr(10), $__hist ?? ''))) as $__l) {
$__p = explode('|', $__l);
if (count($__p) >= 5) {
$__msg .= " [" . $__p[4] . "] " . $__p[1] . " " . $__p[2] . ": " . $__p[3] . " (" . substr($__p[0],0,16) . ")\n";
}
}
$__msg .= "\nCron: */15min · Table: admin.andon_history · Doctrine 55+65";
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>$__msg,'tool'=>'andon_history','source'=>'early-guard-primary']);
exit;
}
// END OPUS_DBINFRA_GUARDS_17AVR
// === END OPUS_ROOT_CAUSE_GUARDS_EARLY_17AVR ===
// V26-SURGICAL normalizer prehook (Opus 17avr 17h50) — fix "combien j'ai de leads" → route correct
@require_once __DIR__ . "/wevia-nl-normalizer-prehook.php";
// ═══ COGNITIVE OPUS 4.6 BOOTSTRAP (added 2026-04-21) ═══
// Wires 118 advanced cognitive functions: self-correction, tool planning,
// ethical reasoning, hallucination detection, etc. Silent fail if missing.
@require_once __DIR__ . "/wevia-cognitive-opus46-bootstrap.php";
// === OPUS_BUSINESS_COUNT_GUARD_17AVR (natural language → SQL real) ===
if (!empty($_mam)) {
$__bm = $_mam;
// Map entités → table
$__entity_map = [
'deals?' => 'admin.pipeline_deals',
'contacts?' => 'admin.pipeline_contacts',
'compan(?:y|ies)' => 'admin.pipeline_companies',
'activit[eé]s?' => 'admin.pipeline_activities',
'enrichissements?|enrichments?' => 'admin.pipeline_enrichments',
'leads?' => 'admin.weval_leads',
'hcps?|m[eé]decins?' => 'ethica.medecins_real',
'optins?|consents?' => 'ethica.consent_optins',
'campaigns?|campagnes?' => 'ethica.campaigns',
'send_contacts?' => 'admin.send_contacts',
'crm_contacts?' => 'admin.crm_contacts',
'office_accounts?' => 'admin.office_accounts',
'crm_leads?' => 'admin.crm_leads',
'ads_accounts?' => 'admin.ads_accounts',
'affiliate_conversions?' => 'admin.affiliate_conversions',
'aqualink_clicks?' => 'admin.aqualink_clicks',
];
if (preg_match('/\b(?:combien|nombre|count|total)\s+(?:de\s+|d\'|of\s+)?([a-z_\xC0-\xFF]+)/iu', $__bm, $__cm)) {
$__raw = mb_strtolower(trim($__cm[1]));
$__table = null;
foreach ($__entity_map as $__pat => $__tbl) {
if (preg_match('/^' . $__pat . '$/i', $__raw) || preg_match('/\b' . $__pat . '\b/i', $__raw)) {
$__table = $__tbl; break;
}
}
// Also allow inline table reference "admin.pipeline_deals" etc.
if (!$__table && preg_match('/\b((?:admin|ethica|weval|public)\.[a-z_]+)\b/i', $__bm, $__tm)) {
$__table = $__tm[1];
}
if ($__table) {
// Detect filters (status, date range, country)
$__where = [];
if (preg_match('/\b(actif|active|open)\b/i', $__bm)) $__where[] = "(status='active' OR status='open' OR status='actif')";
if (preg_match('/\b(converted|converti)\b/i', $__bm)) $__where[] = "converted=true";
if (preg_match('/\bnon.?convert[ei]/i', $__bm)) $__where[] = "(converted IS NULL OR converted=false)";
if (preg_match('/\b(?:30|trente)\s*(?:derniers?|dernier)\s*jours?|last\s+30\s*days?/i', $__bm)) $__where[] = "created_at >= CURRENT_DATE - INTERVAL '30 days'";
if (preg_match('/\b(?:7|sept)\s*(?:derniers?|dernier)\s*jours?|last\s+7\s*days?|derni[eè]re?\s+semaine/i', $__bm)) $__where[] = "created_at >= CURRENT_DATE - INTERVAL '7 days'";
if (preg_match('/\bDZ|alg[ée]rie\b/i', $__bm)) $__where[] = "pays='DZ'";
if (preg_match('/\bMA|maroc\b/i', $__bm)) $__where[] = "pays='MA'";
if (preg_match('/\bTN|tunisie\b/i', $__bm)) $__where[] = "pays='TN'";
// Comparison "30j vs 30j avant"
if (preg_match('/\b(?:30j|30\s+jours?|derniers?\s+30|last\s+30)[\s\S]*?(?:vs|versus|contre|avant|compar[eé])/i', $__bm)) {
$__q = "SELECT 'last_30d' periode, count(*) c FROM {$__table} WHERE created_at >= CURRENT_DATE - INTERVAL '30 days' UNION ALL SELECT 'prev_30d', count(*) FROM {$__table} WHERE created_at >= CURRENT_DATE - INTERVAL '60 days' AND created_at < CURRENT_DATE - INTERVAL '30 days'";
} else {
$__wc = empty($__where) ? "" : " WHERE " . implode(' AND ', $__where);
$__q = "SELECT count(*) c FROM {$__table}{$__wc}";
}
$__cmd = 'PGPASSWORD=admin123 timeout 10 psql -h 10.1.0.3 -U admin -d adx_system -c ' . escapeshellarg($__q) . ' 2>&1';
$__out = @shell_exec($__cmd);
header('Content-Type: application/json');
echo json_encode([
'provider' => 'opus-early-guard',
'content' => "COUNT BUSINESS REAL (S95):\nTable: $__table\nQuery: $__q\n\nResult:\n" . trim($__out ?? 'DB_ERR'),
'tool' => 'count_business_real',
'source' => 'early-guard-primary',
'table' => $__table,
]);
exit;
}
}
// Crons CRM / system crons diagnostic
if (preg_match('/\b(?:crons?|cron\s+job|import)[\s\S]*?(?:CRM|crm|import|stopp[eé]|cass[eé]|fail|broken)|import[s]?\s+(?:stopp|cass|fail|broken)/iu', $__bm)) {
$__c = [];
$__c[] = "=== CRONS DIAGNOSTIC ===";
$__c[] = "S204 crontab www-data:\n" . trim(@shell_exec('crontab -u www-data -l 2>&1 | head -30') ?? 'N/A');
$__c[] = "S204 crontab root:\n" . trim(@shell_exec('sudo crontab -u root -l 2>&1 | head -30') ?? 'N/A');
// Import-related crons
$__c[] = "Import/CRM crons grep:\n" . trim(@shell_exec('(sudo crontab -u root -l; crontab -u www-data -l) 2>&1 | grep -iE "crm|import|pipeline|deal|lead" | head -15') ?? 'N/A');
// Latest import log
$__logs = @shell_exec('ls -t /var/log/weval/*crm* /var/log/weval/*import* /var/log/weval/*pipeline* 2>/dev/null | head -3');
$__c[] = "Latest import logs files:\n" . trim($__logs ?? 'aucun log /var/log/weval/');
if ($__logs) {
$__first = trim(explode("\n", $__logs)[0]);
if (is_file($__first)) $__c[] = "Tail $__first:\n" . trim(@shell_exec("tail -15 " . escapeshellarg($__first)) ?? '');
}
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>implode("\n\n", $__c),'tool'=>'crons_diagnostic_real','source'=>'early-guard-primary']);
exit;
}
}
// === SELF_META INTENT (22avr Opus - vrai count tools) ===
if (preg_match('/\b(?:self[_\s-]?meta|tool[s]?[_\s-]?count|combien.*tool|tools[\s_]?meta|capabilities[_\s-]?count|stats?\s+(?:wevia|master|tools)|tu\s+as\s+combien)\b/iu', $__bm)) {
$__sm = [];
$__sm[] = "=== WEVIA MASTER SELF_META ===";
// Tool registry count
$__reg = @file_get_contents('/opt/wevia-brain/wevia-tool-registry.json');
if ($__reg) {
$__rj = json_decode($__reg, true);
$__sm[] = "Tool registry: v" . ($__rj['v'] ?? '?') . " · count=" . ($__rj['count'] ?? '?') . " · array_size=" . count($__rj['tools'] ?? []);
} else { $__sm[] = "Tool registry: NOT FOUND"; }
// Priority intents NL
$__pi = trim(@shell_exec('wc -l < /opt/wevia-brain/priority-intents-nl.json 2>/dev/null'));
$__sm[] = "Priority intents NL: " . ($__pi ?: '?') . " lines";
// OSS exec registry
$__oss = trim(@shell_exec('cat /opt/wevia-brain/oss-exec-registry.json 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d) if isinstance(d,(list,dict)) else 0)" 2>/dev/null'));
$__sm[] = "OSS exec registry tools: " . ($__oss ?: '?');
// Brain JSONs
$__bj = trim(@shell_exec('find /opt/wevia-brain -maxdepth 2 -name "*.json" 2>/dev/null | wc -l'));
$__sm[] = "Brain knowledge JSONs: " . ($__bj ?: '?');
// Top-IA scripts
$__ti = trim(@shell_exec('ls /opt/weval-ops/top-ia/ 2>/dev/null | wc -l'));
$__sm[] = "Top-IA scripts: " . ($__ti ?: '?');
// Plugins
$__pl = trim(@shell_exec('find /opt/weval-plugins -maxdepth 2 -type d 2>/dev/null | wc -l'));
$__sm[] = "Plugins dirs: " . ($__pl ?: '?');
// DeerFlow skills
$__df = trim(@shell_exec('find /opt/deer-flow -name "*.py" 2>/dev/null | wc -l'));
$__sm[] = "DeerFlow Python scripts: " . ($__df ?: '?');
// Doctrines
$__dc = trim(@shell_exec('ls /var/www/html/wiki/doctrine-*.md 2>/dev/null | wc -l'));
$__sm[] = "Doctrines wiki: " . ($__dc ?: '?');
// Crons WEVIA
$__cr = trim(@shell_exec('ls /etc/cron.d/wevia* 2>/dev/null | wc -l'));
$__sm[] = "Active WEVIA crons: " . ($__cr ?: '?');
$__sm[] = "";
$__sm[] = "=== ARCHITECTURE ===";
$__sm[] = "S204 nginx PHP-FPM dual-pool · S95 PMTA email PostgreSQL · 0eur month all sovereign";
$__sm[] = "Pipeline: nl-priority(80) -> pareto -> fast-path-v3 -> opus-intents(66) -> conv-guard -> arena -> dynamic-resolver -> wave200 -> gap-intents -> master-router -> LLM";
header('Content-Type: application/json');
echo json_encode(['provider'=>'opus-early-guard','content'=>implode("\n", $__sm),'tool'=>'self_meta_real','source'=>'early-guard-primary']);
exit;
}
// === END OPUS_BUSINESS_COUNT_GUARD_17AVR ===
// === V77 PARALLEL MAX-AGENTS (19avr Opus - zero ecrasement) ===
// Intercept max agents / tous les agents / parallelise BEFORE standard SSE.
// V77 fires ~37 agents in parallel ~256ms vs standard sequential 3.4s.
if (!empty($_mam)) {
$_v77_low = mb_strtolower($_mam);
$_v77_triggers = ['max agents','max d agents','tous les agents','tous agents','agents maximum','maximum agents','full parallele','parallel max','max parallele','parallelise','100 agents','v77'];
foreach ($_v77_triggers as $_t) {
if (stripos($_v77_low, $_t) !== false) {
header('X-Accel-Buffering: no');
$msg = $_mam;
include __DIR__ . '/wevia-v77-parallel-executor.php';
exit;
}
}
}
// === V77 PARALLEL MAX-AGENTS END ===
// === V78 CAPABILITY DISPATCHER (19avr Opus) ===
// Intercept dispatcher / selective agents / focus agents BEFORE standard SSE.
// V78 selects relevant agents by keyword matching, fires parallel.
if (!empty($_mam)) {
$_v78_low = mb_strtolower($_mam);
$_v78_triggers = ['dispatcher','selective agents','focus agents','smart agents','agents selectif','agents pertinents','capability dispatcher','agents sur mesure'];
foreach ($_v78_triggers as $_t) {
if (stripos($_v78_low, $_t) !== false) {
header('X-Accel-Buffering: no');
$msg = $_mam;
include __DIR__ . '/wevia-v78-capability-dispatcher.php';
exit;
}
}
}
// === V78 CAPABILITY DISPATCHER END ===
// OPUS WIRE: Content-generation guard — bypass multiagent for content requests
$_is_content_req = preg_match('/(?:r[eé]dige|[eé]cris|pr[eé]pare|g[eé]n[eè]re|compose|cr[eé]e|fais)[\s\-].*(?:post|linkedin|article|contenu|texte|email|marketing|communic|blog|newsletter|carousel|pitch)/iu', $_mam)
|| preg_match('/(?:post|article|contenu|texte)[\s\-].*(?:linkedin|marketing|r[eé]seau|social)/iu', $_mam)
|| preg_match('/(?:plan|calendrier|strat[eé]gie)[\s\-]+(?:de\s+)?(?:contenu|[eé]ditorial|publication|linkedin|marketing)/iu', $_mam);
// V27-SURGICAL 20avr Opus (doctrine #73 Type B + #54): exclude structured intents from content-guard
if ($_is_content_req && preg_match('/\\b(kaizen|muda|andon|5s|pdca|gemba|poka[\\s-]?yoke|a3|ticket|reminder|todo|stub|intent|dashboard|autonomy|honest|orphans|plans?\\s+list|plan\\s+status|kpi\\s+feeder|health\\s+check|capabilities|ethica\\s+count|paperclip|git\\s+(full|status|commit))\\b/iu', $_mam)) {
$_is_content_req = false; // structured intent has priority over content-gen
}
if (!$_is_content_req) { // Only multiagent SSE if NOT a content request
if(preg_match("/multi[\s\-]?agents?|plusieurs[\s\-]?agents?|\d+\s*agents?[\s\-]+(en[\s\-]+)?parall[eè]le|agents?[\s\-]+en[\s\-]+parall[eè]le|agir[\s\-]+en[\s\-]+(multi[\s\-]?)?agents?/iu",$_mam)){$_GET["msg"]=$_mam;header("X-Accel-Buffering: no");include __DIR__."/wevia-sse-orchestrator.php";exit;}}
// OPUS WIRE: Content enrichment — inject real platform data for content-generation requests
if ($_is_content_req ?? false) {
$_platform_data = "DONNÉES PLATEFORME RÉELLES WEVAL (à utiliser dans le contenu):\n"
. "- 153/153 tests NonReg (zéro régression)\n"
. "- 930 agents en production\n"
. "- 382 outils dans le resolver dynamique\n"
. "- 131 639 HCPs Ethica (109K email, 131K tel)\n"
. "- 12/13 providers IA souverains, 0€\n"
. "- 19 containers Docker\n"
. "- -40% délais de pilotage\n"
. "- 1,2M€ de gaspillage identifié\n"
. "- ROI en 4 mois\n"
. "- POC gratuit 2 semaines\n"
. "- 15 dépôts enterprise\n";
$_mam = $_platform_data . "\n\nDEMANDE UTILISATEUR: " . $_mam;
// CONTENT_ENRICHMENT_WIRE marker
// OPUS_CONTENT_DIRECT_LLM_FIX — bypass opus-intents + fast-path for content requests
// Direct to sovereign LLM with enriched $_mam
$__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 Master, IA souveraine de WEVAL Consulting Casablanca. Tu es un expert en rédaction de contenu professionnel, marketing digital et LinkedIn. Tu rédiges du contenu premium en français impeccable : orthographe parfaite, accents corrects, ton de dirigeant. Tu utilises les données réelles de la plateforme WEVAL fournies ci-dessous pour enrichir tes textes. Sois concret, percutant, orienté storytelling terrain. Maximum 1200 caractères par post sauf indication contraire."],
["role" => "user", "content" => $_mam]
],
"max_tokens" => 2000,
"stream" => false
]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 25
]);
$__cr = curl_exec($__ch); curl_close($__ch);
$__cd = @json_decode($__cr, true);
$__ct = $__cd["choices"][0]["message"]["content"] ?? null;
if ($__ct) {
header("Content-Type: application/json");
echo json_encode([
"response" => $__ct,
"provider" => "wevia-master-enhanced",
"executed" => true,
"wire" => "content-direct-llm"
], JSON_UNESCAPED_UNICODE);
exit;
}
// If LLM fails, fall through to normal pipeline
}
// OPUS LEARNING LOOP v2 — capture TOUTES requêtes avant tout fast-path/include
if ($_mam) {
@mkdir('/var/log/wevia', 0755, true);
register_shutdown_function(function() {
$m = $GLOBALS['_mam'] ?? '';
if (!$m) return;
$http = http_response_code();
$prov = $GLOBALS['_OPUS_PROVIDER'] ?? '';
$entry = json_encode([
'ts' => date('c'),
'msg' => substr($m, 0, 500),
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'origin' => $_SERVER['HTTP_ORIGIN'] ?? '',
'http' => $http,
], JSON_UNESCAPED_UNICODE);
@file_put_contents('/var/log/wevia/requests-all.jsonl', $entry . "\n", FILE_APPEND | LOCK_EX);
});
}
// OPUS_CONTENT_BYPASS_FP
if (!($_is_content_req ?? false)) {
// OPUS WIRED INTENTS — fired BEFORE fast-path-v3 (priority for: audit_6sigma, brains_status, debug_fix, send_test, new_pages)
// OPUS46 ADVANCED EXECUTION INTENTS (16AVR)
// OPUS WRITE INTENTS — V12-FINAL autonomie closure (doctrines 46-48): FIRES FIRST
@require_once __DIR__ . "/wevia-opus-write-intents.php";
require_once __DIR__ . '/wevia-oss-intents.php';
require_once __DIR__ . '/wevia-observe-crm-intent.php';
require_once __DIR__ . '/wevia-send-kaouther-intent.php';
require_once __DIR__ . '/wevia-ops-intents.php';
require_once __DIR__ . '/wevia-blade-actions-intent.php';
require_once __DIR__ . '/wevia-partners-intent.php';
require_once __DIR__ . '/wevia-test-email-intent.php';
require_once __DIR__ . '/wevia-office-senders-intent.php';
require_once __DIR__ . '/wevia-ops-screens-intent.php';
@include __DIR__ . '/wevia-vault-git-intents.php';
@include __DIR__ . '/wevia-opus-arch-intents.php';
@include __DIR__ . '/wevia-opus-arch-actions-intents.php'; // V40 actions // V37 arch caps // V32 vault/git/l99 BEFORE doctrine catchall
require_once __DIR__ . '/wevia-doctrine-74-fix-intent.php';
require_once __DIR__ . '/wevia-doctrine-74-intent.php';
require_once __DIR__ . '/wevia-azure-reregister-intent.php';
require_once __DIR__ . '/wevia-backlog-status-intent.php';
require_once __DIR__ . '/wevia-confirm-sql-intent.php';
require_once __DIR__ . '/wevia-sovereign-heal-intent.php';
@require_once __DIR__ . '/wevia-self-diagnostic-intent.php'; // OPUS 20avr doctrine #2 ZERO simulation
if (function_exists("wevia_self_diagnostic")) {
$_sdmsg = json_decode(file_get_contents("php://input"),true)["message"] ?? $_POST["message"] ?? $_GET["message"] ?? "";
$_sd = wevia_self_diagnostic($_sdmsg);
if ($_sd) { header("Content-Type:application/json"); echo json_encode($_sd, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); exit; }
}
if (function_exists("wevia_write_intents")) {
$_wwmsg = json_decode(file_get_contents("php://input"),true)["message"] ?? $_POST["message"] ?? $_GET["message"] ?? "";
$_ww = wevia_write_intents($_wwmsg);
if ($_ww) { header("Content-Type:application/json"); echo json_encode($_ww, JSON_UNESCAPED_UNICODE); exit; }
}
@require_once __DIR__ . "/wevia-opus46-intents.php";
if (function_exists("wevia_opus46_exec")) {
$_o46 = wevia_opus46_exec(json_decode(file_get_contents("php://input"),true)["message"] ?? $_POST["message"] ?? $_GET["message"] ?? "");
if ($_o46) { header("Content-Type:application/json"); echo json_encode($_o46); exit; }
}
@require_once __DIR__ . "/wevia-opus-intents.php";
if (function_exists("wevia_opus_intents")) {
$_oi = wevia_opus_intents(json_decode(file_get_contents("php://input"),true)["message"] ?? $_POST["message"] ?? $_GET["message"] ?? "");
if ($_oi) { header("Content-Type:application/json"); /* W258_HOOK_v1 */ @w258_save_asst($_oi["content"] ?? $_oi["response"] ?? null); echo json_encode($_oi); exit; }
}
@require_once __DIR__ . "/wevia-fast-path-v3.php";
$_fp = function_exists("wevia_fast_path") ? wevia_fast_path(json_decode(file_get_contents("php://input"),true)["message"] ?? $_POST["message"] ?? $_GET["message"] ?? "") : null;
// W258_SKIP_FP: si user a deja un historique memoire (>2 msgs), skip fast-path car il n'utilise pas history
$_fp_skip = false;
if (!empty($GLOBALS["__w258_sid"])) {
try {
$_fp_r = new Redis(); $_fp_r->connect("127.0.0.1", 6379, 1.5); $_fp_r->select(5);
$_fp_cur = $_fp_r->get("chatmem:wevia-master:" . $GLOBALS["__w258_sid"]);
$_fp_arr = $_fp_cur ? json_decode($_fp_cur, true) : [];
if (is_array($_fp_arr) && count($_fp_arr) >= 3) $_fp_skip = true;
} catch (Throwable $e) {}
}
if ($_fp && !$_fp_skip) { header("Content-Type:application/json"); /* W258_HOOK_v1 */ @w258_save_asst($_fp["content"] ?? $_fp["response"] ?? null); echo json_encode($_fp); exit; }
} // end OPUS_CONTENT_BYPASS_FP
// OPUS AUTONOMY LAYER (BEFORE conv-guard): execution + paperclip bridge + archi-aware + self-wire
@require_once __DIR__ . '/wevia-opus-autonomy.php';
if (function_exists('opus_autonomy_check') && isset($_JIN['message'])) {
$_oa = opus_autonomy_check($_JIN['message']);
if ($_oa) { header('Content-Type:application/json'); /* W258_HOOK_v1 */ @w258_save_asst($_oa["content"] ?? $_oa["response"] ?? null); echo json_encode($_oa, JSON_UNESCAPED_UNICODE); exit; }
}
// === CONV_GUARD ===
$_cg=$_JIN["message"]??"";
if(preg_match("/(aide|r[eé]dig|[eé]cri|explique|propose|compare|analyse|tradui|r[eé]sum|am[eé]lior|pr[eé]par|d[eé]cri|donne|raconte|conseille|argumente|convainc|formule|g[eé]n[eé]r|imagine|sugg[eé]r|[eé]labor|d[eé]taill|comment\s+(faire|amelior|organis|structur|convaincr))\/iu",$_cg) && !preg_match("/\b(status|git|docker|cron|disk|nonreg|sovereign|deploy|restart|backup|push|system|infra|l99|scan|diagnostic|nginx|domain|paperclip|deerflow|qdrant|ssl|wiki|vault|arena|cortex|mirofish|provider|cascade|agent|tool|registry|playwright|selenium|qa|visual.*test|chrome.*test|nonreg|l99|reconcil|tableau|dashboard|screenshot|sous-domain|vid[eé]o|ollama|doctrine)\b/i",$_cg)){
// SOVEREIGN DIRECT (bypass mr_route qui timeout)
$__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. Tu aides Yacine avec des réponses directes, concrètes et en français. Tu connais: WEVADS (email marketing), Ethica (141K HCPs pharma), 13 providers IA gratuits, 412 tools, 179 pages."],["role"=>"user","content"=>$_cg]],"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){header("Content-Type:application/json");/* W258_HOOK_v1 */ @w258_save_asst($__txt);echo json_encode(["provider"=>"conv-guard-sovereign","content"=>$__txt,"tool"=>"conv-guard","model"=>$__d2["model"]??"auto"],JSON_UNESCAPED_UNICODE);exit;}
}
// OPUS-PERSISTENT PRE-ROUTER HOOK
$_jin=json_decode(file_get_contents('php://input'),true);
if($_jin && isset($_jin['message'])) $_POST['message']=$_jin['message'];
if(isset($_POST['message'])||isset($_GET['message'])||isset($_jin['message'])){
$_msg=$_jin['message']??$_POST['message']??$_GET['message']??'';
@require_once '/opt/wevia-brain/arena-pre-intents.php';
$_arena=function_exists('arena_pre_check')?arena_pre_check($_msg):null;
if($_arena){header('Content-Type:application/json');echo json_encode($_arena);exit;}
// Dynamic Tool Resolver — 67 tools from JSON registry
@require_once '/opt/wevia-brain/wevia-dynamic-resolver.php';
$_dyn = function_exists('wevia_dynamic_resolve') ? wevia_dynamic_resolve($_msg) : null;
if ($_dyn) { $_dyn['provider']=$_dyn['provider']??'fs-verify'; header('Content-Type:application/json'); echo json_encode($_dyn); exit; }
require_once '/opt/wevia-brain/wevia-wave200.php';
$_w200=wevia_wave200($_msg,['provider'=>'fs-verify','tier'=>0,'latency_ms'=>0,'cost'=>0,'source'=>'wave200-pre']);
if($_w200){header('Content-Type:application/json');echo json_encode($_w200);exit;}
require_once '/opt/wevia-brain/wevia-gap-intents.php';
$_base=['provider'=>'fs-verify','tier'=>0,'latency_ms'=>0,'cost'=>0,'source'=>'opus-persistent'];
$_r=function_exists('opus_persistent_intents')?opus_persistent_intents($_msg,$_base):null;
if(!$_r && function_exists('opus_ux_audit')) $_r=opus_ux_audit($_msg,$_base);
if(!$_r && function_exists('opus_mega_intents')) $_r=opus_mega_intents($_msg,$_base);
if(!$_r && function_exists('opus_tout_va_bien')) $_r=opus_tout_va_bien($_msg,$_base);
if(!$_r && function_exists('opus_extra_intents')) $_r=opus_extra_intents($_msg,$_base);
if($_r){header('Content-Type:application/json');echo json_encode($_r);exit;}
}
/**
* WEVIA MASTER API v1.0 — Standalone endpoint
* URL: /api/wevia-master-api.php
*
* ENDPOINTS:
* POST /api/wevia-master-api.php → Route a message
* GET /api/wevia-master-api.php?health → Health check
* GET /api/wevia-master-api.php?stats → Routing statistics
* GET /api/wevia-master-api.php?test → Quick test
* GET /api/wevia-master-api.php?dashboard → Visual dashboard
*/
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") { http_response_code(200); exit; }
clearstatcache(true, "/opt/wevia-brain/wevia-master-router.php"); if (function_exists('opcache_invalidate')) opcache_invalidate("/opt/wevia-brain/wevia-master-router.php", true);
require_once "/opt/wevia-brain/wevia-master-router.php";
// ═══ ROUTING ═══
$action = null;
if (isset($_GET['health'])) $action = 'health';
elseif (isset($_GET['stats'])) $action = 'stats';
elseif (isset($_GET['test'])) $action = 'test';
elseif (isset($_GET['score'])) $action = 'score';
elseif (isset($_GET['dashboard'])) $action = 'dashboard';
elseif (isset($_GET['rag'])) $action = 'rag';
elseif (isset($_GET['capabilities'])) $action = 'capabilities';
switch ($action) {
case 'health':
echo json_encode(mr_healthCheck(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'stats':
echo json_encode(mr_getStats(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'test':
$msg = $_GET['q'] ?? 'Bonjour, comment vas-tu?';
// Dynamic Resolver FIRST (258 exec tools)
@require_once '/opt/wevia-brain/wevia-dynamic-resolver.php';
$_dr = function_exists('wevia_dynamic_resolve') ? wevia_dynamic_resolve($msg) : null;
if ($_dr) { echo json_encode(['provider'=>$_dr['source']??'dynamic-resolver','response'=>$_dr['content']??''], JSON_UNESCAPED_UNICODE); exit; }
// OPUS INTERCEPT GET
$__base2 = ['provider' => 'opus-intercept', 'tier' => 0];
$__r2 = opus_persistent_intents($msg, $__base2);
if (!$__r2) $__r2 = opus_ux_audit($msg, $__base2);
if (!$__r2) $__r2 = opus_mega_intents($msg, $__base2);
if ($__r2) { echo json_encode($__r2); exit; }
$result = mr_route($msg, @file_get_contents('/etc/wevia/system-prompt.txt') ?: 'Tu es WEVIA, IA souveraine de WEVAL Consulting.');
echo json_encode([
'input' => $msg,
'response' => mb_substr($result['content'], 0, 500),
'model' => $result['model'],
'provider' => $result['provider'],
'tier' => $result['tier'],
'latency_ms' => $result['latency_ms'],
'source' => $result['source'],
'routing' => $result['routing'] ?? null,
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'score':
$msg = $_GET['q'] ?? '';
if (empty($msg)) {
echo json_encode(['error' => 'Pass ?score&q=your+message']);
exit;
}
echo json_encode(mr_scoreComplexity($msg), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'capabilities':
$caps = wevia_listCapabilities();
// Wire dormant capabilities from registry
$dormFile = '/opt/wevia-brain/wevia-master-capabilities.json';
if (file_exists($dormFile)) {
$dorm = json_decode(file_get_contents($dormFile), true);
$caps['dormant_capabilities'] = $dorm['summary'] ?? [];
$caps['total_capabilities'] = ($dorm['total'] ?? 0) + count($caps);
$caps['dormant_categories'] = array_keys($dorm['categories'] ?? []);
}
echo json_encode($caps, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'rag':
$msg = $_GET['q'] ?? 'Comment fonctionne WEVADS?';
$rag = rag_search($msg);
echo json_encode($rag, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
case 'dashboard':
header("Content-Type: text/html; charset=utf-8");
$stats = mr_getStats();
$health = mr_healthCheck();
?><!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVIA Master Router — Dashboard</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0a0a0f;color:#e8e6f0;font-family:-apple-system,sans-serif;padding:2rem}
h1{font-size:1.8rem;margin-bottom:1rem;color:#00ff88}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;margin:1.5rem 0}
.card{background:#12121a;border:1px solid #2a2a3d;border-radius:12px;padding:1.2rem;text-align:center}
.card .num{font-size:2.2rem;font-weight:700;color:#00ff88;font-family:monospace}
.card .label{font-size:.75rem;color:#8888a8;margin-top:.3rem}
.status{display:inline-block;padding:.2em .6em;border-radius:100px;font-size:.7rem;font-family:monospace}
.up{background:#00ff8822;color:#00ff88;border:1px solid #00ff88}
.down{background:#ff446622;color:#ff4466;border:1px solid #ff4466}
table{width:100%;border-collapse:collapse;margin:1rem 0;font-size:.85rem}
th{background:#1a1a28;padding:.6rem;text-align:left;font-size:.7rem;text-transform:uppercase;letter-spacing:.1em;color:#8888a8}
td{padding:.5rem .6rem;border-bottom:1px solid #2a2a3d}
.t0{color:#00ff88}.t1{color:#4488ff}.t2{color:#aa66ff}.t3{color:#ff4466}
pre{background:#12121a;border:1px solid #2a2a3d;border-radius:8px;padding:1rem;overflow-x:auto;font-size:.75rem;margin:1rem 0}
</style>
</head>
<body>
<h1>⚡ WEVIA Master Router v<?=MR_VERSION?></h1>
<div class="grid">
<div class="card">
<div class="num"><?=$health['ollama']==='UP'?'<span class="status up">UP</span>':'<span class="status down">DOWN</span>'?></div>
<div class="label">Ollama (port 11434)</div>
</div>
<div class="card"><div class="num"><?=$health['ollama_models']??0?></div><div class="label">Modèles locaux</div></div>
<div class="card"><div class="num"><?=$health['tier1_providers']?></div><div class="label">Tier 1 (free fast)</div></div>
<div class="card"><div class="num"><?=$health['tier2_providers']?></div><div class="label">Tier 2 (free quality)</div></div>
<div class="card"><div class="num"><?=$health['secrets_count']?></div><div class="label">Secrets chargés</div></div>
</div>
<h2 style="margin-top:2rem">📊 Stats par jour</h2>
<table>
<thead><tr><th>Date</th><th>Total</th><th class="t0">Tier 0 (local)</th><th class="t1">Tier 1 (fast)</th><th class="t2">Tier 2 (quality)</th><th>Latence moy.</th><th>Coût</th></tr></thead>
<tbody>
<?php
if (is_array($stats)) {
krsort($stats);
foreach ($stats as $date => $d) {
if (!is_array($d)) continue;
$t0 = $d['by_tier'][0] ?? 0;
$t1 = $d['by_tier'][1] ?? 0;
$t2 = $d['by_tier'][2] ?? 0;
$total = $d['total'] ?? 0;
$pct0 = $total > 0 ? round($t0/$total*100) : 0;
echo "<tr><td>$date</td><td>{$total}</td>";
echo "<td class='t0'>{$t0} ({$pct0}%)</td>";
echo "<td class='t1'>{$t1}</td><td class='t2'>{$t2}</td>";
echo "<td>{$d['avg_latency']}ms</td><td>{$d['cost']}€</td></tr>";
}
}
?>
</tbody>
</table>
<h2>🔍 Test rapide</h2>
<p style="color:#8888a8;margin:.5rem 0">Exemples:</p>
<pre>
curl "<?=$_SERVER['HTTP_HOST']?>/api/wevia-master-api.php?test&q=Bonjour"
curl "<?=$_SERVER['HTTP_HOST']?>/api/wevia-master-api.php?score&q=Explique+comment+optimiser+nginx"
curl "<?=$_SERVER['HTTP_HOST']?>/api/wevia-master-api.php?health"
</pre>
<h2>🏗️ Architecture</h2>
<pre>
TIER 0 (Souverain, 0€) → Ollama:11434 [weval-brain-v2, qwen2.5:7b, qwen3:4b, mistral, medllama2]
TIER 1 (Free ultra-fast) → Cerebras, Groq, SambaNova
TIER 2 (Free quality) → Mistral Cloud, Cohere, Gemini
TIER 3 (Frontier, payant) → Claude API, GPT API (non implémenté — dernier recours)
</pre>
<h2>📡 Providers actifs</h2>
<pre><?php
$t1 = mr_getTier1Providers();
foreach ($t1 as $n => $c) echo "TIER1 $n: {$c['model']} ({$c['speed']})\n";
$t2 = mr_getTier2Providers();
foreach ($t2 as $n => $c) echo "TIER2 $n: {$c['model']} ({$c['speed']})\n";
?></pre>
<p style="margin-top:2rem;font-size:.7rem;color:#555">WEVIA Master Router — WEVAL Consulting — Avril 2026</p>
</body></html>
<?php
exit;
}
// ═══ POST: Route a message ═══
if ($_SERVER["REQUEST_METHOD"] !== "POST") {
echo json_encode(['error' => 'POST required. Try ?health, ?stats, ?test, ?dashboard']);
exit;
}
// Debug: log raw input
$rawInput = file_get_contents("php://input");
@file_put_contents("/tmp/master-debug.log", date("H:i:s")." RAW=".substr($rawInput,0,200)."\n", FILE_APPEND);
$input = json_decode($rawInput, true);
$message = $input['message'] ?? $input['msg'] ?? $input['content'] ?? '';
$system = $input['system'] ?? (@file_get_contents('/etc/wevia/system-prompt.txt') ?: 'Tu es WEVIA, IA souveraine de WEVAL Consulting.');
// OPUS-FIX RC#7: Inject architecture context for LLM awareness
$system .= "\nARCHI INTERNE: Sovereign=port4000(13 providers IA). Paperclip=890agents/2484skills. DeerFlow=14skills. Registry=375tools. Wiki=1229. Vault=550. Pages=174. APIs=437. Ethica=141K HCPs. MonDsh=test NonReg Monitoring Dashboard. Monitor=test FUNC NonReg. WEVCODE=IDE souverain. Arsenal=backoffice port5890.";
$history = $input['history'] ?? [];
// W115b-PRE: Snapshot Hetzner (12-AVR) — intercept BEFORE wave114
if (preg_match('/(snapshot.*hetzner|hetzner.*snap|snap.*archiv|archiv.*snap|snap.*status|snap.*progress)/iu', $message)) {
$log = @file_get_contents('/tmp/wevia-snapshot-archiver.log');
$ps = trim(@shell_exec('ps aux 2>/dev/null | grep "wevia-snap-archiver" | grep -v grep'));
// W115b-LAUNCH/KILL (wired by Opus)
if (preg_match("/(lance|start|relance|demarre)/iu", $message) && empty($ps)) {
@shell_exec("rm -f /tmp/snap-archiver.lock; echo /tmp/snap-final.sh | at now 2>&1");
sleep(3);
$r = "ARCHIVER LANCE! Verifier dans 30s avec snap archiver status";
echo json_encode(["content"=>$r,"provider"=>"fs-verify","source"=>"w115b-launch"], JSON_UNESCAPED_UNICODE);
exit;
}
if (preg_match("/(kill|stop|arret)/iu", $message)) {
@shell_exec("pkill -f wevia-snap-archiver 2>/dev/null; rm -f /tmp/snap-archiver.lock");
$r = "ARCHIVER STOPPE";
echo json_encode(["content"=>$r,"provider"=>"fs-verify","source"=>"w115b-kill"], JSON_UNESCAPED_UNICODE);
exit;
}
$hz = trim(@shell_exec('python3 /opt/weval-l99/wevia-snap-archiver.py list 2>&1'));
$r = "ARCHIVER: " . ($ps ? "RUNNING
" . $ps : "STOPPED") . "
Snapshots:
" . $hz . "
Log (last 10):
" . ($log ? implode("
", array_slice(explode("
", trim($log)), -10)) : "NO_LOG");
echo json_encode(['content'=>$r,'provider'=>'fs-verify','tier'=>0,'latency_ms'=>0,'cost'=>0,'source'=>'w115b'],JSON_UNESCAPED_UNICODE);
exit;
}
// STRATEGIC GUARD: skip wave114 for business/strategy questions → go direct mr_route
// === OPUS4-AUTOWIRE-INCLUDE-v1 (17avr) ===
// Fix cause racine : Wave 128 autowire syntax tombait en LLM fallback.
// Handler traite "master add intent" + "master list intents" AVANT strategic-guard.
@require_once '/opt/wevia-brain/opus4-autowire-handler.php';
// === OPUS4-AUTOWIRE-INCLUDE-v1 END ===
require_once '/opt/wevia-brain/wevia-strategic-guard.php';
if (!is_strategic_question($message)) {
// === WAVE 114: Intent-first routing ===
$_exec_url = "https://127.0.0.1/api/wevia-full-exec.php?" . http_build_query(['m' => $message]);
$_exec_ctx = stream_context_create(["http" => ["timeout" => 25, "header" => "Host: weval-consulting.com
"], "ssl" => ["verify_peer" => false, "verify_peer_name" => false]]);
$_exec_raw = @file_get_contents($_exec_url, false, $_exec_ctx);
if ($_exec_raw) {
$_exec_d = @json_decode($_exec_raw, true);
$_exec_r = $_exec_d['response'] ?? '';
if ($_exec_r && strlen($_exec_r) > 20 && strpos($_exec_r, 'Dispo:') !== 0) {
echo json_encode(['content' => $_exec_r, 'provider' => 'fs-verify', 'tier' => 0, 'latency_ms' => 0, 'cost' => 0, 'source' => 'intent-execution'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
exit;
}
}
} // end strategic guard wave114
$options = $input['options'] ?? [];
// === WAVE 135: Handle file attachments ===
$attachments = $input['attachments'] ?? [];
if (!empty($attachments)) {
@mkdir('/tmp/wevia-uploads', 0777, true);
$fileContext = "\n\nFICHIERS JOINTS:\n";
foreach (array_slice($attachments, 0, 5) as $att) {
$name = preg_replace('/[^a-zA-Z0-9._-]/', '_', $att['name'] ?? 'file');
$data = base64_decode($att['data'] ?? '');
$path = "/tmp/wevia-uploads/" . time() . "_" . $name;
file_put_contents($path, $data);
$size = strlen($data);
$type = $att['type'] ?? 'unknown';
if (strpos($type, 'image') !== false) {
// Image: save and describe
$fileContext .= "- Image: $name ({$size}B) sauvee: $path\n";
$fileContext .= " Type: $type. Analyse visuelle demandee.\n";
// Copy to public screenshots for reference
@copy($path, "/var/www/html/screenshots/upload_" . basename($path));
$fileContext .= " URL: https://weval-consulting.com/screenshots/upload_" . basename($path) . "\n";
} elseif (strpos($type, 'text') !== false || strpos($type, 'javascript') !== false || strpos($type, 'php') !== false || strpos($type, 'json') !== false || strpos($type, 'xml') !== false || strpos($type, 'csv') !== false) {
// Text/code: read content
$content = substr($data, 0, 5000);
$fileContext .= "- Fichier texte: $name ({$size}B)\n";
$fileContext .= " Contenu:\n```\n$content\n```\n";
} elseif (strpos($type, 'pdf') !== false) {
$fileContext .= "- PDF: $name ({$size}B) sauve: $path\n";
// Try pdftotext
$txt = @shell_exec("pdftotext $path - 2>/dev/null | head -100");
if ($txt) $fileContext .= " Extrait:\n$txt\n";
} else {
$fileContext .= "- Fichier: $name ($type, {$size}B) sauve: $path\n";
}
}
$message .= $fileContext;
}
if (empty(trim($message))) {
echo json_encode(['error' => 'message required']);
exit;
}
ob_start();
try {
// OPUS INTERCEPT: check persistent intents BEFORE LLM
$__base = ['provider' => 'opus-intercept', 'tier' => 0, 'latency_ms' => 0, 'cost' => 0, 'source' => 'opus-persistent'];
$__r = opus_persistent_intents($message, $__base);
if (!$__r) $__r = opus_ux_audit($message, $__base);
if (!$__r) $__r = opus_mega_intents($message, $__base);
if ($__r) {
echo json_encode($__r);
exit;
}
// VAULT CONTEXT: inject relevant notes to reduce tokens
@include_once '/opt/wevia-brain/wevia-vault-context.php';
if (function_exists('wevia_vault_context')) {
$vaultCtx = wevia_vault_context($message, 3);
if ($vaultCtx) $system .= $vaultCtx;
}
$result = mr_route($message, $system, $history, $options);
$stray = ob_get_clean();
if (!$result || empty($result)) {
echo json_encode(['error'=>'empty_result','stray_output'=>substr($stray,0,500),'provider'=>'unknown','response'=>'']);
} else {
// Ensure response key exists for admin compatibility
if (!isset($result['response']) && isset($result['content'])) {
$result['response'] = $result['content'];
}
$json = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
if ($json === false) {
// JSON encode failed - likely UTF8 issue
array_walk_recursive($result, function(&$v){if(is_string($v))$v=mb_convert_encoding($v,'UTF-8','UTF-8');});
$json = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE);
}
// WAVE_258: save assistant response before echo
if (isset($result) && is_array($result)) {
$__asst_txt = $result["content"] ?? $result["response"] ?? "";
if ($__asst_txt) @w258_save_asst($__asst_txt);
}
echo $json;
}
} catch (\Throwable $e) {
$stray = ob_get_clean();
echo json_encode(['error'=>$e->getMessage(),'file'=>basename($e->getFile()),'line'=>$e->getLine(),'stray'=>substr($stray,0,200)]);
}