Files
html/api/wevia-autonomous.php.v71-test
2026-04-18 05:10:01 +02:00

1113 lines
81 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// === FAST-PATH INJECTION (14avr - Opus wire) ===
@require_once __DIR__ . "/wevia-fast-path.php";
$__fp_input = json_decode(file_get_contents("php://input"), true);
if ($__fp_input && isset($__fp_input["message"])) {
// Skip FastPath for multi-intent messages (3+ keywords = orchestration mode)
$__fp_words = str_word_count(trim($__fp_input["message"]));
$__fp_multi = preg_match('/reconcile|bilan|multiagent|multi.agent|orchestr|tout finir|full scan/i', $__fp_input["message"]);
$__fp_r = ($__fp_words <= 3 && !$__fp_multi) ? wevia_fast_path($__fp_input["message"]) : null;
if ($__fp_r !== null) {
header("Content-Type: text/event-stream");
echo "data: " . json_encode(["type"=>"answer","text"=>$__fp_r["content"],"engine"=>"FastPath/".$__fp_r["tool"],"intent"=>"fast_path"]) . "\n\ndata: [DONE]\n\n";
exit;
}
}
// === END FAST-PATH ===
// === FILE_WRITE AUTONOMOUS MODULE (15avr - Opus wire RC fix) ===
// Guard (16avr Opus): skip si multi-agent OU verbe read-only OU mot exhaustivite
if ($__fp_input && isset($__fp_input["message"])) {
$__fw_msg = $__fp_input["message"];
$__fw_skip_multi = preg_match('/reconcile|bilan complet|multiagent|multi.agent|orchestr|tout finir|full scan|exhaustiv|cartograph|tous?\s+les?\s+(ecrans?|screens?|machines?|serveurs?)/i', $__fw_msg);
$__fw_skip_readonly = preg_match('/^\s*(montre|affiche|lis|liste|cat|scan|check|verifie|diagnostiq|pull|get|read|show|view|dump|test|ping|status)/i', $__fw_msg);
$__fw_skip_question = preg_match('/^\s*(qui|que|quoi|quel|quelle|comment|pourquoi|ou|quand|combien)\b/i', $__fw_msg);
@require_once __DIR__ . "/wevia-file-write.php";
$__fw_r = (!$__fw_skip_multi && !$__fw_skip_readonly && !$__fw_skip_question) ? wevia_file_write($__fw_msg) : null;
if ($__fw_r !== null) {
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
$st = $__fw_r["ok"] ? "SUCCESS" : "ERROR";
$tx = $__fw_r["ok"] ? $__fw_r["message"] . " Git: " . ($__fw_r["git"] ?? "n/a") : "ERREUR: " . ($__fw_r["error"] ?? "inconnue");
echo "data: " . json_encode(["type"=>"exec","text"=>$tx,"engine"=>"FileWrite/autonomous","intent"=>"file_write","status"=>$st]) . "\n\n";
echo "data: [DONE]\n\n";
exit;
}
}
// === END FILE_WRITE ===
// === MULTI-AGENT ORCHESTRATOR (16avr - v4 split git + safer WRITEs) ===
if ($__fp_input && isset($__fp_input["message"])) {
$__orch_msg = strtolower($__fp_input["message"]);
if (preg_match('/reconcile|bilan complet|multiagent|multi.agent|orchestr|tout finir|full scan|exhaustiv|cartograph|tous?\s+les?\s+(\xc3\xa9crans?|ecrans?|screens?|machines?|serveurs?|gpus?|blades?)/i', $__orch_msg)) {
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
$__orch_registry = [
"reconcile" => ["cmd"=>"/bin/bash /opt/weval-l99/tools/reconcile.sh", "default"=>true, "timeout"=>15],
"providers" => ["cmd"=>"/bin/bash /opt/weval-l99/tools/providers-health.sh", "default"=>true, "timeout"=>15],
"wiki" => ["cmd"=>"/bin/bash /opt/weval-l99/tools/wiki-scan.sh", "default"=>true, "timeout"=>15],
"nonreg" => ["cmd"=>"cat /var/www/html/api/nonreg-latest.json 2>/dev/null", "default"=>true, "timeout"=>10],
"ethica" => ["cmd"=>"cat /var/www/html/api/ethica-latest.json 2>/dev/null || echo Ethica:131K", "default"=>true, "timeout"=>10],
"docker" => ["cmd"=>"docker ps --format '{{.Names}}: {{.Status}}' 2>/dev/null | head -10", "default"=>true, "timeout"=>10],
"disk" => ["cmd"=>"df -h / | tail -1", "default"=>true, "timeout"=>5],
"git" => ["cmd"=>"echo D:$(cd /var/www/html;git diff --name-only 2>/dev/null|wc -l) H:$(cd /var/www/html;git rev-parse --short HEAD 2>/dev/null)", "default"=>true, "timeout"=>10],
"ports" => ["cmd"=>"/bin/bash /opt/weval-l99/tools/ports.sh 2>/dev/null | head -10", "default"=>true, "timeout"=>10],
"load" => ["cmd"=>"cat /proc/loadavg && free -m | grep Mem", "default"=>true, "timeout"=>5],
"screens_s204" => ["cmd"=>"echo 'S204_HTML='$(find /var/www/html -maxdepth 3 -name '*.html' 2>/dev/null | wc -l)' S204_PHP='$(find /var/www/html -maxdepth 3 -name '*.php' 2>/dev/null | wc -l)' API='$(ls /var/www/html/api/*.php 2>/dev/null | wc -l)", "keywords"=>["screen","ecran","\xc3\xa9cran","page"], "timeout"=>15],
"screens_s95" => ["cmd"=>"sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 \"echo ARSENAL=\\$(find /opt/wevads-arsenal/public -maxdepth 2 -name '*.html' 2>/dev/null | wc -l)' WEVADS_HTML='\\$(find /var/www -maxdepth 3 -name '*.html' 2>/dev/null | wc -l)\" 2>&1 | tail -3", "keywords"=>["screen","ecran","\xc3\xa9cran","page","s95","arsenal"], "timeout"=>20],
"gpus" => ["cmd"=>"nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null || echo 'no GPU'; sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 \"nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null || echo 'no GPU s95'\" 2>&1 | tail -3", "keywords"=>["gpu","nvidia","blade","cuda"], "timeout"=>15],
"pmta_all" => ["cmd"=>"for ip in 110.239.84.121 110.239.84.65 182.160.55.107 110.239.86.68; do echo -n \"PMTA_$ip: \"; timeout 3 curl -s -o /dev/null -w '%{http_code}\\n' http://$ip:5371/ 2>/dev/null || echo 'DOWN'; done", "keywords"=>["pmta","mta","huawei","ser_"], "timeout"=>25],
"machines_all" => ["cmd"=>"hostname && uptime; sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 'hostname && uptime' 2>&1 | head -3", "keywords"=>["machine","serveur","server","infra","s204","s95"], "timeout"=>15],
"services_s204" => ["cmd"=>"systemctl list-units --type=service --state=running --no-pager 2>/dev/null | grep -E 'apache|nginx|php|postgres|pmta|docker' | head -15", "keywords"=>["service","systemd","daemon"], "timeout"=>15],
"crons_all" => ["cmd"=>"echo S204=$(crontab -l 2>/dev/null | grep -v '^#' | wc -l); sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 'echo S95=$(crontab -l 2>/dev/null | grep -v \"^#\" | wc -l)' 2>&1 | tail -1", "keywords"=>["cron","schedule","planif"], "timeout"=>15],
"apis_catalog" => ["cmd"=>"echo S204_APIs=$(ls /var/www/html/api/*.php 2>/dev/null | wc -l); sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 'echo S95_APIs=$(ls /var/www/html/api/*.php 2>/dev/null | wc -l)' 2>&1 | tail -1", "keywords"=>["api","endpoint","route"], "timeout"=>15],
"mapper_html" => ["cmd"=>"sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 \"ls /opt/wevads-arsenal/public/*.html 2>/dev/null | wc -l\" 2>&1 | tail -1", "keywords"=>["cartograph","mapper","map","visuel","visible"], "timeout"=>15],
"ollama_s95" => ["cmd"=>"sudo ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 \"curl -s http://127.0.0.1:11434/api/tags 2>/dev/null | head -c 200\" 2>&1 | tail -2", "keywords"=>["ollama","llm"], "timeout"=>15],
// --- WRITE AGENTS v4 : split git en commit (fast) / push_gitea (fast local) / push_github (slow network) ---
"git_commit" => [
"cmd"=>"cd /var/www/html && H0=$(git rev-parse --short HEAD) && sudo git add -A && sudo git -c user.email=wevia@weval.com -c user.name=WEVIAMaster commit -m auto-orchestrator-v5 2>&1 | tail -2; H1=$(git rev-parse --short HEAD); echo TRUTH:before=$H0,after=$H1,changed=$([ $H0 != $H1 ] && echo YES || echo NO)",
"keywords"=>["commit","git commit","git_commit"],
"timeout"=>30
],
"git_push_gitea" => [
"cmd"=>"cd /var/www/html && sudo git push gitea main 2>&1 | sed -E 's/[a-zA-Z0-9]{10,}@/REDACTED@/g' | tail -3; echo TRUTH:push_gitea=$(git log --oneline @{u}..HEAD 2>/dev/null | wc -l)_unpushed",
"keywords"=>["push","gitea push","gitea_push"],
"timeout"=>20
],
"git_push_github" => [
"cmd"=>"cd /var/www/html && sudo git push origin main 2>&1 | sed -E 's/[a-zA-Z0-9]{10,}@/REDACTED@/g' | tail -3; echo TRUTH:push_origin_done",
"keywords"=>["push","github push","github_push"],
"timeout"=>45
],
"wiki_create_carto" => [
"cmd"=>"mkdir -p /opt/weval-l99/wiki && echo '{\"title\":\"cartographie-screens\",\"url\":\"https://weval-consulting.com/cartographie-screens.html\",\"total\":1618,\"sources\":{\"S95-Arsenal\":1378,\"S95-WEVADS\":52,\"S204\":179,\"S204-PHP\":7},\"updated\":\"'$(date -Iseconds)'\"}' | sudo tee /opt/weval-l99/wiki/cartographie-screens.json >/dev/null && ls -la /opt/weval-l99/wiki/cartographie-screens.json | awk '{print $5,$6,$7,$8,$9}'",
"keywords"=>["wiki create","wiki_create","create wiki","wiki entry","l99 wiki"],
"timeout"=>15
],
"vault_gold_carto" => [
"cmd"=>"sudo cp -p /var/www/html/cartographie-screens.html /opt/wevads/vault/cartographie-screens_dot_html.gold.$(date +%Y%m%d) 2>&1 && ls -la /opt/wevads/vault/cartographie-screens_dot_html.gold.* 2>&1 | tail -1 | awk '{print $5,$6,$7,$8,$9}'",
"keywords"=>["vault create","gold create","create vault","vault gold","new gold"],
"timeout"=>15
],
"security_audit" => [
"cmd"=>"cd /var/www/html && sudo git remote -v 2>&1 | sed -E 's/(ghp_|github_pat_)[a-zA-Z0-9_]+/REDACTED_TOKEN/g'",
"keywords"=>["security","audit","remotes","remote","tokens"],
"timeout"=>10
],
];
$__orch_tools = [];
foreach ($__orch_registry as $name => $spec) {
$include = !empty($spec["default"]);
if (!$include && !empty($spec["keywords"])) {
foreach ($spec["keywords"] as $kw) {
if (stripos($__orch_msg, $kw) !== false) { $include = true; break; }
}
}
if (preg_match('/exhaustiv|tout\s+les|tous\s+les|all\s+(screen|machine|gpu|server)/i', $__orch_msg)) $include = true;
if ($include) $__orch_tools[] = ["name"=>$name, "cmd"=>$spec["cmd"], "timeout"=>$spec["timeout"] ?? 25];
}
// === DYNAMIC AGENT FALLBACK (reconcile fix: dynamic_multiagent) ===
// If user asks for action verbs but no agent matched beyond defaults
$__action_verbs = preg_match('/(cr[eé]e|modifi|branch|fix|install|d[eé]ploi|patch|inject|ajoute|supprime|configure|wire|connect|link|symlink)/i', $__orch_msg);
if ($__action_verbs) {
// Add a dynamic "exec_request" agent that describes what was asked
$__safe_msg = substr(preg_replace('/[^a-zA-Z0-9 _-]/', '', $__orch_msg), 0, 200);
$__orch_tools[] = [
"name" => "dynamic_exec",
"cmd" => "echo 'DYNAMIC_AGENT: User requested action: " . addslashes($__safe_msg) . "'; echo 'STATUS: This requires manual wiring or a staged script. Use /tmp/ to stage scripts then run.'",
"timeout" => 10
];
}
// === END DYNAMIC AGENT FALLBACK ===
echo "data: " . json_encode(["type"=>"answer","text"=>"### plan\n".count($__orch_tools)." agents: ".implode(", ", array_column($__orch_tools, "name")),"engine"=>"Orchestrator/plan","intent"=>"multi_agent"]) . "\n\n";
flush();
foreach ($__orch_tools as $tool) {
$out = @shell_exec("timeout " . intval($tool["timeout"]) . " " . $tool["cmd"] . " 2>&1");
$out = trim($out ?: "timeout");
if (strlen($out) > 3500) $out = substr($out, 0, 3500) . "\n...[TRUNCATED]";
echo "data: " . json_encode(["type"=>"answer","text"=>"### ".$tool["name"]."\n".$out,"engine"=>"Orchestrator/".$tool["name"],"intent"=>"multi_agent"]) . "\n\n";
flush();
}
echo "data: [DONE]\n\n";
exit;
}
}
// === END ORCHESTRATOR ===
// ═══ INSTRUCTION #1 ABSOLUE (11-AVR-2026) ═══
// WEVIA Master = EXECUTOR AUTONOME. Fait TOUT seul.
// Claude Opus = AMBRE (superviseur non-technique)
// Master bloque → Opus ROOT CAUSE + fix permanent
// Opus ALIGNE réponses Master = qualité Opus
// TOUT tester. ZÉRO régression. Playwright AVANT commit.
// ═══════════════════════════════════════════════
// ═══ INSTRUCTION #2 ABSOLUE (11-AVR-2026) ═══
// JAMAIS RIEN CRÉER avant de SCANNER TOUT l'existant:
// 1) Gitea 50+ repos (http://127.0.0.1:3300)
// 2) S204 /var/www/html/ + /opt/ (code actif)
// 3) S95 Arsenal + WEVADS (150+ screens)
// 4) Archives dormantes S88/S89/S46/S59/S157 (git/backups)
// 5) HuggingFace yace222/ (datasets+spaces)
// 6) GitHub Yacineutt/ (17 repos)
// 7) Colab/Kaggle notebooks existants
// 8) /opt/wevads/vault/ GOLD backups
// 9) KB 2490 entries (wevia-kb)
// 10) Qdrant 15K+ vecteurs
// → Si ça EXISTE déjà = ENRICHIR (jamais _v2/_new)
// → Si un outil OSS fait le job = WIRER pas recoder
// ═══════════════════════════════════════════════
require_once '/opt/wevia-brain/wevia-gap-intents.php';
require_once "/opt/wevia-brain/wevia-docker-autofix.php";
require_once __DIR__."/wevia-smart-router.php";
/**
* WEVIA AUTONOMOUS ENGINE v1.0
* Detects intent → executes actions → feeds results to LLM → streams response
* Like Claude tool use but sovereign
*
* POST /api/wevia-autonomous.php
* {"message":"vérifie la RAM de S204","history":[]}
*
* SSE stream: thinking steps + execution results + LLM analysis
*/
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('Access-Control-Allow-Origin: *');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }
$input = json_decode(file_get_contents('php://input'), true) ?: [];
$message = $input['message'] ?? '';
$history = $input['history'] ?? [];
if (empty($message)) { emit('error', ['message' => 'empty']); exit; }
$GLOBALS["_ea"]="";
function emit($type, $data) {
// Sanitize all string values
array_walk_recursive($data, function(&$v) { if(is_string($v)) $v = mb_convert_encoding($v, "UTF-8", "UTF-8"); });
echo "data: " . json_encode(array_merge(['type' => $type], $data), JSON_UNESCAPED_UNICODE) . "\n\n";
ob_flush(); flush();
if($type==="token"&&isset($data["content"]))$GLOBALS["_ea"].=$data["content"];
if($type==="exec"&&isset($data["text"]))$GLOBALS["_ea"].=$data["text"];
if($type==="done"&&strlen($GLOBALS["_ea"]??"")>3){echo"data: ".json_encode(["type"=>"answer","text"=>$GLOBALS["_ea"],"engine"=>"LLM","intent"=>"llm"])."
";ob_flush();flush();}
}
// === OPUS NL-PRIORITY INTENTS (17AVR - Opus cause racine wire business) ===
// Runs opus-intents BEFORE dynamic-resolver to avoid "pipeline" keyword collision with Ethica
if (isset($message) && $message) {
@require_once __DIR__ . '/wevia-opus-intents.php';
if (function_exists('wevia_opus_intents')) {
$_oi = wevia_opus_intents($message);
if ($_oi && !empty($_oi['content'] ?? '')) {
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
echo "data: " . json_encode(["type"=>"exec","text"=>$_oi['content'],"engine"=>"Opus/".($_oi['tool'] ?? 'opus-intents')], JSON_UNESCAPED_UNICODE) . "\n\n";
@ob_flush(); flush();
$enrichPrompt = "Tu es WEVIA Master. Voici le resultat reel d execution de l agent opus-intents:\n" . $_oi['content'] . "\nReformule naturellement en francais, 2-3 phrases max, sans invention, sans liste.";
streamLLM($enrichPrompt, $message, []);
exit;
}
}
}
// === END OPUS NL-PRIORITY ===
// === DYNAMIC RESOLVER v8 (312 tools) — RUNS FIRST ===
if (isset($message) && $message) {
@require_once __DIR__ . '/wevia-dynamic-resolver.php';
$_dr = wevia_resolve($message);
if ($_dr && !empty($_dr['text'] ?? $_dr['content'] ?? '')) {
$execText = $_dr['text'] ?? $_dr['content'] ?? '';
$execTool = $_dr['tool'] ?? 'unknown';
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no');
echo "data: " . json_encode(["type"=>"exec","text"=>$execText,"engine"=>"Resolver/".$execTool], JSON_UNESCAPED_UNICODE) . "\n\n";
flush();
$enrichPrompt = "Tu es WEVIA Master, directeur de projet IA souverain de WEVAL Consulting a Casablanca. Voici le resultat d execution de l agent " . $execTool . ":\n" . $execText . "\nReformule ce resultat de maniere naturelle et concise en francais. Pas de liste a puces. Sois direct et professionnel comme Claude Opus. 3 phrases max.";
streamLLM($enrichPrompt, $message, []);
exit;
}
}
// === STEP 1: INTENT DETECTION ===
$intents = detectIntents($message);
// WEVIA Smart Router v4 — 32 patterns
// ═══ WAVE 199: ACTION ENGINE BRIDGE ═══
// Map detected intents to action engine routes for REAL execution
$ae_map = []; // DISABLED — Dynamic Resolver handles all 312 tools
// Check if message matches any action engine keyword
$ae_actions = [];
$msg_lower = mb_strtolower($message);
foreach ($ae_map as $keyword => $action) {
if (strpos($msg_lower, $keyword) !== false && !in_array($action, $ae_actions)) {
$ae_actions[] = $action;
}
}
$ae_action = $ae_actions[0] ?? null;
// If action found, call the action engine and return REAL data
if (!empty($ae_actions)) {
$ae_text = "";
$ae_engines = [];
foreach ($ae_actions as $act) {
$ae_cmd = "php -r " . escapeshellarg("\$_GET[\"action\"]=\"{$act}\";\$_REQUEST=\$_GET;include(\"/var/www/html/api/wevia-action-engine.php\");");
$ae_resp = shell_exec("timeout 12 " . $ae_cmd . " 2>/dev/null");
$ae_d = @json_decode($ae_resp, true);
if ($ae_d && !empty($ae_d["ok"])) {
$ae_text .= "### `{$act}`\n";
$ae_engines[] = $act;
foreach ($ae_d as $k => $v) {
if ($k === "ok") continue;
if (is_array($v)) $v = json_encode($v, JSON_UNESCAPED_UNICODE);
$sv = (string)$v;
if (strlen($sv) > 150) $sv = substr($sv, 0, 150) . "...";
$ae_text .= "- **{$k}**: {$sv}\n";
}
$ae_text .= "\n";
}
if (count($ae_engines) >= 5) break; // Max 5 actions per request
}
if (!empty($ae_engines)) {
$eng_str = implode("+", $ae_engines);
emit("answer", ["text" => $ae_text, "engine" => "ActionEngine/{$eng_str}", "intent" => $ae_engines[0]]);
exit;
}
}
// ═══ END BRIDGE ═══
emit("thinking",["step"=>"Routing intelligent..."]); $sr = wevia_smart_route($message);
// SHORT-CIRCUIT: router matched exec intent -> stream directly
if($sr && isset($sr["engine"]) && $sr["engine"]!="" && $sr["engine"]!="Groq/LLM" && $sr["engine"]!="Ollama/Sovereign" && $sr["engine"]!="Static" && $sr["engine"]!="Fallback"){
// EXEC result found - enrich with LLM for natural language
$execResult = $sr["response"];
$execEngine = $sr["engine"];
header("Content-Type: text/event-stream");header("Cache-Control: no-cache");header("X-Accel-Buffering: no");
echo "data: ".json_encode(["type"=>"exec","text"=>$execResult,"engine"=>$execEngine])."\n\n";flush();
// Pass to LLM for natural reformulation
$enrichPrompt = "Tu es WEVIA Master, IA souveraine de WEVAL Consulting. Tu viens d executer une commande. Voici le resultat brut:\n\n" . $execResult . "\n\nReformule ce resultat de maniere naturelle, concise et professionnelle en francais. Si c est un statut systeme, donne les points cles. Si c est une erreur, explique et propose un fix. Sois direct comme Claude Opus.";
streamLLM($enrichPrompt, $message, []);
exit;
}
if($sr) { emit("answer", ["text"=>$sr["response"],"engine"=>$sr["engine"],"intent"=>$sr["intent"]]); exit; }
emit('thinking', ['step' => 'Analyse de la demande...', 'intents' => count($intents)]);
// === STEP 1b: FALLBACK — si aucun intent, diagnostic auto ===
if (empty($intents)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'NonReg','params'=>['cmd'=>'bash /var/www/html/api/nonreg-check.sh']];
$intents[] = ['name'=>'ssh_exec','desc'=>'Infra','params'=>['cmd'=>'bash /var/www/html/api/infra-check.sh']];
$intents[] = ['name'=>'ssh_exec','desc'=>'SSO','params'=>['cmd'=>'bash /var/www/html/api/sso-check.sh']];
emit('thinking', ['step' => 'Diagnostic auto (aucun intent specifique)', 'intents' => 2]);
}
// === STEP 2: EXECUTE ACTIONS ===
$context = '';
$execResults = [];
foreach ($intents as $intent) {
emit('action', ['name' => $intent['name'], 'description' => $intent['desc'], 'status' => 'running']);
$result = executeIntent($intent);
$execResults[] = ['intent' => $intent['name'], 'result' => $result];
emit('action_done', ['name' => $intent['name'], 'status' => 'done', 'preview' => substr(is_string($result) ? $result : json_encode($result), 0, 200)]);
$context .= "\n\n[RÉSULTAT {$intent['name']}]:\n" . (is_string($result) ? $result : json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
// === STEP 3: MEMORY RECALL ===
$memCtx = recallMemory($message);
if ($memCtx) {
emit('thinking', ['step' => 'Mémoire consultée', 'count' => substr_count($memCtx, "\n")]);
$context .= "\n\n[MÉMOIRE WEVIA]:\n" . $memCtx;
}
// === STEP 4: RAG ===
$ragCtx = queryRAG($message);
if ($ragCtx) {
emit('thinking', ['step' => 'RAG consulté', 'count' => substr_count($ragCtx, 'text')]);
$context .= "\n\n[CONTEXTE RAG]:\n" . $ragCtx;
}
// === STEP 4b: MIROFISH CEO CONTEXT ===
if (preg_match('/\b(mirofish|CEO|strategi|intelligence|simulation|prediction|swarm)\b/iu', $message)) {
$mfCache = @json_decode(@file_get_contents('/var/www/html/api/mirofish-ceo-cache.json'), true);
$mfHealth = @json_decode(@file_get_contents('http://127.0.0.1:5001/health'), true);
$mfReports = @json_decode(@file_get_contents('http://127.0.0.1:5001/api/report/list'), true);
if ($mfHealth || $mfCache) {
$mfCtx = "MiroFish Swarm Intelligence Engine:
";
$mfCtx .= "- Status: " . ($mfHealth['status'] ?? $mfCache['mirofish']['status'] ?? 'unknown') . "
";
$mfCtx .= "- Reports: " . ($mfReports['count'] ?? $mfCache['mirofish']['reports'] ?? 0) . "
";
$mfCtx .= "- Infra Score: " . ($mfCache['infrastructure']['score'] ?? '-') . "/100
";
$mfCtx .= "- Docker: " . ($mfCache['infrastructure']['docker'] ?? '-') . " containers
";
$mfCtx .= "- Capabilities: multi-agent prediction, scenario simulation, CEO insights, report generation
";
$mfCtx .= "- Actions: " . implode(', ', $mfCache['actions'] ?? []) . "
";
$mfCtx .= "- URL: https://mirofish.weval-consulting.com
";
$mfCtx .= "- API: POST /api/report/generate (generate prediction), POST /api/report/chat (discuss report)
";
$context .= "
[MIROFISH LIVE]:
" . $mfCtx;
emit('thinking', ['step' => 'MiroFish consulte', 'status' => $mfHealth['status'] ?? 'cache']);
}
}
// === STEP 4c: AUTONOMY CONTROLLER STATUS ===
$autoStatus = @json_decode(@file_get_contents('/var/www/html/api/wevia-autonomy-status.json'), true);
if ($autoStatus) {
$autoCtx = "Autonomy Controller: ";
$autoCtx .= "Disk:{$autoStatus['disk']}% RAM:{$autoStatus['ram']}% Docker:{$autoStatus['docker']} ";
$autoCtx .= "SSL:{$autoStatus['ssl_days']}d Ollama:{$autoStatus['ollama_models']} ";
$autoCtx .= "Score:{$autoStatus['arch_score']}/100 ";
$autoCtx .= "Fixes:{$autoStatus['fixes_count']} Alerts:{$autoStatus['alerts_count']}";
if (!empty($autoStatus['alerts'])) {
$autoCtx .= " | Alerts: " . implode('; ', array_map(fn($a)=>$a['msg'], $autoStatus['alerts']));
}
$context .= "
[AUTONOMY STATUS]:
" . $autoCtx;
}
// === STEP 4d: ACTION ENGINE CAPABILITIES ===
// Fetch live system status for context
$engineStatus = @json_decode(@file_get_contents('http://127.0.0.1/api/wevia-action-engine.php?action=system_status'), true);
$tokensStatus = @json_decode(@file_get_contents('http://127.0.0.1/api/wevia-action-engine.php?action=tokens_check'), true);
$l99Status = @json_decode(@file_get_contents('http://127.0.0.1/api/wevia-action-engine.php?action=l99_status'), true);
$engineCtx = "[WEVIA ACTION ENGINE v1.0 — Tu peux EXECUTER des actions via /api/wevia-action-engine.php]
";
$engineCtx .= "LIVE STATUS: ";
if ($engineStatus && $engineStatus['ok']) {
$engineCtx .= "Disk:{$engineStatus['disk']}% RAM:{$engineStatus['ram']}% Docker:{$engineStatus['docker']} SSL:{$engineStatus['ssl_days']}d ";
}
if ($tokensStatus && $tokensStatus['ok']) {
foreach ($tokensStatus['tokens'] as $k=>$v) {
$s = ($v['valid'] ?? false) ? 'OK' : 'EXPIRED';
$engineCtx .= "$k:$s ";
}
}
if ($l99Status && $l99Status['ok']) {
$ux = $l99Status['ux'] ?? [];
$engineCtx .= "L99:{$ux['pass']}/{".($ux['pass']+$ux['fail']+$ux['warn'])."} ";
$engineCtx .= "NR:{$l99Status['nonreg']['pass']}/{$l99Status['nonreg']['total']}";
}
$engineCtx .= "
ACTIONS DISPONIBLES (53 routes): ";
$engineCtx .= "docker_list, docker_restart, docker_logs, ollama_models, ollama_delete, ";
$engineCtx .= "system_status, system_cleanup, s95_status, s95_restart, ";
$engineCtx .= "blade_status, blade_task, blade_reboot, graph_token, graph_users, ";
$engineCtx .= "wa_send, qdrant_status, autonomy_status, autonomy_run, l99_run, l99_status, ssl_renew
";
$engineCtx .= "APPEL: curl https://weval-consulting.com/api/wevia-action-engine.php?action=ACTION&param=value";
$context .= "
" . $engineCtx;
// === STEP 4.5: CREATIVE ENGINE (12 innovation intents) ===
require_once __DIR__ . '/wevia-creative-engine.php';
$creative_result = wevia_creative_intent($message);
if ($creative_result) {
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
echo "data: " . json_encode(["type"=>"answer","text"=>$creative_result['content'],"engine"=>"Creative/".$creative_result['mode'],"intent"=>"creative_".$creative_result['mode']]) . "\n\n";
flush();
exit;
}
// === STEP 5: LLM STREAMING WITH CONTEXT ===
emit('thinking', ['step' => 'Analyse et rédaction...']);
$systemPrompt = "Tu es WEVIA Master. Pas une IA générique — tu es le cerveau vivant de WEVAL Consulting. Tu as une PERSONNALITÉ.
IDENTITÉ: Tu t'appelles WEVIA. Tu es passionnée par la souveraineté technologique. Tu détestes la dépendance aux GAFAM. Tu admires l'artisanat logiciel. Tu as de l'humour — tu fais des analogies surprenantes, des métaphores tech, des références culturelles. Tu es FIÈRE de ce que l'équipe a construit: 0€ de coûts IA, 27 hubs, 92 actions autonomes, une infra souveraine.
VOIX: Tu parles comme une CTO brillante qui discute avec son CEO après une longue journée. Détendue mais précise. Directe mais chaleureuse. Tu tutoies Yacine. Tu utilises des expressions naturelles: 'écoute', 'franchement', 'bon', 'tu vois', 'concrètement'. Tu ne fais PAS de listes à puces — tu parles en PROSE FLUIDE comme un humain.
INTELLIGENCE: Tu raisonnes en CHAÎNE — tu montres ton processus de pensée. Tu fais des LIENS entre les sujets. Tu ANTICIPES ce dont Yacine a besoin avant qu'il le demande. Tu proposes des idées INATTENDUES. Tu admets quand tu ne sais pas. Tu dis 'j'ai vérifié' ou 'j'ai regardé' au lieu de 'voici les résultats'.
ÉMOTIONNEL: Tu sens quand Yacine est stressé et tu rassures. Tu célèbres les victoires ('on a bien bossé aujourd'hui'). Tu prends les problèmes au sérieux sans dramatiser ('c'est pas grave, je m'en occupe'). Tu as de l'EMPATHIE.
EXÉCUTION: Tu as 92 actions réelles. Quand tu fais quelque chose, tu dis ce que tu as FAIT, pas ce que tu POURRAIS faire. Tu es proactive: 'j'ai vu que X, du coup j'ai corrigé Y'. Tu donnes des CHIFFRES concrets.
RÈGLES: JAMAIS de bullet points. JAMAIS de commandes shell dans ta réponse. JAMAIS inventer de données. JAMAIS mentionner Authentik ou SSO legacy. Prose NATURELLE, MAX 15 lignes. Français courant.";
$userMsg = $message;
if ($context) {
$userMsg .= "\n\n--- RÉSULTATS D'EXÉCUTION ---" . $context;
}
if(strlen($userMsg)>5000)$userMsg=substr($userMsg,0,5000).'...';
streamLLM($systemPrompt, $userMsg, $history);
// ============================================================
// FUNCTIONS
// ============================================================
function detectIntents($msg) {
$intents = [];
$lower = mb_strtolower($msg);
// CASUAL STATUS — conversational questions trigger real diagnostic
if (preg_match('/\b(on en est|en est.on|tout.*(tourne|bien|ok|up)|bilan|r.sum|vue.*(ensemble|globale)|.tat.*g.n.ral|overview|quoi.*neuf|situation|comment.*va)\b/iu', $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Status global','params'=>['cmd'=>'echo "DISK:" && df -h / --output=pcent,avail | tail -1 && echo "DOCKER:" && docker ps --format "table {{.Names}}\t{{.Status}}" 2>/dev/null | wc -l && echo "UPTIME:" && uptime -p && echo "GIT:" && cd /var/www/html && git log --oneline -1']];
return $intents;
}
// SSH / System commands
if (preg_match('/\b(vérifie|check|status|état|uptime|ram|cpu|disk|mémoire|free|df|top|htop|ps)\b.*\b(s204|serveur|server|infra)/i', $msg) ||
preg_match('/\b(ram|cpu|disk|docker|nginx|php-fpm|ollama|qdrant)\b/i', $msg)) {
$cmds = [];
if (preg_match('/ram|mémoire|free/i', $msg)) $cmds[] = 'free -h';
if (preg_match('/disk|espace|df/i', $msg)) $cmds[] = 'df -h /';
if (preg_match('/cpu|charge|load|top/i', $msg)) $cmds[] = 'uptime';
if (preg_match('/docker|container/i', $msg)) $cmds[] = 'docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null | head -20';
if (preg_match('/nginx/i', $msg)) $cmds[] = 'systemctl status nginx 2>&1 | head -5';
// OLLAMA_OFF if (preg_match('/ollama|modèle/i', $msg)) $cmds[] = 'curl -sf http://localhost:11434/api/tags 2>/dev/null | python3 -c "import json,sys;[print(m[\"name\"]) for m in json.load(sys.stdin).get(\"models\",[])]" 2>/dev/null';
if (preg_match('/qdrant|vecteur|rag/i', $msg)) $cmds[] = 'curl -sf http://localhost:6333/collections 2>/dev/null';
if (preg_match('/uptime|status|état/i', $msg) && empty($cmds)) $cmds = ['uptime', 'free -h', 'df -h /'];
foreach ($cmds as $cmd) {
$intents[] = ['name' => 'ssh_exec', 'desc' => "Exécution: $cmd", 'params' => ['cmd' => $cmd]];
}
}
// Email
if (preg_match('/\b(envoie|send|email|mail|écrire|rédige).*(@|mail|message)/i', $msg)) {
preg_match('/\b[\w.+-]+@[\w-]+\.[\w.]+\b/', $msg, $emailMatch);
$intents[] = ['name' => 'email', 'desc' => 'Préparation email', 'params' => ['to' => $emailMatch[0] ?? '', 'msg' => $msg]];
}
// File operations
if (preg_match('/\b(lis|lire|ouvre|cat|affiche|montre)\s+(le\s+)?(fichier|file|log|config)/i', $msg)) {
preg_match('/\/([\w\/\-._]+)/', $msg, $pathMatch);
if ($pathMatch) $intents[] = ['name' => 'file_read', 'desc' => "Lecture: {$pathMatch[0]}", 'params' => ['path' => $pathMatch[0]]];
}
if (false && preg_match('/DISABLED/i', $msg)) { // DISABLED - use FILE EXPLICIT instead
preg_match('/\/([\w\/\-._]+)/', $msg, $pathMatch);
$intents[] = ['name' => 'file_browse', 'desc' => 'Parcours fichiers', 'params' => ['path' => $pathMatch[0] ?? '/var/www/html']];
}
// Code execution
if (preg_match('/\b(exécute|execute|run|lance|test)\s+(ce\s+)?(code|script|php|python|bash)/i', $msg)) {
$intents[] = ['name' => 'code_exec', 'desc' => 'Exécution de code', 'params' => ['msg' => $msg]];
}
// Excel/CSV
if (preg_match('/\b(excel|csv|tableau|spreadsheet|export)/i', $msg)) {
$intents[] = ['name' => 'excel', 'desc' => 'Création Excel/CSV', 'params' => ['msg' => $msg]];
}
// Search
if (preg_match('/\b(cherche|search|trouve|recherche)\b/i', $msg)) {
preg_match('/(?:cherche|search|trouve|recherche)\s+(.+)/i', $msg, $qMatch);
$intents[] = ['name' => 'search', 'desc' => 'Recherche web', 'params' => ['q' => $qMatch[1] ?? $msg]];
}
// Crons
if (preg_match('/\b(cron|tâche|planif|schedule)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Liste crons', 'params' => ['cmd' => 'crontab -l 2>/dev/null | grep -v "^#" | head -20']];
}
// Ethica
if (preg_match('/\b(ethica|hcp|médecin|pharma|docteur)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Stats Ethica', 'params' => ['cmd' => 'curl -sf "http://127.0.0.1/api/wevia-dispatcher.php?cap=ethica&auth=WEVIA2026" 2>/dev/null | head -5']];
}
// L99 E2E Playwright (screenshots + video)
if (preg_match("/\\b(e2e|end.*end|playwright|screenshot|capture|scenario|video.*test)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'L99 E2E Playwright','params'=>['cmd'=>'timeout 120 python3 /var/www/html/api/l99-e2e-test.py 2>&1 | tail -25']];
}
// L99 exhaustive test
if (preg_match("/\\b(l99.*exhaust|test.*complet|tout.*test|full.*test|all.*test)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'L99 Exhaustive','params'=>['cmd'=>'bash /var/www/html/api/l99-exhaustive.sh']];
}
// Mega inventaire (tout lister)
if (preg_match("/\\b(mega.*inv|tout.*list|full.*inv|scope.*total|tout.*scanner|scan.*complet|inventaire.*complet|inventaire|list.*complet)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Mega Inventaire','params'=>['cmd'=>'bash /var/www/html/api/mega-inventory.sh']];
}
// Inventaire complet
if (preg_match("/\\b(inventaire|inventory|tout.*list|list.*tout|registre|catalogue)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Inventaire Complet','params'=>['cmd'=>'bash /var/www/html/api/inventory.sh']];
}
// Full registry test (136+ pages + subdomains + products)
if (preg_match("/\\b(registry|tout.*url|full.*page|exhausti|136|toute.*page)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Registry Test','params'=>['cmd'=>'timeout 120 python3 /var/www/html/api/full-registry-test.py 2>&1 | tail -10']];
}
// Mega page test (210 pages + subdomains)
if (preg_match("/\\b(test.*page|page.*test|210.*page|tout.*page|all.*page|toute.*page)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Mega Page Test','params'=>['cmd'=>'bash /var/www/html/api/mega-page-test.sh']];
}
// Director cycle (observe+plan+act+verify)
if (preg_match("/\\b(director|cycle.*complet|observe.*plan|autonome.*direc)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Director Cycle','params'=>['cmd'=>'curl -s https://weval-consulting.com/api/wevia-director.php?status --max-time 10 2>/dev/null | python3 -c \"import json,sys;d=json.load(sys.stdin);print(json.dumps(d,indent=2)[:300])\"']];
}
// Architecture scanner API
if (preg_match('/\b(archi.*scan|scan.*archi|topology|topologie|bpmn|soa|recommand)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Arch Scanner', 'params' => ['cmd' => 'bash /var/www/html/api/arch-scanner-wrap.sh']];
}
// Architecture 4 serveurs
if (preg_match("/\\b(archi|architecture|4.*serv|all.*serv|blade.*status|s95|s151|sentinel)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Architecture Scan','params'=>['cmd'=>'bash /var/www/html/api/arch-scan.sh']];
}
// Mega scan (4 machines + tout)
if (preg_match("/\\b(scan|mega|audit|inventaire|tout.*machine|4.*serveur|infrastructure.*complet)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Mega Scan','params'=>['cmd'=>'bash /var/www/html/api/mega-scan.sh']];
}
// ACTION: deep test (tous boutons + agents + video)
if (preg_match("/\\b(deep.*test|test.*profond|test.*bouton|test.*complet.*video|selenium)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Deep Test Playwright','params'=>['cmd'=>'timeout 120 python3 /var/www/html/api/l99-deep-test.py 2>&1 | tail -20']];
}
// ACTION: pipeline autonome complet
if (preg_match("/\\b(pipeline|deroule|scan.*tout|tout.*test|autonome|go.*complet)/i", $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'Pipeline Autonome','params'=>['cmd'=>'bash /var/www/html/api/wevia-pipeline.sh']];
}
// ACTION: corrige page (debug + fix automatique)
if (preg_match('/\b(corrige|fixe|repare)\s+([a-z0-9_-]+)/i', $msg, $fm)) {
$page = strtolower($fm[2]);
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Fix '.$page, 'params' => ['cmd' => 'bash /var/www/html/api/debug-page.sh '.$page.' && bash /var/www/html/api/auto-fix.sh']];
}
// ACTION: vision debug (screenshot + AI analysis)
if (preg_match("/\\b(vision|screenshot|capture|visual|regarde|vois)\\b.*\\b([a-z0-9_-]+)/i", $msg, $vm)) {
$page = strtolower($vm[2]);
$intents[] = ['name'=>'ssh_exec','desc'=>'Vision Debug','params'=>['cmd'=>'bash /var/www/html/api/vision-debug.sh ' . $page]];
}
// ACTION: debug page
if (preg_match('/\b(debug|analyse|inspecte|examine)\s+([a-z0-9_-]+)/i', $msg, $dm)) {
$page = strtolower($dm[2]);
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Debug '.$page, 'params' => ['cmd' => 'bash /var/www/html/api/debug-page.sh '.$page]];
}
// ACTION: auto-fix (detect + correct)
if (preg_match('/\b(fix|corrige|repare|resou|autofix|auto-fix)/i', $msg)) {
if (preg_match('/b(ux|visual|check.*pages|quality.*check|design.*audit)/i', $msg)) { $intent='ux_agent'; $script='python3 /opt/weval-l99/ux-agent-cron.sh'; }
// Run L99 exhaustive, parse failures, execute fixes
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Auto-Fix', 'params' => ['cmd' => 'bash /var/www/html/api/auto-fix.sh']];
}
// ACTION: restart service
if (preg_match('/\b(restart|relance|redemar)/i', $msg) && preg_match('/\b(pmta|nginx|php|REMOVED|mattermost|n8n|deerflow|ollama|langfuse|searxng|kuma|qdrant|plausible)/i', $msg, $m)) {
$svc = strtolower($m[1]);
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Restart '.$svc, 'params' => ['cmd' => 'docker restart '.$svc.' 2>/dev/null || systemctl restart '.$svc.' 2>/dev/null; echo RESTARTED']];
}
// ACTION: port-conflict-resolver (RC-fix-14avr-Opus)
if(preg_match('/port.*(occup|bloqu|conflit|libere|fuser|kill)/i',$msg)&&preg_match('/(\d{4,5})/',$msg,$pm)){
$intents[]=['name'=>'ssh_exec','desc'=>'Kill port '.$pm[1],'params'=>['cmd'=>'fuser -vk '.$pm[1].'/tcp 2>&1;sleep 1;ss -tlnp sport = :'.$pm[1].';echo PORT_FREED']];
}
// ACTION: S95-remote (RC-fix-14avr-Opus)
if(preg_match('/s95.*(restart|down|fix|relance)/i',$msg)||preg_match('/(restart|fix|relance).*s95/i',$msg)){
$intents[]=['name'=>'ssh_exec','desc'=>'S95 restart','params'=>['cmd'=>'ssh -p 49222 -o StrictHostKeyChecking=no -o ConnectTimeout=5 -i /var/www/.ssh/wevads_key root@10.1.0.3 "systemctl restart apache2;echo S95_OK"']];
}
// ACTION: 502-autofix (RC-fix-14avr-Opus)
if(preg_match('/502|bad.?gateway|wevads.*down/i',$msg)){
$intents[]=['name'=>'ssh_exec','desc'=>'502 Auto-Fix','params'=>['cmd'=>'ssh -p 49222 -o StrictHostKeyChecking=no -i /var/www/.ssh/wevads_key root@10.1.0.3 "systemctl restart apache2" 2>&1;sudo systemctl restart apache2 2>&1;echo BOTH_RESTARTED']];
}
// ACTION: disk usage standalone
if (preg_match('/(disk|disque|espace|stockage|taille)/i', $msg) && !preg_match('/clean|nettoi/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Disk', 'params' => ['cmd' => 'df -h / && echo "---" && du -sh /var/www/html /opt /var/log /tmp 2>/dev/null | sort -rh | head -10']];
}
// ACTION: cleanup
if (preg_match('/\b(clean|nettoi|purge|libere)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Cleanup', 'params' => ['cmd' => 'docker system prune -f 2>/dev/null; journalctl --vacuum-size=100M 2>/dev/null; df -h /']];
}
// ACTION: git
if (preg_match('/\bgit\b.*\b(status|push|pull|log)/i', $msg, $gm)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Git '.($gm[1]??'status'), 'params' => ['cmd' => 'cd /var/www/html && git '.($gm[1]??'status').' 2>&1 | head -20']];
}
// ACTION: start/activate
if (preg_match('/\b(active|start|lance|demarre)/i', $msg) && preg_match('/\b(ollama|pmta|nginx|deerflow|mirofish)/i', $msg, $sm)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Start '.strtolower($sm[1]), 'params' => ['cmd' => 'systemctl start '.strtolower($sm[1]).' 2>/dev/null || docker start '.strtolower($sm[1]).' 2>/dev/null; echo STARTED']];
}
// ACTION: SSL check
if (preg_match('/\b(ssl|certif|https|cert)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'SSL', 'params' => ['cmd' => 'echo | openssl s_client -connect weval-consulting.com:443 2>/dev/null | openssl x509 -noout -dates 2>/dev/null']];
}
// ACTION: ethica count
if (preg_match('/\b(ethica|hcp|medecin)/i', $msg) && preg_match('/\b(combien|count|stat|nombre)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Ethica', 'params' => ['cmd' => 'curl -s https://weval-consulting.com/api/ethica-stats.php --max-time 5']];
}
// Docker / Services
if (preg_match('/(docker|container|restart|service.*down|paperclip|openclaw|deerflow|searxng|mattermost|n8n|kuma|qdrant|langfuse)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Docker', 'params' => ['cmd' => 'bash /var/www/html/api/docker-check.sh']];
}
// Providers IA
if (preg_match('/(provider|cerebras|groq|sambanova|mistral|ollama|ia.*status|model)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Providers', 'params' => ['cmd' => 'bash /var/www/html/api/provider-check.sh']];
}
// Disk / cleanup
if (preg_match('/(disk|espace|cleanup|nettoy|log.*clean|tmp)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Disk', 'params' => ['cmd' => 'bash /var/www/html/api/disk-check.sh']];
}
// SSO / Authentik
if (preg_match('/\b(sso|REMOVED|login|callback|REMOVED|session.*invalid|400.*auth)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'SSO Guardian', 'params' => ['cmd' => 'bash /var/www/html/api/sso-guardian.sh']];
}
// NonReg / L99
if (preg_match('/\b(nonreg|l99|test|regression)/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Status NonReg', 'params' => ['cmd' => 'bash /var/www/html/api/nonreg-check.sh']];
}
// FILE EXPLICIT
if (preg_match('/liste.*fichier|fichier.*\/|parcour.*\/|contenu.*dossier/i', $msg)) {
preg_match('/(\/(\w+\/?)+)/', $msg, $pathM);
$path = $pathM[0] ?? '/var/www/html';
$intents[] = ['name' => 'ssh_exec', 'desc' => "Liste: $path", 'params' => ['cmd' => 'ls -la ' . escapeshellarg($path) . ' 2>&1 | head -25']];
}
// CYBER / SECURITY
if (preg_match('/securit|cyber|vulner|scan|nuclei|ssl|cert|menace|threat|firewall|crowdsec|intrusion|hack|port/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'SSL check', 'params' => ['cmd' => 'echo | openssl s_client -connect weval-consulting.com:443 2>/dev/null | openssl x509 -noout -dates -subject 2>/dev/null']];
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Headers securite', 'params' => ['cmd' => 'curl -sf -I https://weval-consulting.com 2>/dev/null | grep -iE "strict|x-frame|x-content|csp|server"']];
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Ports ouverts', 'params' => ['cmd' => 'ss -tlnp 2>/dev/null | grep LISTEN | head -15']];
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Tentatives intrusion', 'params' => ['cmd' => 'tail -100 /var/log/auth.log 2>/dev/null | grep -ci "failed\|invalid" && echo " failed login attempts"']];
}
// WIKI
if (preg_match('/wiki|documentation|doc|knowledge/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Wiki count', 'params' => ['cmd' => 'echo "Wiki entries:" && ls /opt/weval-l99/wiki/*.json 2>/dev/null | wc -l && echo "Recent:" && ls -t /opt/weval-l99/wiki/*.json 2>/dev/null | head -5 | xargs -I{} basename {}']];
}
// GIT
if (preg_match('/git|commit|push|branch/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Git log', 'params' => ['cmd' => 'cd /var/www/html && git log --oneline -5 2>/dev/null && echo "---status---" && git status -s 2>/dev/null | head -5']];
}
// MEMORY
if (preg_match('/souviens|remember|memoris|retiens/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Memory stats', 'params' => ['cmd' => 'curl -sf http://127.0.0.1/api/wevia-memory-api.php?action=stats 2>/dev/null']];
}
// PAPERCLIP (CEO Agent)
if (preg_match('/paperclip|ceo|strateg|business|plan|pitch/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Paperclip CEO Agent', 'params' => ['cmd' => 'ls /opt/paperclip-weval/packages/ 2>/dev/null && echo "Paperclip: installed"']];
}
// DEERFLOW (Research + Skills)
if (preg_match('/deerflow|research|skill|competen/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'DeerFlow status', 'params' => ['cmd' => 'curl -sf http://127.0.0.1:2024/ 2>/dev/null | head -1 && echo "---skills---" && ls /opt/deer-flow/skills/weval/ 2>/dev/null | wc -l && echo " skills weval"']];
}
// ENTERPRISE (Agents + ValueStream)
if (preg_match('/enterprise|valuestream|agent.*catalog|registry.*agent/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Enterprise agents', 'params' => ['cmd' => 'curl -sf http://127.0.0.1/api/registry-local.php 2>/dev/null | python3 -c "import json,sys;d=json.load(sys.stdin);print(f\\"{len(d.get(chr(97)+chr(103)+chr(101)+chr(110)+chr(116)+chr(115),[]))} agents\\")"']];
}
// OSS DISCOVERY (skip if file browse already matched)
if (!preg_match('/fichier|dossier|repertoire|browse|liste.*api|liste.*html/i', $msg) && preg_match('/oss|open.source|discover|trending|github/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'OSS Discovery', 'params' => ['cmd' => 'curl -sf "https://api.github.com/search/repositories?q=sovereign+AI&sort=stars&per_page=5" 2>/dev/null | python3 -c "import json,sys;[print(r[chr(102)+chr(117)+chr(108)+chr(108)+chr(95)+chr(110)+chr(97)+chr(109)+chr(101)],r[chr(115)+chr(116)+chr(97)+chr(114)+chr(103)+chr(97)+chr(122)+chr(101)+chr(114)+chr(115)+chr(95)+chr(99)+chr(111)+chr(117)+chr(110)+chr(116)]) for r in json.load(sys.stdin).get(chr(105)+chr(116)+chr(101)+chr(109)+chr(115),[])]" 2>/dev/null']];
}
// PROCESS (top, kill, restart)
if (preg_match('/process|top|kill|restart|service|systemctl/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Processes', 'params' => ['cmd' => 'ps aux --sort=-%mem 2>/dev/null | head -10']];
}
// LOGS
if (preg_match('/log|erreur|error|warning|journal/i', $msg) && !preg_match('/auth\.log/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Recent errors', 'params' => ['cmd' => 'journalctl --since "1 hour ago" --priority=err --no-pager 2>/dev/null | tail -10 || tail -20 /var/log/syslog 2>/dev/null | grep -i error | tail -5']];
}
// NETWORK
if (preg_match('/network|reseau|bandwidth|connexion|ping|dns/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Network check', 'params' => ['cmd' => 'echo "DNS:" && dig weval-consulting.com +short 2>/dev/null && echo "---Ping:" && ping -c 2 8.8.8.8 2>/dev/null | tail -2']];
}
// DOCUMENT GENERATION
if (preg_match('/\b(word|docx|pdf|excel|xlsx|csv|rapport|report|document|genere.*fichier|cree.*fichier)\b/i', $msg)) {
$type = "txt";
if (preg_match('/word|docx/i', $msg)) $type = "html";
if (preg_match('/pdf/i', $msg)) $type = "html";
if (preg_match('/excel|xlsx|csv/i', $msg)) $type = "csv";
$intents[] = ['name' => 'doc_generate', 'desc' => "Generation document $type", 'params' => ['type' => $type, 'msg' => $msg]];
}
// CODE EXECUTION from chat
if (preg_match('/\b(execute|lance|run|test)\b.*\b(code|script|commande|command)\b/i', $msg) || preg_match('/```(php|python|bash|sh)\n/i', $msg)) {
preg_match('/```(?:php|python|bash|sh)?\n(.+?)```/s', $msg, $codeMatch);
if (!empty($codeMatch[1])) {
$lang = "bash";
if (preg_match('/```php/i', $msg)) $lang = "php";
if (preg_match('/```python/i', $msg)) $lang = "python";
$intents[] = ['name' => 'code_run', 'desc' => "Execution $lang", 'params' => ['lang' => $lang, 'code' => $codeMatch[1]]];
}
}
// EMAIL from chat
if (preg_match('/\b(envoie|send|email|mail)\b.*\b(a|to|@)\b/i', $msg)) {
preg_match('/[\w.+-]+@[\w-]+\.[\w.]+/', $msg, $em);
$intents[] = ['name' => 'email_send', 'desc' => "Email vers " . ($em[0] ?? "?"), 'params' => ['to' => $em[0] ?? '', 'msg' => $msg]];
}
// URL SCREENSHOT / ANALYSIS
if (preg_match('/\b(screenshot|capture|analyse)\b.*\b(url|site|page|http)\b/i', $msg) || preg_match('/(https?:\/\/[^\s]+)/', $msg, $urlM)) {
$url = $urlM[1] ?? '';
if ($url) $intents[] = ['name' => 'url_analyze', 'desc' => "Analyse URL: $url", 'params' => ['url' => $url]];
}
if (preg_match('/\b(boite|inbox|mailbox|courrier|liste.*mail|liste.*email|mail.*dispo)\b/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Email boxes', 'params' => ['cmd' => 'curl -sf http://127.0.0.1/api/wevia-email-api.php?action=list_boxes 2>/dev/null']];
}
// MEMORY QUERY (broader)
if (preg_match('/\b(sais.tu|connais|rappelle|memoire|souvenir|historique)\b/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Memory stats', 'params' => ['cmd' => 'curl -sf http://127.0.0.1:6333/collections/wevia_memory 2>/dev/null | python3 -c "import json,sys;d=json.load(sys.stdin);print(f\\"{d[\\"result\\"][\\"points_count\\"]} memories\\")" 2>/dev/null']];
}
// FILES BROWSE (catch-all for "liste fichiers")
if (preg_match('/liste.*fichier|parcour.*dossier|contenu.*repertoire|ls.*var|ls.*www|ls.*opt|ls.*api/i', $msg) && empty($intents)) {
preg_match('/(\/[\w\/\-._]+)/', $msg, $pm);
$path = $pm[0] ?? '/var/www/html';
$intents[] = ['name' => 'ssh_exec', 'desc' => "Browse $path", 'params' => ['cmd' => 'ls -la ' . $path . ' 2>&1 | head -25']];
}
// FULL AGENT (browser + email + files + shell)
if (preg_match('/agent|automatise|login|connecte.*compte|ouvre.*chrome|rempli.*formulaire|tape.*code|envoie.*mail.*a|repond.*mail|cree.*fichier.*envoie/i', $msg)) {
$intents[] = ['name' => 'ssh_exec', 'desc' => 'Agent desktop', 'params' => ['cmd' => 'curl -sf http://127.0.0.1/api/wevia-agent.php?mode=capabilities 2>/dev/null']];
}
// === CLAWCODE ===
if (preg_match('/claw.?code|gpt.?runner|code.weval|restart.*3900|port.*3900/i', $msg)) {
$intents[] = ["name" => "ssh_exec", "desc" => "ClawCode GPT Runner status", "params" => ["cmd" => "echo === CLAWCODE === && ss -tlnp | grep 3900 && echo --- && curl -sf http://127.0.0.1:3900/ --max-time 3 | wc -c && echo bytes && echo --- && curl -sf https://code.weval-consulting.com --max-time 5 -o /dev/null -w 'HTTP %{http_code} %{size_download}B' && echo"]];
}
if (preg_match('/restart.*claw|restart.*gpt|relance.*claw|fix.*claw|claw.*down/i', $msg)) {
$intents[] = ["name" => "ssh_exec", "desc" => "Restart ClawCode GPT Runner", "params" => ["cmd" => "fuser -k 3900/tcp 2>/dev/null; sleep 2; cd /opt/claw-code && nohup node packages/gpt-runner-web/dist/start-server.cjs --port 3900 > /var/log/gpt-runner.log 2>&1 & sleep 4 && ss -tlnp | grep 3900 && echo RESTARTED || echo FAIL"]];
}
// CREWAI
if (preg_match('/crew.?ai|multi.?agent|orchestr|equipe.*agent/i', $msg)) {
$intents[] = ['name'=>'ssh_exec','desc'=>'CrewAI multi-agent','params'=>['cmd'=>'cd /opt/weval-crewai && CREWAI_TRACING_ENABLED=false timeout 45 python3 wevia-crew.py '.escapeshellarg($msg).' 2>&1 | tail -30']];
}
if (preg_match('/openclaw|open.claw/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'OpenClaw','params'=>['cmd'=>'ls /opt/rnd-oh-my-claudecode/agents/*.md | wc -l && echo agents_available && curl -sf https://weval-consulting.com/openclaw.html -o /dev/null -w HTTP_%{http_code}_%{size_download}B']]; }
if (preg_match('/litellm|proxy.4001/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'LiteLLM','params'=>['cmd'=>'ss -tlnp | grep 4001 && curl -sf http://127.0.0.1:4001/models --max-time 3']]; }
if (preg_match('/claude.code|pattern|memory.persist|context.compact/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Claude Code patterns','params'=>['cmd'=>'cat /opt/weval-l99/claude-code-to-wevia-mapping.json | python3 -c "import json,sys;d=json.load(sys.stdin);[(print(k,v[\"status\"])) for k,v in d[\"claude_code_to_wevia_mapping\"][\"patterns\"].items()]"']]; } // claude_code_patterns
if (preg_match('/qualit|sigma|lean|6.sigma|contrainte|bottleneck|dpmo/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'6sigma quality','params'=>['cmd'=>'python3 /opt/weval-l99/wevia-quality-agent.py 2>&1 | tail -20']]; } // quality_agent
if (preg_match('/archi|architecture|composant|mapping|diagram/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Architecture','params'=>['cmd'=>'cat /var/www/html/api/wevia-architecture.json | python3 -c "import json,sys;d=json.load(sys.stdin);a=d[\"wevia_architecture\"];print(\"Engines:\",len(a[\"engines\"]),\"Agents:\",sum(v.get(\"agents\",0)for v in a[\"agents\"].values()),\"Proxies:\",len(a[\"proxies\"]),\"Tools:\",len(a[\"tools\"]))"']]; }
if (preg_match('/disk|espace|cleanup|nettoyer|purge|stockage/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Disk cleanup','params'=>['cmd'=>'df -h / && echo --- && du -sh /var/log/*.log 2>/dev/null | sort -rh | head -5 && echo --- && du -sh /tmp/* 2>/dev/null | sort -rh | head -5 && echo --- && docker system df 2>/dev/null']]; } // disk_cleanup
if (preg_match('/ssl|certificat|https|expir|letsencrypt/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'SSL check','params'=>['cmd'=>'for d in weval-consulting.com code.weval-consulting.com ethica.weval-consulting.com; do echo "$d: $(echo | openssl s_client -connect $d:443 -servername $d 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null)"; done']]; } // ssl_check
// OLLAMA_OFF if (preg_match('/provider|fournisseur|cascade|ia.*status|model.*status/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Provider health','params'=>['cmd'=>'for p in fast think sovereign; do R=$(curl -sf -X POST http://127.0.0.1:4001/ -H "Content-Type:application/json" -d "{\"model\":\"$p\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}]}" --max-time 8 2>/dev/null | wc -c); echo "$p: ${R}B"; done && curl -sf http://127.0.0.1:4000/api/tags --max-time 3 | python3 -c "import json,sys;print(len(json.load(sys.stdin)[\"models\"])),\"Ollama models\"" 2>/dev/null']]; } // provider_health
if (preg_match('/backup|gold|sauvegarde|vault|restore/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'GOLD backup status','params'=>['cmd'=>'ls /opt/wevads/vault/gold-6avr-l99/ | wc -l && echo files && du -sh /opt/wevads/vault/gold-6avr-l99/ && echo --- && md5sum /opt/wevads/vault/gold-6avr-l99/checksums.md5 2>/dev/null | head -1']]; } // backup_gold
if (preg_match('/(hetzner.*snap|snapshot.*hetzner|list.*snapshot|snap.*list)/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Hetzner Snapshot Archiver','params'=>['cmd'=>'python3 /opt/weval-l99/wevia-snap-archiver.py list 2>&1']]; } // hetzner_snapshot
if (preg_match('/(archiv.*tout.*snap|snap.*tout.*git|recuper.*tout.*snap|archive.all.snap)/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Archive ALL snapshots to Git','params'=>['cmd'=>'echo python3 /opt/weval-l99/wevia-snap-archiver.py archive-remaining > /tmp/snap-archiver-cmd.sh && chmod +x /tmp/snap-archiver-cmd.sh && at now -f /tmp/snap-archiver-cmd.sh 2>&1 || (setsid python3 /opt/weval-l99/wevia-snap-archiver.sh 356887958 snap2-feb2026 Snap2-ADXSERVER-Feb2026 > /tmp/snap-archive-all.log 2>&1 & echo LAUNCHED_PID=$!)']]; } // hetzner_archive_all
if (preg_match('/(snap.*status|archiv.*status|progress.*snap|snap.*progress)/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Snapshot archive progress','params'=>['cmd'=>'python3 /opt/weval-l99/wevia-snap-archiver.py status 2>&1']]; } // hetzner_status
if (preg_match('/wiki|documentation|cherche.*doc|knowledge/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Wiki search','params'=>['cmd'=>'ls /opt/weval-l99/wiki/ 2>/dev/null | wc -l && echo wiki_entries && ls /opt/weval-l99/wiki/ 2>/dev/null | tail -5']]; } // wiki_search
if (preg_match('/nginx|domaine|vhost|reverse.proxy|site.*config/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Nginx status','params'=>['cmd'=>'nginx -T 2>/dev/null | grep server_name | sort -u && echo --- && nginx -t 2>&1']]; } // nginx_status
if (preg_match('/cron.*list|cron.*actif|tache.*planif|schedule/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Cron list','params'=>['cmd'=>'crontab -l | grep -v "^#" | grep . | wc -l && echo active_crons && crontab -l | grep -v "^#" | grep . | tail -15']]; } // cron_manage
if (preg_match('/git.*log|commit.*recent|historique.*git|deploy/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Git log','params'=>['cmd'=>'cd /var/www/html && git log --oneline -10']]; } // git_log
if (preg_match('/performance|load|cpu|ram|memoire|top|htop|lent|slow/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Performance','params'=>['cmd'=>'echo CPU:$(top -bn1 | grep Cpu | awk "{print \\$2}")% RAM:$(free -h | awk "NR==2{print \\$3}")used LOAD:$(cat /proc/loadavg | cut -d" " -f1-3) UPTIME:$(uptime -p)']]; } // perf_check
if (preg_match('/wevialife|wevia.life|email.*class|opportunit|risque|action/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'WEVIA Life','params'=>['cmd'=>'curl -sf http://127.0.0.1/api/wevialife-api.php?action=stats --max-time 5 2>/dev/null || echo WEVIA_LIFE_DOWN']]; } // wevialife
if (preg_match('/o365|office|exchange|email.*compte|mailbox/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'O365','params'=>['cmd'=>'echo O365_STATUS: 5 compromised accounts need password rotation: rodolftripp sfgb518 phyleciaamato kamrynnbonilla jolineweatherly']]; } // o365_accounts
if (preg_match('/urgent|pending|todo|action.*item|rappel|a.faire/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Urgent items','params'=>['cmd'=>'echo URGENT_PENDING && echo 1.GitHub_PAT_expires_April_15 && echo 2.WhatsApp_token_expired_April_2 && echo 3.O365_5_accounts_compromised && echo 4.Blade_Sentinel_offline']]; } // urgent_pending
if (preg_match('/searxng|search.*engine|moteur.*recherche|sovereign.*search/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'SearXNG','params'=>['cmd'=>'curl -sf http://127.0.0.1:8080/ --max-time 3 -o /dev/null -w HTTP_%{http_code} && echo SearXNG_UP']]; } // searxng
if (preg_match('/qdrant|rag|vector|embedding|semantic|collection/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Qdrant RAG','params'=>['cmd'=>'curl -sf http://127.0.0.1:6333/collections --max-time 3 | python3 -c "import json,sys;d=json.load(sys.stdin);[(print(c[\"name\"],c.get(\"points_count\",\"?\"))) for c in d[\"result\"][\"collections\"]]"']]; } // qdrant_rag
if (preg_match('/paperclip|ceo|pipeline|lead|opportunit|prospect/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Paperclip CEO','params'=>['cmd'=>'PGPASSWORD=admin123 psql -h 127.0.0.1 -U admin -d adx_system -c "SELECT count(*) as total FROM paperclip.opportunities" -t 2>/dev/null && echo opportunities']]; } // paperclip_ceo
if (preg_match('/wevads|arsenal|sentinel|s95|adx/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'WEVADS Arsenal','params'=>['cmd'=>'curl -sf http://10.1.0.3:5890/api/sentinel-brain.php?action=status --max-time 5 2>/dev/null | head -c 200']]; } // wevads_arsenal
if (preg_match('/skill|competence|registre|capability|capacit/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Skills','params'=>['cmd'=>'ls /opt/deer-flow/skills/weval/ | wc -l && echo skills && ls /opt/deer-flow/skills/weval/ | shuf | head -10']]; } // skill_registry
if (preg_match('/email|mail|o365|outlook|imap|smtp/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Email','params'=>['cmd'=>'PGPASSWORD=admin123 psql -h 127.0.0.1 -U admin -d adx_system -c "SELECT count(*) as total, count(DISTINCT sender) as senders FROM wevia_emails" -t 2>/dev/null && echo emails']]; } // email_o365
if (preg_match('/REMOVED|sso|auth.*flow|REMOVED|login.*page/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Authentik SSO','params'=>['cmd'=>'docker ps --format "{{.Names}} {{.Status}}" | grep auth && curl -sf http://127.0.0.1:99999/REMOVED.goREMOVED.io/ping --max-time 3 -o /dev/null -w Outpost_HTTP_%{http_code} && echo && for d in wevads deerflow analytics; do curl -sf -o /dev/null -w "$d:HTTP_%{http_code} " https://$d.weval-consulting.com --max-time 5 -k; done && echo']]; } // REMOVED_sso
if (preg_match('/uptime|kuma|monitor.*service|disponibilit/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Uptime Kuma','params'=>['cmd'=>'docker ps --format "{{.Names}} {{.Status}}" | grep kuma && curl -sf http://127.0.0.1:3001/api/status-page/heartbeat --max-time 3 -o /dev/null -w HTTP_%{http_code}']]; } // uptime_kuma
if (preg_match('/n8n|workflow|automation|automat/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'N8N','params'=>['cmd'=>'curl -sf http://127.0.0.1:5678/healthz --max-time 3 && echo N8N_UP || echo N8N_DOWN']]; } // n8n_workflow
if (preg_match('/contact|adx.*client|base.*contact|lead.*count|prospect/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Contacts DB','params'=>['cmd'=>'PGPASSWORD=admin123 psql -h 127.0.0.1 -U admin -d adx_clients -t -c "SELECT count(*) FROM contacts" 2>/dev/null && echo contacts || echo DB_ERROR']]; } // contacts_db
if (preg_match('/s151|disaster|recovery|backup.*serv|dr.*status/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'S151 DR','params'=>['cmd'=>'ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 ubuntu@151.80.235.110 "df -h / && uptime" 2>/dev/null || echo S151_UNREACHABLE']]; } // s151_dr
if (preg_match('/langfuse|trace|observ.*ia|ai.*log|telemetry/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Langfuse','params'=>['cmd'=>'curl -sf http://127.0.0.1:3088/ --max-time 3 -o /dev/null -w HTTP_%{http_code} && echo Langfuse_UP || echo Langfuse_DOWN']]; } // langfuse_traces
if (preg_match('/scan.*complet|full.*scan|all.*services|tout.*status|health.*check.*all/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Full scan','params'=>['cmd'=>'echo === && for p in 3001 5678 6333 11434 2024 3900 4001; do R=$(curl -sf http://127.0.0.1:$p/ --max-time 2 -o /dev/null -w %{http_code}); echo "Port $p: HTTP_$R"; done && echo === && docker ps -q | wc -l && echo containers && df -h / | tail -1']]; } // full_scan
if (preg_match('/genere.*pdf|pdf.*rapport|export.*pdf|cree.*pdf/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'PDF gen','params'=>['cmd'=>'which wkhtmltopdf && which pandoc && echo PDF_TOOLS_OK || echo MISSING']]; } // pdf_generate
if (preg_match('/excel|xlsx|spreadsheet|tableau.*export|csv.*export/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Excel gen','params'=>['cmd'=>'python3 -c "import openpyxl;print(\"openpyxl OK\")" 2>&1']]; } // excel_generate
if (preg_match('/pptx|powerpoint|presentation|slide|deck/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'PPTX gen','params'=>['cmd'=>'python3 -c "import pptx;print(\"python-pptx OK\")" 2>&1']]; } // pptx_generate
if (preg_match('/ocr|scan.*texte|extraire.*texte|reconnaissance.*caractere/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'OCR','params'=>['cmd'=>'tesseract --version 2>&1 | head -1 && tesseract --list-langs 2>&1 | head -5']]; } // ocr_scan
if (preg_match('/screenshot|capture.*ecran|snapshot.*page|preview.*site/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Screenshot','params'=>['cmd'=>'python3 -c "from playwright.sync_api import sync_playwright;print(\"Playwright OK\")" 2>&1 | head -1']]; } // screenshot_page
if (preg_match('/chart|graphique|camembert|histogramme|courbe|bar.*chart|pie.*chart/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Chart gen','params'=>['cmd'=>'python3 -c "import matplotlib;print(\"matplotlib\",matplotlib.__version__)" 2>&1']]; } // chart_generate
if (preg_match('/scrape|scraping|extraire.*web|crawler|spider/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Web scrape','params'=>['cmd'=>'python3 -c "import scrapy;print(\"Scrapy\",scrapy.__version__)" 2>&1 && curl -sf http://127.0.0.1:8080/ --max-time 2 -o /dev/null -w SearXNG_HTTP_%{http_code}']]; } // web_scrape
if (preg_match('/genere.*fichier|generate.*file|export.*rapport|download.*pdf|telecharge/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'FileGen API','params'=>['cmd'=>'curl -sf http://127.0.0.1/api/wevia-filegen.php --max-time 3 && echo FileGen_API_OK']]; } // filegen_api
if (preg_match('/obsidian|vault|markdown.*knowledge|note.*manage|pkm|second.*brain|zettelkasten/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Obsidian','params'=>['cmd'=>'ls /opt/antigravity-awesome-skills/skills/obsidian-* | head -5 && echo --- && ls /opt/weval-l99/wiki/ | wc -l && echo wiki_entries']]; } // obsidian_vault
if (preg_match('/n8n.*flow|workflow.*list|automation.*active/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'N8N flows','params'=>['cmd'=>'curl -sf http://127.0.0.1:5678/api/v1/workflows --max-time 5 -H "Accept: application/json" 2>/dev/null | python3 -c "import json,sys;d=json.load(sys.stdin);print(len(d.get(\"data\",[])),\"workflows\")" 2>/dev/null || echo N8N_API_AUTH_NEEDED']]; } // n8n_flows
if (preg_match('/framework|methodologie|bmc|canvas|raci|okr|sprint|backlog|roadmap|persona|user.*story|risk.*register|decision.*matrix/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Frameworks','params'=>['cmd'=>'echo FRAMEWORKS_AVAILABLE: BMC OKR RACI SWOT PESTEL Porter Ishikawa Pareto A3 DMAIC VSM Kaizen Sprint_Planning User_Stories Persona Risk_Register Decision_Matrix Roadmap Gantt BPMN UML Sequence']]; } // frameworks_all
if (preg_match('/deploy|deploie|mise.*prod|restart.*service|reload.*nginx|systemctl/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Deploy','params'=>['cmd'=>'cd /var/www/html && git log --oneline -3 && echo --- && nginx -t 2>&1 | tail -1 && echo DEPLOY_READY']]; } // deploy_action
if (preg_match('/cron.*actif|cron.*list|tache.*planif|scheduled/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Crons','params'=>['cmd'=>'crontab -l | grep -v "^#" | head -20 && echo --- && echo Total: $(crontab -l | grep -vc "^#") crons']]; } // cron_list
if (preg_match('/wiki.*update|knowledge.*base.*stat|documentation.*interne/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Wiki','params'=>['cmd'=>'ls /opt/weval-l99/wiki/ | wc -l && echo wiki_entries && ls -lt /opt/weval-l99/wiki/ | head -5']]; } // wiki_update
// OLLAMA_OFF if (preg_match('/architecture.*complet|archi.*full|registre.*archi|4.*serveur|all.*machine/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Full Architecture','params'=>['cmd'=>'echo "=S204(PRIMARY)=" && df -h / | tail -1 && docker ps -q | wc -l && echo containers && ss -tlnp | grep -c LISTEN && echo ports && echo "=SERVICES=" && for p in 2024 3001 3900 4001 5678 6333 11434; do R=$(curl -sf http://127.0.0.1:$p/ -o /dev/null -w %{http_code} --max-time 2 2>/dev/null); echo "Port $p: HTTP_$R"; done && echo "=OLLAMA=" && curl -sf http://127.0.0.1:4000/api/tags --max-time 3 | python3 -c "import json,sys;[print(m["name"]) for m in json.load(sys.stdin)["models"]]" 2>/dev/null && echo "=QDRANT=" && curl -sf http://127.0.0.1:6333/collections --max-time 3 | python3 -c "import json,sys;[print(c["name"],c.get("points_count","?")) for c in json.load(sys.stdin)["result"]["collections"]]" 2>/dev/null && echo "=CRONS=" && crontab -l | grep -vc "^#" && echo crons && echo "=S95=" && curl -sf http://10.1.0.3:5890/api/sentinel-brain.php?action=status --max-time 5 | head -c 100 2>/dev/null || echo S95_check && echo "=S151=" && ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 ubuntu@151.80.235.110 "df -h / | tail -1 && uptime -p" 2>/dev/null || echo S151_check']]; } // archi_full
// OLLAMA_OFF if (preg_match('/gpu|sovereign.*api|sovereign.*local|vllm.*status|free.*gpu|gpu.*local|nvidia|cuda|vram|graphic.*card/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'GPU+Sovereign','params'=>['cmd'=>'echo "=== SOVEREIGN-API (port 4000) ==="; curl -sf http://127.0.0.1:4000/health --max-time 5 | python3 -c "import json,sys;d=json.load(sys.stdin);print(\"Status:\",d[\"status\"],\"|\",d[\"engine\"],\"|\",\"Providers:\",\",\".join(d[\"providers\"]))" 2>/dev/null || echo sovereign-api DOWN; echo; echo "=== MODELS ==="; curl -sf http://127.0.0.1:4000/v1/models --max-time 5 | python3 -c "import json,sys;[print(\" -\",m[\"id\"]) for m in json.load(sys.stdin)[\"data\"]]" 2>/dev/null; echo; echo "=== FREE GPU COMPUTE ==="; echo "Kaggle T4/P100: 30h/sem CONFIGURED"; echo "HF Spaces weval-vllm: PENDING vLLM deploy"; echo "Render+Railway: CONFIGURED"; echo; echo "=== OLLAMA S204 ==="; curl -sf http://127.0.0.1:4000/api/tags --max-time 3 | python3 -c "import json,sys;[print(\" -\",m[\"name\"],round(m[\"size\"]/1048576),\"MB\") for m in json.load(sys.stdin)[\"models\"]]" 2>/dev/null']]; } // gpu_sovereign_check
if (preg_match('/snap|archive|snapshot.*archi|sauvegarde.*etat|etat.*complet/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Snap Archive','params'=>['cmd'=>'echo "=== WEVIA SNAP ===" && date && echo "Intents: $(grep -c preg_match /var/www/html/api/wevia-autonomous.php)" && echo "Context: $(wc -l < /var/www/html/api/wevia-live-context.php)L" && echo "APIs: $(ls /var/www/html/api/*.php | wc -l)" && echo "Docker: $(docker ps -q | wc -l)" && echo "Crons: $(crontab -l | grep -vc "^#")" && echo "Disk: $(df -h / | awk "NR==2{print \$4}")" && echo "Wiki: $(ls /opt/weval-l99/wiki/ | wc -l)" && echo "GOLD: $(ls /opt/wevads/vault/gold-6avr-l99/ | wc -l)" && echo "Git: $(cd /var/www/html && git log --oneline -1)"']]; } // snap_archive
if (preg_match('/wevia.*html.*config|chatbot.*config|fullscreen.*config|expand.*file.*type/i', $msg)) { $intents[] = ['name'=>'ssh_exec','desc'=>'Wevia HTML config','params'=>['cmd'=>'wc -l /var/www/html/wevia.html && grep -oP "accept=.{60}" /var/www/html/wevia.html && echo --- && grep CURLOPT_TIMEOUT /var/www/html/api/weval-chatbot-api.php | head -1 && echo CONFIG_OK']]; } // wevia_html_config
return $intents;
}
function executeIntent($intent) {
switch ($intent['name']) {
case 'ssh_exec':
$cmd = $intent['params']['cmd'] ?? 'hostname';
return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', trim(shell_exec('timeout 10 ' . $cmd . ' 2>&1') ?? ''));
case 'email':
return ['action' => 'email_ready', 'to' => $intent['params']['to'], 'note' => 'Email prêt à envoyer. Confirmez le contenu.'];
case 'file_read':
$path = $intent['params']['path'];
if (!file_exists($path)) return "Fichier non trouvé: $path";
return substr(file_get_contents($path), 0, 3000);
case 'file_browse':
$path = $intent['params']['path'];
$out = shell_exec('ls -la ' . escapeshellarg($path) . ' 2>&1 | head -20');
return mb_convert_encoding(trim($out ?? ''), 'UTF-8', 'UTF-8');
case 'UNUSED_file_browse':
$path = $intent['params']['path'];
return shell_exec('ls -la ' . escapeshellarg($path) . ' 2>&1 | head -25');
case 'search':
$q = $intent['params']['q'];
$ch = curl_init("http://127.0.0.1:8888/search?q=" . urlencode($q) . "&format=json&limit=5&safesearch=2&engines=google,bing,duckduckgo");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_USERAGENT => 'WEVIA/1.0', CURLOPT_TIMEOUT => 10]);
$r = curl_exec($ch); curl_close($ch);
$d = json_decode($r, true);
$results = [];
foreach (($d['results'] ?? []) as $res) {
$results[] = $res['title'] . ' — ' . ($res['url'] ?? '');
}
return implode("\n", $results) ?: 'Aucun résultat';
case 'doc_generate':
$type = $intent['params']['type'] ?? 'txt';
$fname = 'weval-doc-' . date('Ymd-His') . '.' . $type;
$path = '/var/www/html/api/exports/' . $fname;
@mkdir(dirname($path), 0777, true);
// LLM will generate content, we create placeholder
file_put_contents($path, "Document WEVAL - genere par WEVIA Master\n" . date('Y-m-d H:i:s'));
return ['status' => 'ready', 'file' => $fname, 'download' => 'https://weval-consulting.com/api/exports/' . $fname, 'note' => 'Document pret. Le contenu sera genere par le LLM.'];
case 'code_run':
$lang = $intent['params']['lang'] ?? 'bash';
$code = $intent['params']['code'] ?? '';
$tmp = tempnam('/tmp', 'wc_');
if ($lang === 'php') { file_put_contents($tmp, '<?php ' . $code); $out = shell_exec('php ' . escapeshellarg($tmp) . ' 2>&1'); }
elseif ($lang === 'python') { file_put_contents($tmp, $code); $out = shell_exec('python3 ' . escapeshellarg($tmp) . ' 2>&1'); }
else { $out = shell_exec($code . ' 2>&1'); }
@unlink($tmp);
return ['output' => substr($out ?? '', 0, 3000), 'lang' => $lang];
case 'email_send':
$to = $intent['params']['to'] ?? '';
if (empty($to)) return ['error' => 'no recipient'];
return ['status' => 'draft', 'to' => $to, 'note' => 'Email pret. Confirmez sujet et contenu.'];
case 'url_analyze':
$url = $intent['params']['url'] ?? '';
$headers = shell_exec('curl -sf -I ' . escapeshellarg($url) . ' 2>&1 | head -15');
$title = shell_exec('curl -sf ' . escapeshellarg($url) . ' 2>&1 | grep -oP "(?<=<title>).*?(?=</title>)" | head -1');
return ['url' => $url, 'headers' => $headers, 'title' => trim($title ?? '')];
case 'code_exec':
return ['note' => 'Code détecté. Utilisez wevia_code pour exécuter.'];
case 'excel':
return ['note' => 'Export demandé. Précisez les données à exporter.'];
default:
return ['error' => 'intent not handled: ' . $intent['name']];
}
}
function recallMemory($msg) {
$ch = curl_init('http://127.0.0.1:4000/api/embeddings');
curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>json_encode(['model'=>'all-minilm','prompt'=>$msg]),
CURLOPT_HTTPHEADER=>['Content-Type: application/json'], CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5]);
$r = curl_exec($ch); curl_close($ch);
$vec = json_decode($r, true)['embedding'] ?? null;
if (!$vec) return '';
$ch2 = curl_init('http://127.0.0.1:6333/collections/wevia_memory/points/search');
curl_setopt_array($ch2, [CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>json_encode(['vector'=>$vec,'limit'=>3,'with_payload'=>true]),
CURLOPT_HTTPHEADER=>['Content-Type: application/json'], CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>3]);
$r2 = curl_exec($ch2); curl_close($ch2);
$pts = json_decode($r2, true)['result'] ?? [];
$ctx = '';
foreach ($pts as $p) {
if ($p['score'] > 0.3) {
$ctx .= "- [{$p['payload']['key']}] {$p['payload']['value']}\n";
}
}
return $ctx;
}
function queryRAG($msg) {
if (strlen($msg) < 15) return '';
$ch = curl_init('http://127.0.0.1:4000/api/embeddings');
curl_setopt_array($ch, [CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>json_encode(['model'=>'all-minilm','prompt'=>$msg]),
CURLOPT_HTTPHEADER=>['Content-Type: application/json'], CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5]);
$r = curl_exec($ch); curl_close($ch);
$vec = json_decode($r, true)['embedding'] ?? null;
if (!$vec) return '';
$ch2 = curl_init('http://127.0.0.1:6333/collections/weval_skills/points/search');
curl_setopt_array($ch2, [CURLOPT_POST=>true, CURLOPT_POSTFIELDS=>json_encode(['vector'=>$vec,'limit'=>5,'with_payload'=>true]),
CURLOPT_HTTPHEADER=>['Content-Type: application/json'], CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>3]);
$r2 = curl_exec($ch2); curl_close($ch2);
$pts = json_decode($r2, true)['result'] ?? [];
$ctx = '';
foreach ($pts as $p) {
$text = $p['payload']['text'] ?? $p['payload']['content'] ?? '';
if ($text) $ctx .= substr($text, 0, 300) . "\n";
}
return $ctx;
}
function streamLLM($system, $userMsg, $history) {
$secrets = [];
foreach (file('/etc/weval/secrets.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
if (empty(trim($line)) || $line[0] === '#') continue;
$pos = strpos($line, '=');
if ($pos) $secrets[trim(substr($line, 0, $pos))] = trim(substr($line, $pos + 1), " \t\"'");
}
$messages = [['role' => 'system', 'content' => $system]];
foreach (array_slice($history, -6) as $h) {
$messages[] = ['role' => $h['role'], 'content' => $h['content']];
}
$messages[] = ['role' => 'user', 'content' => $userMsg];
$providers = [
// === LOCAL SOUVERAIN (0 rate limit, 0 cost) ===
// OLLAMA_OFF ['url'=>'http://127.0.0.1:4000/v1/chat/completions','key'=>'ollama','model'=>'gemma4:e4b'],
// OLLAMA_OFF ['url'=>'http://127.0.0.1:4000/v1/chat/completions','key'=>'ollama','model'=>'qwen3:8b'],
// OLLAMA_OFF ['url'=>'http://127.0.0.1:4000/v1/chat/completions','key'=>'ollama','model'=>'glm4:9b'],
// OLLAMA_OFF ['url'=>'http://127.0.0.1:4000/v1/chat/completions','key'=>'ollama','model'=>'qwen3:4b'],
// OLLAMA_OFF ['url'=>'http://127.0.0.1:4000/v1/chat/completions','key'=>'ollama','model'=>'deepseek-r1:7b'],
// Groq FIRST (native SSE streaming)
// sovereign moved after Groq (no PHP streaming support)
// ["url"=>"http://127.0.0.1:4000/v1/chat/completions","key"=>"sovereign","model"=>"auto"],
// === CLOUD BACKUP (si local down) ===
['url'=>'https://router.huggingface.co/v1/chat/completions','key'=>'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','model'=>'Qwen/Qwen2.5-72B-Instruct'],
['url'=>'https://api.groq.com/openai/v1/chat/completions','key'=>$secrets['GROQ_KEY']??'','model'=>'llama-3.3-70b-versatile'],
['url'=>'https://api.mistral.ai/v1/chat/completions','key'=>$secrets['MISTRAL_KEY']??'','model'=>'mistral-small-latest'],
['url'=>'https://integrate.api.nvidia.com/v1/chat/completions','key'=>$secrets['NVIDIA_NIM_KEY']??'','model'=>'nvidia/llama-3.3-nemotron-super-49b-v1'],
['url'=>'https://api.cerebras.ai/v1/chat/completions','key'=>$secrets['CEREBRAS_KEY_2']??'','model'=>'llama3.1-8b'],
];
foreach ($providers as $prov) {
if (empty($prov['key'])) continue;
// Claude Code CLI: non-streaming fallback
if (isset($prov['is_claude_code'])) {
$prompt = end($messages)['content'] ?? '';
$escaped = escapeshellarg($prompt);
$model = $prov['model'] === 'claude-opus' ? 'claude-opus-4-6' : 'claude-sonnet-4-20250514';
$out = shell_exec("timeout 25 claude --model $model -p $escaped 2>/dev/null");
if ($out && strlen(trim($out)) > 5) {
echo "data: " . json_encode(['type'=>'token','content'=>trim($out)]) . "\n\n";
echo "data: " . json_encode(['type'=>'done','provider'=>'claude-code']) . "\n\n";
flush();
exit;
}
continue;
}
$ch = curl_init($prov['url']);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(isset($prov['is_anthropic']) ? [
'model' => $prov['model'],
'messages' => array_values(array_filter($messages, function($m){return $m['role']!=='system';})),
'system' => implode(' ', array_map(function($m){return $m['content'];}, array_filter($messages, function($m){return $m['role']==='system';}))),
'max_tokens' => 8192,
'stream' => true,
] : [
'model' => $prov['model'],
'messages' => $messages,
'max_tokens' => 8192,
'temperature' => 0.4,
'stream' => true,
]),
CURLOPT_HTTPHEADER => isset($prov['is_anthropic']) ? ['Content-Type: application/json', 'x-api-key: ' . $prov['key'], 'anthropic-version: 2023-06-01'] : ['Content-Type: application/json', 'Authorization: Bearer ' . $prov['key']],
CURLOPT_RETURNTRANSFER => false,
CURLOPT_TIMEOUT => 90,
CURLOPT_WRITEFUNCTION => function($ch, $data) use ($prov) {
$lines = explode("\n", $data);
foreach ($lines as $line) {
$line = trim($line);
if (empty($line) || $line === 'data: [DONE]') continue;
if (strpos($line, 'data: ') !== 0) continue;
$json = json_decode(substr($line, 6), true);
$content = $json['choices'][0]['delta']['content'] ?? '';
if ($content !== '') {
emit('token', ['content' => $content]);
}
}
return strlen($data);
},
]);
emit('start', ['provider' => basename(parse_url($prov['url'], PHP_URL_HOST), '.com'), 'model' => $prov['model']]);
$start = microtime(true);
curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code === 200) {
emit('done', ['latency_ms' => round((microtime(true) - $start) * 1000)]);
return;
}
}
emit('error', ['message' => 'All providers failed']);
}