Files
html/api/wevia-unified-api.php

292 lines
12 KiB
PHP

<?php
/**
* WEVIA Unified API v2 · TOUTES les 7 sources agents + déduplication
* Opus Yacine · 19avr2026
*/
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
header('Access-Control-Allow-Origin: *');
$action = $_GET['action'] ?? 'summary';
$QDRANT = 'http://127.0.0.1:6333';
function qdrant($url, $m='GET', $d=null) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>6, CURLOPT_CUSTOMREQUEST=>$m]);
if ($d) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($d)); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); }
$r = curl_exec($ch); curl_close($ch);
return json_decode($r ?: '{}', true);
}
// === FAST PATH · Use truth-registry as single source if available (Yacine) ===
$TRUTH = @json_decode(@file_get_contents('/var/www/html/api/wevia-truth-registry.json'), true);
if ($TRUTH && !empty($TRUTH['agents']['count_unique'])) {
header('X-Source: truth-registry');
$action_in = $_GET['action'] ?? 'summary';
if ($action_in === 'summary') {
echo json_encode([
'ok' => true,
'ts' => date('c'),
'source' => 'truth-registry',
'summary' => [
'agents' => [
'UNIQUE_DEDUP' => $TRUTH['agents']['count_unique'],
'total_with_overlaps' => $TRUTH['agents']['count_with_overlaps'],
'per_source' => $TRUTH['agents']['by_source'],
],
'intents' => [
'php_files' => $TRUTH['intents']['count'],
'arena_declared' => $TRUTH['intents']['arena_declared'],
'by_status' => $TRUTH['intents']['by_status'] ?? [],
'by_domain' => $TRUTH['intents']['by_domain'] ?? [],
],
'skills' => [
'TOTAL_ALL_SOURCES' => $TRUTH['skills']['TOTAL'],
'disk_dirs' => $TRUTH['skills']['sources']['disk_dirs'] ?? 0,
'qdrant_vectorized' => $TRUTH['skills']['sources']['qdrant_vectorized'] ?? 0,
'tools_registry' => $TRUTH['skills']['sources']['tools_registry'] ?? 0,
'arena_declared' => $TRUTH['skills']['sources']['arena_declared'] ?? 0,
'doctrines' => $TRUTH['doctrines']['count'] ?? 0,
],
'brains' => ['count' => $TRUTH['brains']['count']],
'dashboards' => $TRUTH['dashboards']['count'],
'apis' => $TRUTH['apis_php_count'] ?? 0,
],
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
if ($action_in === 'agents') {
echo json_encode([
'ok' => true,
'ts' => date('c'),
'source' => 'truth-registry',
'agents' => array_map(function($a) {
return [
'name' => $a['name'],
'key' => $a['key'] ?? '',
'sources' => $a['sources'],
'sources_count' => count($a['sources']),
'category' => $a['meta']['category'] ?? ($a['meta']['role'] ?? '?'),
'role' => $a['meta']['role'] ?? $a['meta']['description'] ?? '',
'icon' => $a['meta']['icon'] ?? $a['meta']['emoji'] ?? '',
];
}, $TRUTH['agents']['items']),
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
}
$out = ['ok'=>true, 'ts'=>date('c')];
// ============== AGENTS MULTI-SOURCE DÉDUPLIQUÉ ==============
$agents_by_name = []; // key = normalized name → metadata
$sources_counts = [];
function normalize_name($n) { return strtolower(trim(preg_replace('/[^a-z0-9]+/i', '_', $n), '_')); }
function add_agent(&$reg, $name, $source, $meta = []) {
if (!$name) return;
$key = normalize_name($name);
if (!isset($reg[$key])) {
$reg[$key] = ['name' => $name, 'sources' => [], 'meta' => $meta];
}
if (!in_array($source, $reg[$key]['sources'])) {
$reg[$key]['sources'][] = $source;
}
$reg[$key]['meta'] = array_merge($reg[$key]['meta'], $meta);
}
// Source 1: agent-avatars-v2.json (most complete · 148 agents)
$av2 = @json_decode(@file_get_contents('/var/www/html/api/agent-avatars-v2.json'), true);
$sources_counts['agent_avatars_v2'] = 0;
if (is_array($av2)) {
foreach ($av2 as $name => $meta) {
add_agent($agents_by_name, $name, 'agent_avatars_v2', is_array($meta) ? $meta : []);
$sources_counts['agent_avatars_v2']++;
}
}
// Source 2: agent-avatars.json (136 agents · older)
$av1 = @json_decode(@file_get_contents('/var/www/html/api/agent-avatars.json'), true);
$sources_counts['agent_avatars_v1'] = 0;
if (is_array($av1)) {
foreach ($av1 as $name => $meta) {
add_agent($agents_by_name, $name, 'agent_avatars_v1', is_array($meta) ? $meta : []);
$sources_counts['agent_avatars_v1']++;
}
}
// Source 3: wevia-agents-registry.json (47 categorized · categories metadata)
$reg_cat = @json_decode(@file_get_contents('/var/www/html/api/wevia-agents-registry.json'), true);
$sources_counts['wevia_agents_registry'] = $reg_cat['total'] ?? 0;
// Categories metadata used later
// Source 4: paperclip-agility-agents-registered.json (12 agents V71)
$pc_agility = @json_decode(@file_get_contents('/var/www/html/api/paperclip-agility-agents-registered.json'), true);
$sources_counts['paperclip_agility_v71'] = 0;
if (is_array($pc_agility) && isset($pc_agility['agents'])) {
foreach ($pc_agility['agents'] as $a) {
add_agent($agents_by_name, $a['name'] ?? '?', 'paperclip_agility_v71', ['category' => $a['category'] ?? 'agility', 'icon' => $a['icon'] ?? '🤖', 'role' => $a['role'] ?? '']);
$sources_counts['paperclip_agility_v71']++;
}
}
// Source 5: /api/*agent*.json files (11 files)
$sources_counts['api_agent_files'] = 0;
foreach (glob('/var/www/html/api/*agent*.json') as $f) {
$fname = basename($f, '.json');
// Skip the registries we already processed
if (in_array($fname, ['agent-avatars', 'agent-avatars-v2', 'wevia-agents-registry', 'paperclip-agility-agents-registered', 'wevia-agents-pack-status'])) continue;
add_agent($agents_by_name, $fname, 'api_agent_files', ['path' => str_replace('/var/www/html','',$f)]);
$sources_counts['api_agent_files']++;
}
// Source 6: /api/agent-stubs/*.php (50 stubs)
$sources_counts['agent_stubs'] = 0;
foreach (glob('/var/www/html/api/agent-stubs/*.php') as $f) {
$name = basename($f, '.php');
add_agent($agents_by_name, $name, 'agent_stubs', ['type' => 'stub_php']);
$sources_counts['agent_stubs']++;
}
// Source 7: /api/sub-agents/*.json (65 Claude sub-agents)
$sources_counts['claude_subagents'] = 0;
foreach (glob('/var/www/html/api/sub-agents/*.json') as $f) {
$data = @json_decode(@file_get_contents($f), true);
$name = $data['name'] ?? basename($f, '.json');
add_agent($agents_by_name, $name, 'claude_subagents', $data ?: []);
$sources_counts['claude_subagents']++;
}
// Source 8: Qdrant weval_agents_registry (if exists)
$qdrant_agents = qdrant("$QDRANT/collections/weval_agents_registry");
$sources_counts['qdrant_agents_vectorized'] = $qdrant_agents['result']['points_count'] ?? 0;
// Paperclip ecosystem reference (from disk)
$paperclip_dirs = glob('/opt/deer-flow/skills/weval/paperclip*', GLOB_ONLYDIR);
$sources_counts['paperclip_opt_catalog'] = is_array($paperclip_dirs) ? count($paperclip_dirs) : 0;
$agents_unique_count = count($agents_by_name);
// ============== INTENTS ==============
$intents = [];
foreach (glob('/var/www/html/api/wired-pending/intent-*.php') as $f) {
ob_start();
$info = @include $f;
ob_end_clean();
if (is_array($info)) {
$intents[] = [
'name' => $info['name'] ?? basename($f),
'domain' => $info['domain'] ?? 'general',
'status' => $info['status'] ?? '?',
'triggers' => array_slice($info['triggers'] ?? [], 0, 3),
'source' => $info['source'] ?? '?',
];
}
}
$arena = @json_decode(@file_get_contents('/var/www/html/api/arena-intent-registry.json'), true);
// ============== SKILLS ==============
$skills_disk = glob('/var/www/html/skills/*', GLOB_ONLYDIR);
$qdrant_skills = qdrant("$QDRANT/collections/weval_skills");
$qdrant_skills_count = $qdrant_skills['result']['points_count'] ?? 0;
$reg = @json_decode(@file_get_contents('/var/www/html/api/wevia-tool-registry.json'), true);
$tools_count = isset($reg['tools']) && is_array($reg['tools']) ? count($reg['tools']) : 0;
$arena_skills = $arena['total_skills'] ?? 0;
// Doctrines (58 mentioned in screenshots)
$doctrine_files = glob('/var/www/html/api/doctrine*.json');
$doctrines_count = is_array($doctrine_files) ? count($doctrine_files) : 0;
// Also check /opt/wevads/doctrines/
$doctrine_files2 = glob('/opt/wevads/doctrines/*.md');
if (is_array($doctrine_files2)) $doctrines_count += count($doctrine_files2);
// ============== BRAINS ==============
$brain_patterns = ['/var/www/html/api/*brain*.php', '/var/www/html/api/*brain*.json', '/var/www/html/api/*brain*.py'];
$brains = [];
foreach ($brain_patterns as $pat) {
foreach (glob($pat) as $f) {
$name = basename($f);
// Filter noise
if (strpos($name, 'playwright') !== false) continue;
if (strpos($name, 'screenshot') !== false) continue;
$brains[] = [
'name' => str_replace(['.php','.json','.py'], '', $name),
'path' => str_replace('/var/www/html','',$f),
'type' => pathinfo($f, PATHINFO_EXTENSION),
'size' => filesize($f),
];
}
}
// Dashboards
$dash_paths = array_unique(array_merge(
glob('/var/www/html/wevia-*.html') ?: [],
glob('/var/www/html/agents-*.html') ?: [],
glob('/var/www/html/*-dashboard*.html') ?: [],
glob('/var/www/html/*-hub*.html') ?: [],
glob('/var/www/html/l99*.html') ?: [],
));
$dashboards_count = count($dash_paths);
// APIs
$apis_count = count(glob('/var/www/html/api/*.php') ?: []);
// ============== OUTPUT ==============
$out['summary'] = [
'agents' => [
'UNIQUE_DEDUP' => $agents_unique_count, // Real unique agents
'per_source' => $sources_counts,
'total_with_overlaps' => array_sum($sources_counts),
'note' => 'Agents dédupliqués par nom normalisé · fusion 7+ sources',
],
'intents' => [
'php_files' => count($intents),
'arena_declared' => $arena['total_intents'] ?? 0,
'by_status' => array_count_values(array_column($intents, 'status')),
'by_domain' => array_count_values(array_column($intents, 'domain')),
],
'skills' => [
'disk_dirs' => count($skills_disk),
'qdrant_vectorized' => $qdrant_skills_count,
'tools_registry' => $tools_count,
'arena_declared' => $arena_skills,
'doctrines' => $doctrines_count,
'TOTAL_ALL_SOURCES' => count($skills_disk) + $qdrant_skills_count + $tools_count + $arena_skills,
],
'brains' => [
'count' => count($brains),
'list' => $brains,
],
'dashboards' => $dashboards_count,
'apis' => $apis_count,
];
if ($action === 'agents') {
$agents_list = [];
foreach ($agents_by_name as $key => $a) {
$agents_list[] = [
'name' => $a['name'],
'key' => $key,
'sources' => $a['sources'],
'sources_count' => count($a['sources']),
'category' => $a['meta']['category'] ?? '?',
'role' => $a['meta']['role'] ?? $a['meta']['description'] ?? '',
'icon' => $a['meta']['icon'] ?? $a['meta']['emoji'] ?? '',
];
}
// Sort by sources_count desc (most referenced first), then alpha
usort($agents_list, function($a,$b) {
if ($a['sources_count'] !== $b['sources_count']) return $b['sources_count'] - $a['sources_count'];
return strcmp($a['name'], $b['name']);
});
$out['agents'] = $agents_list;
}
if ($action === 'intents') $out['intents_list'] = $intents;
if ($action === 'brains') $out['brains_list'] = $brains;
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);