false, 'error'=>'truth-registry not built · run wevia-truth-builder.php']); exit; } $T = json_decode(file_get_contents($registry_path), true); if (!$T) { echo json_encode(['ok'=>false, 'error'=>'truth-registry corrupted']); exit; } // Helper function hay($haystack, $needles) { foreach ((array)$needles as $n) { if (stripos($haystack, $n) !== false) return true; } return false; } $answer = null; $matched_pattern = null; // ============== PATTERN MATCHING ============== // 1. Counts & numbers if (hay($q, ['combien', 'how many', 'nombre de', 'count'])) { if (hay($q, ['agent'])) { $answer = [ 'question' => $q, 'answer' => $T['agents']['count_unique'] . ' agents uniques (dédupliqués sur ' . count($T['agents']['by_source']) . ' sources · ' . $T['agents']['count_with_overlaps'] . ' avec overlaps)', 'value' => $T['agents']['count_unique'], 'details' => $T['agents']['by_source'], ]; $matched_pattern = 'count_agents'; } elseif (hay($q, ['intent'])) { $answer = [ 'question' => $q, 'answer' => $T['intents']['count'] . ' intents wired (' . $T['intents']['arena_declared'] . ' arena declared)', 'value' => $T['intents']['count'], 'by_status' => $T['intents']['by_status'], 'by_domain' => $T['intents']['by_domain'], ]; $matched_pattern = 'count_intents'; } elseif (hay($q, ['skill'])) { $answer = [ 'question' => $q, 'answer' => number_format($T['skills']['TOTAL']) . ' skills TOTAL · 5 sources', 'value' => $T['skills']['TOTAL'], 'sources' => $T['skills']['sources'], ]; $matched_pattern = 'count_skills'; } elseif (hay($q, ['brain'])) { $answer = ['question' => $q, 'answer' => $T['brains']['count'] . ' brains', 'value' => $T['brains']['count']]; $matched_pattern = 'count_brains'; } elseif (hay($q, ['doctrine'])) { $answer = ['question' => $q, 'answer' => $T['doctrines']['count'] . ' doctrines', 'value' => $T['doctrines']['count'], 'items' => array_slice($T['doctrines']['items'], 0, 10)]; $matched_pattern = 'count_doctrines'; } elseif (hay($q, ['dashboard', 'page'])) { $answer = ['question' => $q, 'answer' => $T['dashboards']['count'] . ' dashboards HTML', 'value' => $T['dashboards']['count']]; $matched_pattern = 'count_dashboards'; } elseif (hay($q, ['provider', 'llm', 'model'])) { $answer = ['question' => $q, 'answer' => $T['providers']['declared_total'] . '/13 providers', 'value' => $T['providers']['declared_total']]; $matched_pattern = 'count_providers'; } elseif (hay($q, ['api', 'endpoint'])) { $answer = ['question' => $q, 'answer' => $T['apis_php_count'] . ' APIs PHP', 'value' => $T['apis_php_count']]; $matched_pattern = 'count_apis'; } } // 2. Score / autonomy / godmode if (!$answer && hay($q, ['score', 'autonomy', 'autonomie', 'godmode'])) { $answer = [ 'question' => $q, 'answer' => $T['autonomy_score'] . '/100 · ' . $T['autonomy_level'], 'value' => $T['autonomy_score'], 'level' => $T['autonomy_level'], ]; $matched_pattern = 'autonomy'; } // 3. Find agent by name if (!$answer && (hay($q, ['agent']) && !hay($q, ['combien', 'how many']))) { $matches = []; foreach ($T['agents']['items'] as $a) { if (stripos($a['name'], $q) !== false || stripos($a['key'], $q) !== false || stripos(str_replace('agent', '', $q), $a['key']) !== false) { $matches[] = $a; } } // Extract keyword after "agent" if (empty($matches) && preg_match('/agent\s+(\w+)/', $q, $m)) { $kw = $m[1]; foreach ($T['agents']['items'] as $a) { if (stripos($a['name'], $kw) !== false) $matches[] = $a; } } if (!empty($matches)) { $answer = [ 'question' => $q, 'answer' => count($matches) . ' agents trouvés', 'matches' => array_slice($matches, 0, 20), ]; $matched_pattern = 'find_agent'; } } // 4. Find intent by trigger if (!$answer && hay($q, ['intent', 'trigger'])) { $matches = []; $kw = $q; if (preg_match('/intent\s+([\w]+)/', $q, $m)) $kw = $m[1]; elseif (preg_match('/trigger\s+([\w]+)/', $q, $m)) $kw = $m[1]; foreach ($T['intents']['items'] as $i) { $hay = strtolower($i['name'] . ' ' . implode(' ', $i['triggers'] ?? []) . ' ' . ($i['description'] ?? '') . ' ' . ($i['domain'] ?? '')); if (stripos($hay, $kw) !== false) $matches[] = $i; } if (!empty($matches)) { $answer = [ 'question' => $q, 'answer' => count($matches) . ' intents trouvés', 'matches' => array_slice($matches, 0, 15), ]; $matched_pattern = 'find_intent'; } } // 5. Status / health if (!$answer && hay($q, ['status', 'etat', 'état', 'health', 'truth', 'consolidation'])) { $answer = [ 'question' => $q, 'answer' => 'WEVIA Truth Registry · ' . $T['autonomy_level'], 'summary' => [ 'agents' => $T['agents']['count_unique'], 'intents' => $T['intents']['count'], 'skills' => $T['skills']['TOTAL'], 'brains' => $T['brains']['count'], 'doctrines' => $T['doctrines']['count'], 'dashboards' => $T['dashboards']['count'], 'providers' => $T['providers']['declared_total'], 'qdrant_collections' => $T['qdrant']['collections_count'], 'qdrant_points' => $T['qdrant']['total_points'], 'nonreg' => $T['nonreg']['score'] . '/' . $T['nonreg']['total'], 'autonomy' => $T['autonomy_score'] . '/100 ' . $T['autonomy_level'], ], 'built_at' => $T['built_at'], ]; $matched_pattern = 'status'; } // 6. List / what is available if (!$answer && hay($q, ['list', 'liste', 'tous', 'all', 'what', 'quels'])) { $answer = [ 'question' => $q, 'answer' => 'WEVIA capabilities summary', 'agents_total' => $T['agents']['count_unique'], 'intents_total' => $T['intents']['count'], 'skills_total' => $T['skills']['TOTAL'], 'top_agents' => array_slice(array_filter($T['agents']['items'], fn($a) => count($a['sources']) >= 3), 0, 20), 'arena_domains' => array_keys($T['intents']['arena_domains'] ?? []), ]; $matched_pattern = 'list'; } // 7. DEFAULT · no match · return help if (!$answer) { $answer = [ 'question' => $q, 'answer' => 'Question non reconnue · voici les patterns supportés', 'help' => [ '"combien d\'agents ?"' => 'Returns agent count + breakdown by source', '"combien d\'intents ?"' => 'Returns intent count + by status/domain', '"combien de skills ?"' => 'Returns skills total + 5 sources', '"autonomy score"' => 'Returns autonomy score + GODMODE level', '"status / etat / truth"' => 'Full WEVIA state summary', '"agent X"' => 'Find agents matching X', '"intent Y"' => 'Find intents matching Y', '"list all"' => 'List top referenced agents + domains', ], 'examples' => [ '/api/wevia.php?q=combien+d\'agents', '/api/wevia.php?q=status', '/api/wevia.php?q=agent+cerebras', '/api/wevia.php?q=intent+warmup', ], 'truth_registry' => '/api/wevia-truth-registry.json', ]; $matched_pattern = 'help'; } $answer['matched_pattern'] = $matched_pattern; $answer['ts'] = date('c'); $answer['registry_built_at'] = $T['built_at']; // Output formats if ($fmt === 'text') { header('Content-Type: text/plain; charset=utf-8'); if (isset($answer['answer'])) echo "Q: " . ($q ?: '(no query)') . "\n"; echo "A: " . ($answer['answer'] ?? 'N/A') . "\n"; if (isset($answer['value'])) echo "V: " . $answer['value'] . "\n"; if (isset($answer['details'])) { echo "Details:\n"; foreach ($answer['details'] as $k=>$v) echo " · $k: $v\n"; } if (isset($answer['summary'])) { echo "Summary:\n"; foreach ($answer['summary'] as $k=>$v) echo " · $k: " . (is_array($v) ? json_encode($v) : $v) . "\n"; } exit; } echo json_encode(['ok'=>true] + $answer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);