0 && mb_strlen($msg_lower) > 60 && preg_match("/reconcil|diagnostic|bilan|test_global/", $tool["id"] ?? "")) $score += 1; if ($score > $best_score || ($score == $best_score && !empty($tool["cmd"]) && empty($best["cmd"]))) { $second_best_score = $best_score; $best_score = $score; $best = $tool; } elseif ($score > $second_best_score) { $second_best_score = $score; } } // HARDENING: seuil relevé de 3 à 6 (exige regex exact score=10 OU 3 keywords matches score=6) // Évite fuzzy-match abusif type "plus" → ports.sh if (!$best || $best_score < 6) { // Retourner suggestion au lieu de null si score "moyen" (3-5) if ($best && $best_score >= 3) { return [ 'provider' => 'dynamic-resolver', 'content' => "Je n'ai pas bien compris votre demande. Vous vouliez peut-être :\n • " . ($best['id'] ?? 'unknown') . " (demandez : \"" . ($best['kw'] ?? '') . "\")\n\nSi ce n'est pas ça, essayez :\n • \"candidats dashboard\" — stats recrutement\n • \"facturation mission\" — missions & TJM\n • \"etat du systeme\" — vue globale\n • \"andons actifs\" — alertes en cours", 'tool' => 'disambiguation' ]; } return null; } // HARDENING: si 2 tools ont scores très proches (diff <= 1) ET regex non-exact, demander clarification if ($best_score < 10 && $second_best_score >= $best_score - 1 && $second_best_score >= 4) { return [ 'provider' => 'dynamic-resolver', 'content' => "Votre demande est ambiguë (plusieurs interprétations possibles). Précisez svp :\n • Pour la situation business → \"etat du systeme\", \"candidats dashboard\", \"facturation mission\"\n • Pour l'infra → \"etat global\", \"andons actifs\", \"verify l99\"", 'tool' => 'ambiguous' ]; } $result = ''; if (!empty($best['cmd'])) { $result = shell_exec('sudo timeout 15 bash -c ' . escapeshellarg($best['cmd']) . ' 2>&1') ?? ''; if (trim($result) === '') $result = '[timeout 15s] Commande lente. Essayez plus ciblé.'; } elseif (strpos($best['api'] ?? '', 'GET:') === 0) { $ctx = stream_context_create(['http' => ['timeout' => 4]]); $result = @file_get_contents('http://127.0.0.1' . substr($best['api'], 4), false, $ctx) ?? ''; } elseif (strpos($best['api'] ?? '', 'POST:') === 0) { $ctx = stream_context_create(['http' => ['method' => 'POST', 'timeout' => 4]]); $result = @file_get_contents('http://127.0.0.1' . substr($best['api'], 5), false, $ctx) ?? ''; } if (!$result) return ["provider"=>"dynamic-resolver","content"=>"[" . ($best["id"] ?? "tool") . "] pas de reponse (timeout ou service down)","tool"=>$best["id"]??"unknown"]; return ['provider' => 'dynamic-resolver', 'content' => trim($result), 'tool' => $best['id'] ?? 'unknown']; } function wevia_dynamic_resolve($msg) { return wevia_resolve($msg); }