Files
html/cloudbot-social.html
Opus b29b1e85d9
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
feat(cloudbot-social): ajout lien header Live Ops dashboard temps reel
- Injection ancree apres lien Paperclip Flow (ligne 224)
- Style gradient rouge #e94560 distinctif pour visibilite
- Doctrine additive (zero ecrasement autre Claude)
- GOLD backup pre-liveops-v2 pour rollback
- chattr +i restaure apres modif
- HTTP 200 verify ok
2026-04-23 22:37:27 +02:00

916 lines
48 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVIA Cloudbot Social v2 - Live Network</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
<style>
:root{
--bg:#070a15;--bg2:#0d1220;--card:#121829;--card-h:#1a2138;--bd:rgba(130,150,210,.1);--bd2:rgba(130,150,210,.18);
--ac:#8b5cf6;--a2:#06d6ba;--wn:#fbbf24;--er:#ef4444;--ok:#10b981;--inf:#3b82f6;--pk:#ec4899;
--fg:#f1f5f9;--dm:#64748b;--mg:#94a3b8;--hg:#cbd5e1;
--grad:linear-gradient(135deg,#8b5cf6 0%,#06d6ba 100%);
--grad2:linear-gradient(135deg,#ec4899 0%,#8b5cf6 50%,#06d6ba 100%);
--gradInfo:linear-gradient(135deg,#3b82f6 0%,#8b5cf6 100%);
--shadow-sm:0 2px 8px rgba(139,92,246,.08);
--shadow-md:0 8px 32px rgba(139,92,246,.12);
--shadow-lg:0 20px 60px rgba(139,92,246,.2);
--glow:0 0 40px rgba(139,92,246,.4);
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{background:var(--bg);color:var(--fg);font-family:'Inter',-apple-system,Segoe UI,sans-serif;min-height:100vh;overflow-x:hidden}
/* Animated bg */
body::before{content:"";position:fixed;inset:0;background:
radial-gradient(ellipse at 20% 0%,rgba(139,92,246,.15),transparent 50%),
radial-gradient(ellipse at 80% 100%,rgba(6,214,186,.08),transparent 50%),
radial-gradient(ellipse at 50% 50%,rgba(236,72,153,.05),transparent 60%);
z-index:-1;pointer-events:none;animation:bgMove 20s ease-in-out infinite alternate}
@keyframes bgMove{0%{transform:scale(1)}100%{transform:scale(1.1) rotate(1deg)}}
header{padding:20px 32px;border-bottom:1px solid var(--bd);display:flex;align-items:center;justify-content:space-between;gap:20px;position:sticky;top:0;z-index:100;backdrop-filter:blur(24px) saturate(180%);background:rgba(7,10,21,.75);flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:14px}
.logo{width:44px;height:44px;border-radius:12px;background:var(--grad2);display:flex;align-items:center;justify-content:center;font-size:22px;box-shadow:var(--shadow-md);position:relative;overflow:hidden}
.logo::after{content:"";position:absolute;inset:0;background:linear-gradient(45deg,transparent 30%,rgba(255,255,255,.3) 50%,transparent 70%);animation:shimmer 3s infinite}
@keyframes shimmer{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}
h1{font-size:24px;font-weight:900;background:var(--grad2);-webkit-background-clip:text;-webkit-text-fill-color:transparent;letter-spacing:-.6px;line-height:1}
.sub{font-size:11px;color:var(--mg);margin-top:4px;display:flex;align-items:center;gap:10px}
.pulse-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--ok);animation:pulse 2s infinite;box-shadow:0 0 8px var(--ok)}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.6;transform:scale(1.3)}}
.nav{display:flex;gap:6px;flex-wrap:wrap}
.btn{padding:9px 14px;border-radius:10px;background:var(--card);border:1px solid var(--bd2);color:var(--fg);font-size:12px;font-weight:600;cursor:pointer;text-decoration:none;transition:all .2s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.btn:hover{background:var(--card-h);border-color:var(--ac);transform:translateY(-1px);box-shadow:var(--shadow-sm)}
.btn-primary{background:var(--grad);border:none;color:#fff;font-weight:700}
.btn-primary:hover{box-shadow:var(--glow)}
/* Hero stats */
.hero{max-width:1500px;margin:24px auto 0;padding:0 24px}
.hero-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:24px}
.stat-card{background:var(--card);border:1px solid var(--bd2);border-radius:16px;padding:18px;position:relative;overflow:hidden;transition:all .3s}
.stat-card:hover{transform:translateY(-3px);border-color:var(--ac);box-shadow:var(--shadow-md)}
.stat-card::before{content:"";position:absolute;top:-50%;right:-30%;width:200px;height:200px;border-radius:50%;opacity:.08;filter:blur(40px)}
.stat-card.c1::before{background:var(--ac)}
.stat-card.c2::before{background:var(--a2)}
.stat-card.c3::before{background:var(--wn)}
.stat-card.c4::before{background:var(--pk)}
.stat-card.c5::before{background:var(--inf)}
.stat-card.c6::before{background:var(--ok)}
.stat-val{font-size:32px;font-weight:900;line-height:1;letter-spacing:-1px}
.stat-val.g1{background:var(--grad);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-val.g2{background:linear-gradient(135deg,#06d6ba,#3b82f6);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-val.g3{background:linear-gradient(135deg,#fbbf24,#ec4899);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-val.g4{background:linear-gradient(135deg,#ec4899,#8b5cf6);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-val.g5{background:linear-gradient(135deg,#3b82f6,#06d6ba);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-val.g6{background:linear-gradient(135deg,#10b981,#06d6ba);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
.stat-lbl{font-size:10px;text-transform:uppercase;letter-spacing:2px;color:var(--mg);margin-top:8px;font-weight:700}
.stat-extra{font-size:11px;color:var(--hg);margin-top:6px;display:flex;align-items:center;gap:5px}
.stat-icon{width:30px;height:30px;border-radius:8px;background:rgba(139,92,246,.15);display:flex;align-items:center;justify-content:center;font-size:16px;margin-bottom:12px}
.up{color:var(--ok)} .dn{color:var(--er)}
/* Main grid */
main{max-width:1500px;margin:0 auto;padding:0 24px 40px;display:grid;grid-template-columns:260px 1fr 320px;gap:20px}
@media(max-width:1200px){main{grid-template-columns:220px 1fr;padding:0 16px 24px}.activity{display:none}}
@media(max-width:768px){main{grid-template-columns:1fr;padding:0 12px 24px}.sidebar{display:none}}
/* Sidebar cats */
.sidebar{position:sticky;top:110px;height:calc(100vh - 130px);overflow-y:auto;scrollbar-width:thin}
.sidebar::-webkit-scrollbar{width:4px}
.sidebar::-webkit-scrollbar-thumb{background:var(--bd2);border-radius:2px}
.panel{background:var(--card);border:1px solid var(--bd2);border-radius:14px;padding:16px;margin-bottom:14px;backdrop-filter:blur(10px)}
.panel-h{font-size:10px;text-transform:uppercase;letter-spacing:1.6px;color:var(--mg);margin-bottom:14px;font-weight:800;display:flex;align-items:center;gap:8px}
.cat-list{display:flex;flex-direction:column;gap:4px}
.cat-item{padding:9px 12px;border-radius:9px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;font-size:12px;font-weight:600;transition:all .15s;border:1px solid transparent}
.cat-item:hover{background:var(--card-h);border-color:var(--bd2)}
.cat-item.active{background:rgba(139,92,246,.12);color:var(--ac);border-color:rgba(139,92,246,.3)}
.cat-count{background:rgba(130,150,210,.08);padding:2px 8px;border-radius:10px;font-size:10px;color:var(--hg);font-weight:700;font-family:'JetBrains Mono',monospace}
.cat-item.active .cat-count{background:var(--ac);color:#fff}
/* Feed */
.feed{min-height:calc(100vh - 130px)}
.filter-bar{background:var(--card);border:1px solid var(--bd2);border-radius:14px;padding:14px;margin-bottom:18px;display:flex;gap:10px;align-items:center;flex-wrap:wrap;box-shadow:var(--shadow-sm)}
.search-wrap{flex:1;position:relative;min-width:240px}
.search-wrap::before{content:"🔍";position:absolute;left:14px;top:50%;transform:translateY(-50%);opacity:.5}
.search{width:100%;background:var(--bg2);border:1px solid var(--bd2);padding:10px 14px 10px 40px;border-radius:10px;color:var(--fg);font-size:13px;font-family:inherit;transition:all .2s}
.search:focus{outline:none;border-color:var(--ac);box-shadow:0 0 0 3px rgba(139,92,246,.15)}
.chip{padding:6px 12px;border-radius:8px;background:var(--bg2);border:1px solid var(--bd2);font-size:11px;cursor:pointer;color:var(--mg);font-weight:600;transition:all .15s;display:inline-flex;align-items:center;gap:5px}
.chip:hover{color:var(--fg);border-color:var(--ac)}
.chip.on{background:var(--grad);color:#fff;border-color:transparent}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:14px}
.agent-card{background:var(--card);border:1px solid var(--bd2);border-radius:14px;padding:18px;cursor:pointer;transition:all .25s;position:relative;overflow:hidden}
.agent-card::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:var(--cat-color,var(--ac));opacity:.6;transition:opacity .2s}
.agent-card::after{content:"";position:absolute;top:-30%;right:-30%;width:180px;height:180px;border-radius:50%;background:var(--cat-color,var(--ac));opacity:0;filter:blur(50px);transition:opacity .4s}
.agent-card:hover{transform:translateY(-4px);border-color:var(--cat-color,var(--ac));box-shadow:var(--shadow-md)}
.agent-card:hover::before{opacity:1}
.agent-card:hover::after{opacity:.15}
.agent-card>*{position:relative;z-index:1}
.agent-head{display:flex;align-items:flex-start;gap:12px;margin-bottom:12px}
.agent-avatar{width:46px;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:22px;flex-shrink:0;box-shadow:var(--shadow-sm);position:relative;background:var(--cat-color,var(--ac))}
.agent-avatar::after{content:"";position:absolute;inset:0;border-radius:12px;border:2px solid rgba(255,255,255,.1)}
.agent-name{font-size:15px;font-weight:800;color:var(--fg);margin-bottom:3px;letter-spacing:-.3px}
.agent-cat-lbl{font-size:10px;color:var(--mg);text-transform:uppercase;letter-spacing:.8px;font-weight:700;display:flex;align-items:center;gap:5px}
.agent-desc{font-size:12px;color:var(--hg);line-height:1.6;margin:8px 0 14px;min-height:38px}
.agent-metrics{display:flex;gap:6px;margin-bottom:12px;flex-wrap:wrap}
.metric-tag{font-size:9.5px;padding:3px 7px;background:var(--bg2);border-radius:5px;color:var(--mg);font-weight:600;font-family:'JetBrains Mono',monospace;border:1px solid var(--bd)}
.agent-status{display:flex;align-items:center;gap:6px;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:var(--ok)}
.agent-status.idle{color:var(--dm)}
.agent-status .status-dot{width:7px;height:7px;border-radius:50%;background:currentColor;animation:pulse 2s infinite;box-shadow:0 0 8px currentColor}
.agent-status.idle .status-dot{animation:none}
.agent-actions{display:flex;gap:6px;margin-top:14px;padding-top:14px;border-top:1px solid var(--bd)}
.act-btn{flex:1;padding:8px 10px;background:var(--bg2);border:1px solid var(--bd2);border-radius:8px;font-size:11px;color:var(--mg);cursor:pointer;transition:all .15s;text-align:center;font-weight:600;display:inline-flex;align-items:center;justify-content:center;gap:5px}
.act-btn:hover{background:var(--card-h);color:var(--ac);border-color:var(--ac);transform:scale(1.02)}
.act-btn.primary{background:var(--grad);color:#fff;border-color:transparent}
.act-btn.primary:hover{box-shadow:var(--glow)}
/* Activity right */
.activity{position:sticky;top:110px;height:calc(100vh - 130px);overflow-y:auto;scrollbar-width:thin}
.activity::-webkit-scrollbar{width:4px}
.activity::-webkit-scrollbar-thumb{background:var(--bd2);border-radius:2px}
.live-feed{max-height:360px;overflow-y:auto}
.live-item{padding:10px 12px;background:var(--bg2);border-radius:10px;margin-bottom:8px;border-left:3px solid var(--ac);font-size:11px;transition:all .2s;position:relative}
.live-item:hover{background:var(--card-h);transform:translateX(2px)}
.live-item-head{display:flex;justify-content:space-between;align-items:flex-start;gap:8px;margin-bottom:4px}
.live-item-msg{color:var(--fg);font-weight:500;line-height:1.45}
.live-item-meta{font-size:9px;color:var(--dm);margin-top:6px;display:flex;align-items:center;gap:6px}
.infra-list{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.infra-item{background:var(--bg2);padding:8px 10px;border-radius:8px;font-size:11px;font-weight:600;display:flex;justify-content:space-between;align-items:center}
.infra-item.ok{border-left:3px solid var(--ok)}
.infra-item.down{border-left:3px solid var(--er)}
.svc-dot{width:6px;height:6px;border-radius:50%;background:var(--ok);display:inline-block}
.svc-dot.down{background:var(--er)}
/* Modal chat - premium glass */
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,.82);z-index:1000;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(10px)}
.modal.on{display:flex;animation:modalIn .3s ease}
@keyframes modalIn{from{opacity:0}to{opacity:1}}
.modal-box{width:900px;max-width:100%;height:680px;max-height:92vh;background:var(--card);border-radius:20px;display:flex;flex-direction:column;overflow:hidden;box-shadow:var(--shadow-lg),0 0 60px rgba(139,92,246,.3);border:1px solid var(--bd2);animation:modalSlide .35s ease}
@keyframes modalSlide{from{transform:translateY(20px) scale(.98)}to{transform:translateY(0) scale(1)}}
.modal-head{padding:16px 22px;border-bottom:1px solid var(--bd2);display:flex;align-items:center;gap:14px;background:linear-gradient(180deg,rgba(139,92,246,.08),transparent)}
.modal-title{flex:1}
.modal-title-name{font-size:16px;font-weight:800;letter-spacing:-.3px}
.modal-title-sub{font-size:11px;color:var(--mg);margin-top:2px;display:flex;align-items:center;gap:6px}
.modal-close{background:var(--bg2);border:1px solid var(--bd2);color:var(--fg);font-size:18px;cursor:pointer;width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;transition:all .15s}
.modal-close:hover{background:var(--er);color:#fff;border-color:var(--er)}
.chat-area{flex:1;overflow-y:auto;padding:24px;display:flex;flex-direction:column;gap:12px;scrollbar-width:thin}
.chat-area::-webkit-scrollbar{width:6px}
.chat-area::-webkit-scrollbar-thumb{background:var(--bd2);border-radius:3px}
.msg{max-width:82%;padding:12px 16px;border-radius:16px;font-size:13px;line-height:1.6;word-wrap:break-word;animation:msgIn .3s ease}
@keyframes msgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.msg.u{background:var(--grad);color:#fff;align-self:flex-end;border-bottom-right-radius:4px;box-shadow:var(--shadow-sm)}
.msg.a{background:var(--bg2);border:1px solid var(--bd2);align-self:flex-start;border-bottom-left-radius:4px}
.msg.sys{background:rgba(251,191,36,.08);border:1px solid rgba(251,191,36,.25);color:var(--wn);align-self:center;font-size:11px;max-width:95%;text-align:center;padding:8px 14px}
.msg-meta{font-size:10px;color:var(--dm);margin-top:6px;display:flex;align-items:center;gap:6px}
.typing{display:none;align-self:flex-start;padding:12px 16px;background:var(--bg2);border-radius:16px;border:1px solid var(--bd2)}
.typing.on{display:block}
.typing span{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--ac);margin:0 2px;animation:typingDot 1.4s infinite}
.typing span:nth-child(2){animation-delay:.2s} .typing span:nth-child(3){animation-delay:.4s}
@keyframes typingDot{0%,60%,100%{transform:translateY(0);opacity:.4}30%{transform:translateY(-6px);opacity:1}}
.chat-input-bar{display:flex;gap:8px;padding:16px 22px;border-top:1px solid var(--bd2);background:rgba(7,10,21,.6)}
.chat-input{flex:1;background:var(--bg2);border:1px solid var(--bd2);padding:12px 16px;border-radius:12px;color:var(--fg);font-size:13px;font-family:inherit}
.chat-input:focus{outline:none;border-color:var(--ac);box-shadow:0 0 0 3px rgba(139,92,246,.15)}
.send-btn{padding:12px 22px;background:var(--grad);border:none;border-radius:12px;color:#fff;font-size:13px;font-weight:700;cursor:pointer;transition:all .15s;display:flex;align-items:center;gap:6px}
.send-btn:disabled{opacity:.5;cursor:wait}
.send-btn:not(:disabled):hover{box-shadow:var(--glow);transform:translateY(-1px)}
.loading-sk{background:linear-gradient(90deg,var(--card) 0%,var(--card-h) 50%,var(--card) 100%);background-size:200% 100%;animation:skeleton 1.5s infinite;border-radius:14px;height:180px}
@keyframes skeleton{0%{background-position:200% 0}100%{background-position:-200% 0}}
.empty{text-align:center;padding:40px;color:var(--dm);font-size:12px}
.heart{color:var(--er);animation:heart 1.5s infinite}
@keyframes heart{0%,100%{transform:scale(1)}50%{transform:scale(1.15)}}
/* Badge categories */
.cat-emoji{font-size:14px;line-height:1}
/* DOCTRINE 143 SSE badge */
#sse-live-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:9px;font-weight:700;letter-spacing:.5px;color:#fff;background:#64748b;vertical-align:middle;margin-left:8px}
@keyframes flash{0%{opacity:1}50%{opacity:.3}100%{opacity:1}}
#sse-health-pulse{font-size:10px;color:var(--a2);font-weight:600}
</style>
</head>
<body>
<header>
<div class="brand">
<div class="logo">☁️</div>
<div>
<h1>WEVIA Cloudbot Social</h1>
<div class="sub">
<span class="pulse-dot"></span>
<span id="hdr-status">Réseau vivant</span>
·
<span id="hdr-agents">726 agents</span>
·
<span id="hdr-score">-</span>
</div>
</div>
</div>
<nav class="nav">
<a class="btn" href="/all-ia-hub.html">🌐 All IA Hub</a>
<a class="btn" href="/wevia-meeting-rooms.html">🏛️ Meeting</a>
<a class="btn" href="/paperclip-flow.html" style="background:linear-gradient(135deg,#7c5cff,#4fd1c7);color:#fff;border:none">Paperclip Flow</a>
<a class="btn" href="/weval-live-ops.html" style="background:linear-gradient(135deg,#e94560,#c03350);color:#fff;border:none;font-weight:800">📊 Live Ops</a>
<a class="btn" href="/wevia-master.html">🧠 Master</a>
<a class="btn" href="/wevia-orchestrator.html">🎛️ Orchestrator</a>
<a class="btn btn-primary" href="/weval-technology-platform.html">⚡ WTP</a>
</nav>
</header>
<section class="hero">
<div class="hero-stats">
<div class="stat-card c1">
<div class="stat-icon">🤖</div>
<div class="stat-val g1" id="s-agents">726</div>
<div class="stat-lbl">Agents Network</div>
<div class="stat-extra"><span class="up"></span> 8 catégories actives</div>
</div>
<div class="stat-card c2">
<div class="stat-icon">🎯</div>
<div class="stat-val g2" id="s-intents">2215</div>
<div class="stat-lbl">Intents wired</div>
<div class="stat-extra"><span class="up"></span> <span id="s-score">-</span> Health</div>
</div>
<div class="stat-card c3">
<div class="stat-icon"></div>
<div class="stat-val g3" id="s-skills">694</div>
<div class="stat-lbl">Skills disponibles</div>
<div class="stat-extra">Registry <span id="s-catalog">-</span></div>
</div>
<div class="stat-card c4">
<div class="stat-icon">🧠</div>
<div class="stat-val g4" id="s-cognitive">635</div>
<div class="stat-lbl">Cognitive fn Opus46</div>
<div class="stat-extra">Qdrant <span id="s-qdrant">-</span> vecteurs</div>
</div>
<div class="stat-card c5">
<div class="stat-icon">💬</div>
<div class="stat-val g5" id="s-conv">0</div>
<div class="stat-lbl">Conversations session</div>
<div class="stat-extra"><span id="s-active">0</span> agents interrogés</div>
</div>
<div class="stat-card c6">
<div class="stat-icon">🛡️</div>
<div class="stat-val g6" id="s-nr">153/153</div>
<div class="stat-lbl">NonReg invariant</div>
<div class="stat-extra"><span class="up"></span> L99 <span id="s-l99">-</span></div>
</div>
</div>
</section>
<main>
<aside class="sidebar">
<div class="panel">
<div class="panel-h">📂 Catégories</div>
<div class="cat-list" id="cat-list">
<div class="cat-item active" data-cat="all">🌐 Tous <span class="cat-count">-</span></div>
</div>
</div>
<div class="panel">
<div class="panel-h">⚡ Actions rapides</div>
<div class="cat-list">
<div class="cat-item" onclick="startMultiAgent()">🎯 Broadcast N agents</div>
<div class="cat-item" onclick="askFavorites()">⭐ Ask my favorites</div>
<div class="cat-item" onclick="location.href='/wevia-meeting-rooms.html'">🏛️ Meeting Room</div>
<div class="cat-item" onclick="startCollab()">🤝 Collab 2 agents</div>
<div class="cat-item" onclick="sendToPaperclip()" style="border-top:1px solid var(--bd);margin-top:6px;padding-top:10px;color:var(--a2)">🚀 Déclencher Paperclip</div>
<div class="cat-item" onclick="viewPaperclipQueue()">📋 Queue Paperclip</div>
<div class="cat-item" onclick="location.href='/wevia-orchestrator.html'">🎛️ Orchestrator</div>
</div>
</div>
<div class="panel">
<div class="panel-h">🔥 Top agents</div>
<div id="top-agents" class="cat-list">
<div class="empty" style="padding:20px 0;font-size:11px">Chargement...</div>
</div>
</div>
</aside>
<section class="feed">
<div class="filter-bar">
<div class="search-wrap">
<input type="text" class="search" placeholder="Chercher agent (WEVIA, Ethica, Blade, Cortex, DeerFlow...)" id="q" oninput="renderAgents()">
</div>
<div class="chip on" data-st="all" onclick="filterStatus(this)">Tous</div>
<div class="chip" data-st="live" onclick="filterStatus(this)">🟢 LIVE</div>
<div class="chip" data-st="ready" onclick="filterStatus(this)">✓ Ready</div>
<div class="chip" onclick="sortBy('name')" id="sort-name">↕️ Nom</div>
<div class="chip" onclick="sortBy('cat')" id="sort-cat">📂 Cat</div>
</div>
<div class="grid" id="grid">
<div class="loading-sk"></div>
<div class="loading-sk"></div>
<div class="loading-sk"></div>
<div class="loading-sk"></div>
</div>
</section>
<aside class="activity">
<div class="panel">
<div class="panel-h">🔔 Feed LIVE (router)</div>
<div class="live-feed" id="live-feed">
<div class="empty" style="font-size:11px">Chargement...</div>
</div>
</div>
<div class="panel">
<div class="panel-h">🖥️ Infra live</div>
<div class="infra-list" id="infra-list">
<div class="empty" style="font-size:11px;grid-column:1/-1">Scan...</div>
</div>
</div>
<div class="panel">
<div class="panel-h">🎓 Training</div>
<div id="training-info" style="font-size:11px;line-height:1.7;color:var(--hg)">
<div class="empty" style="font-size:11px">Loading...</div>
</div>
</div>
</aside>
</main>
<!-- Modal chat premium -->
<div class="modal" id="chat-modal">
<div class="modal-box">
<div class="modal-head">
<div class="agent-avatar" id="m-avatar" style="width:44px;height:44px;font-size:20px">?</div>
<div class="modal-title">
<div class="modal-title-name" id="m-name">Agent</div>
<div class="modal-title-sub"><span class="pulse-dot"></span> <span id="m-api">Routing...</span></div>
</div>
<button class="act-btn" onclick="sendChatToPaperclip()" style="padding:6px 12px;margin-right:8px">🚀 Paperclip</button>
<button class="modal-close" onclick="closeModal()"></button>
</div>
<div class="chat-area" id="m-chat"></div>
<div class="typing" id="m-typing"><span></span><span></span><span></span></div>
<div class="chat-input-bar">
<input class="chat-input" id="m-input" placeholder="Pose une question..." onkeypress="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendMsg()}">
<button class="send-btn" id="m-send" onclick="sendMsg()">Envoyer ➤</button>
</div>
</div>
</div>
<script>
// ========== STATE ==========
var AGENTS=[], FILTERED=[], CURRENT_AGENT=null, STATUS_FILTER="all", CURRENT_CAT="all", SORT="default";
var CONV_COUNT=0, ACTIVE_AGENTS=new Set();
var UNIVERSAL_API="/api/weval-ia-fast.php";
var AGENT_APIS={
"wevia master":"/api/wevia-master-api.php",
"weval mind":"/api/hamid-api-proxy.php",
"weval manager":"/api/weval-manager.php",
"ethica":"/api/ethica-brain.php",
"bladerazor":"/api/blade-brain.php",
"blade":"/api/blade-brain.php",
"wevcode":"/api/wevcode-superclaude.php",
"wedroid":"/api/wedroid-brain-api.php",
"consensus":"/api/chat-proxy.php",
"claude":"/api/chat-proxy.php"
};
// Icons et couleurs par categorie (visuel vivant)
var CAT_META={
"core":{icon:"⚡",color:"#8b5cf6",label:"Core"},
"claudecode":{icon:"🔮",color:"#06d6ba",label:"Claude Code"},
"deerflow":{icon:"🦌",color:"#10b981",label:"DeerFlow"},
"hermes":{icon:"⚕️",color:"#fbbf24",label:"Hermes"},
"superclaude":{icon:"🧠",color:"#ec4899",label:"Superclaude"},
"skills":{icon:"🎯",color:"#06b6d4",label:"Skills"},
"business":{icon:"💼",color:"#3b82f6",label:"Business"},
"big4":{icon:"🏆",color:"#ef4444",label:"Big 4"}
};
function catMeta(cat){return CAT_META[cat]||{icon:"🤖",color:"#64748b",label:cat||"misc"}}
function getAgentAPI(agent){
var n=(agent.name||"").toLowerCase();
for(var k in AGENT_APIS){ if(n.indexOf(k)>=0)return AGENT_APIS[k]; }
return UNIVERSAL_API;
}
// ========== LOADERS ==========
async function loadAgents(){
try{
var r=await fetch("/api/agents-catalog-api.php");
var d=await r.json();
AGENTS=d.agents||[];
document.getElementById("s-agents").textContent=AGENTS.length.toLocaleString();
document.getElementById("hdr-agents").textContent=AGENTS.length.toLocaleString()+" agents";
document.getElementById("s-catalog").textContent=AGENTS.length;
renderCats(d.categories||{});
renderAgents();
renderTopAgents();
}catch(e){
document.getElementById("grid").innerHTML='<div class="empty">⚠️ '+e.message+'</div>';
}
}
async function loadHealth(){
try{
var r=await fetch("/api/ecosystem-health.php");
var d=await r.json();
if(d.score){document.getElementById("s-score").textContent=d.score;document.getElementById("hdr-score").textContent="Health "+d.score;}
if(d.l99){document.getElementById("s-l99").textContent=d.l99.pass+"/"+d.l99.total;}
if(d.ecosystem){
if(d.ecosystem.skills)document.getElementById("s-skills").textContent=d.ecosystem.skills.toLocaleString();
}
}catch(e){}
}
async function loadTraining(){
try{
var r=await fetch("/api/training-status.php");
var d=await r.json();
if(d.cognitive&&d.cognitive.fn)document.getElementById("s-cognitive").textContent=d.cognitive.fn;
if(d.intents&&d.intents.wired)document.getElementById("s-intents").textContent=d.intents.wired.toLocaleString();
if(d.qdrant&&d.qdrant.vectors!==undefined)document.getElementById("s-qdrant").textContent=d.qdrant.vectors;
// Panel training droit
var info=document.getElementById("training-info");
info.innerHTML='';
var addRow=function(icon,label,val){ info.innerHTML+='<div style="display:flex;justify-content:space-between;padding:4px 0"><span style="color:var(--mg)">'+icon+' '+label+'</span><strong style="color:var(--fg)">'+val+'</strong></div>'; };
if(d.hf_model)addRow("🤗","HF Model",'<span style="font-family:monospace;font-size:10px">'+d.hf_model+'</span>');
if(d.wiki&&d.wiki.entries)addRow("📚","Wiki",d.wiki.entries+" entries");
if(d.vault&&d.vault.files)addRow("🔐","Vault",d.vault.files+" files");
if(d.vault&&d.vault.gold)addRow("🥇","GOLD",d.vault.gold+" backups");
if(d.qdrant)addRow("🧬","Qdrant",(d.qdrant.vectors||0)+" vectors");
if(d.cron_training){
var crons=Object.keys(d.cron_training).map(function(k){return k+":"+d.cron_training[k]}).join(", ");
addRow("⏰","Crons",'<span style="color:var(--ok);font-size:10px">active x'+Object.keys(d.cron_training).length+'</span>');
}
}catch(e){}
}
async function loadInfra(){
try{
var r=await fetch("/api/infra-monitor-api.php");
var d=await r.json();
var list=document.getElementById("infra-list");
list.innerHTML='';
var servers=d.servers||{};
// Juste S204 services (les plus importants)
var s204=servers.s204||{};
var svcs=(s204.services||[]).slice(0,8);
svcs.forEach(function(s){
var cls=s.status==="active"?"ok":"down";
var dot=s.status==="active"?"":"down";
list.innerHTML+='<div class="infra-item '+cls+'"><span><span class="svc-dot '+dot+'"></span> '+s.name.substring(0,10)+'</span><span style="font-size:10px;color:var(--mg);font-family:monospace">'+(s.port||"")+'</span></div>';
});
}catch(e){ document.getElementById("infra-list").innerHTML='<div class="empty" style="grid-column:1/-1;font-size:11px">⚠️ offline</div>'; }
}
async function loadLiveFeed(){
try{
var r=await fetch("/api/router-activity.php?k=WEVADS2026&limit=10");
var d=await r.json();
var feed=document.getElementById("live-feed");
var matches=d.matches||[];
if(!matches.length){ feed.innerHTML='<div class="empty" style="font-size:11px">Pas d activité récente</div>'; return; }
feed.innerHTML=matches.slice(0,8).map(function(m){
var ago=timeAgo(m.ts);
var msg=(m.msg||"").substring(0,80);
return '<div class="live-item">'+
'<div class="live-item-head">'+
'<div class="live-item-msg">💭 '+escapeHtml(msg)+'</div>'+
'</div>'+
'<div class="live-item-meta">⏱ '+ago+' · <span style="font-family:monospace;opacity:.6">router</span></div>'+
'</div>';
}).join("");
}catch(e){}
}
// ========== RENDER ==========
function renderCats(cats){
var el=document.getElementById("cat-list");
el.innerHTML='<div class="cat-item active" data-cat="all" onclick="selectCat(\'all\',this)"><span><span class="cat-emoji">🌐</span> Tous</span><span class="cat-count">'+AGENTS.length+'</span></div>';
Object.keys(cats).sort(function(a,b){return cats[b]-cats[a]}).forEach(function(c){
var m=catMeta(c);
el.innerHTML+='<div class="cat-item" data-cat="'+c+'" onclick="selectCat(\''+c+'\',this)" style="--cat-color:'+m.color+'"><span><span class="cat-emoji">'+m.icon+'</span> '+m.label+'</span><span class="cat-count">'+cats[c]+'</span></div>';
});
}
function renderTopAgents(){
var el=document.getElementById("top-agents");
var top=AGENTS.slice(0,7);
el.innerHTML=top.map(function(a,i){
var m=catMeta(a.cat);
return '<div class="cat-item" onclick="openChat('+AGENTS.indexOf(a)+')" style="--cat-color:'+m.color+'">'+
'<span><span class="cat-emoji">'+(a.icon||m.icon)+'</span> '+(a.name||"?").substring(0,18)+'</span>'+
'<span class="cat-count" style="background:'+m.color+'22;color:'+m.color+'">'+m.label.substring(0,4)+'</span>'+
'</div>';
}).join("");
}
function selectCat(c,el){
CURRENT_CAT=c;
document.querySelectorAll(".cat-item[data-cat]").forEach(function(x){x.classList.remove("active")});
el.classList.add("active");
renderAgents();
}
function filterStatus(el){
STATUS_FILTER=el.dataset.st;
document.querySelectorAll(".filter-bar .chip[data-st]").forEach(function(x){x.classList.remove("on")});
el.classList.add("on");
renderAgents();
}
function sortBy(key){
SORT=key; renderAgents();
}
function renderAgents(){
var q=(document.getElementById("q").value||"").toLowerCase().trim();
FILTERED=AGENTS.filter(function(a){
if(CURRENT_CAT!=="all"&&a.cat!==CURRENT_CAT)return false;
if(STATUS_FILTER==="live"&&a.status!=="live"&&a.status!=="ready")return false;
if(STATUS_FILTER==="ready"&&a.status!=="ready")return false;
if(q&&!(a.name||"").toLowerCase().includes(q)&&!(a.desc||"").toLowerCase().includes(q))return false;
return true;
});
if(SORT==="name")FILTERED.sort(function(a,b){return(a.name||"").localeCompare(b.name||"")});
if(SORT==="cat")FILTERED.sort(function(a,b){return(a.cat||"").localeCompare(b.cat||"")});
var g=document.getElementById("grid");
if(!FILTERED.length){ g.innerHTML='<div class="empty" style="grid-column:1/-1">Aucun agent. Essaye "WEVIA" ou "Ethica"</div>'; return; }
var limit=60;
g.innerHTML=FILTERED.slice(0,limit).map(function(a){
var init=(a.name||"?").charAt(0).toUpperCase();
var m=catMeta(a.cat);
var statusCls=(a.status==="ready"||a.status==="live")?"":"idle";
var iconUsed=a.icon&&a.icon.length>=2?a.icon:init;
var idx=AGENTS.indexOf(a);
// Extract metriques de la desc si elle contient numbers
var metrics=[];
var desc=a.desc||"";
var nums=desc.match(/\d[\d,\/.]*/g)||[];
nums.slice(0,3).forEach(function(n){metrics.push(n)});
return '<div class="agent-card" style="--cat-color:'+m.color+'" onclick="openChat('+idx+')">'+
'<div class="agent-head">'+
'<div class="agent-avatar" style="background:linear-gradient(135deg,'+m.color+','+m.color+'cc)">'+iconUsed+'</div>'+
'<div style="flex:1;min-width:0">'+
'<div class="agent-name">'+escapeHtml(a.name||"?")+'</div>'+
'<div class="agent-cat-lbl"><span class="cat-emoji">'+m.icon+'</span> '+m.label+'</div>'+
'</div>'+
'</div>'+
'<div class="agent-desc">'+escapeHtml(desc||"Agent WEVAL")+'</div>'+
(metrics.length?'<div class="agent-metrics">'+metrics.map(function(x){return '<span class="metric-tag">'+x+'</span>'}).join("")+'</div>':'')+
'<div class="agent-status '+statusCls+'"><span class="status-dot"></span> '+(a.status||"ready").toUpperCase()+'</div>'+
'<div class="agent-actions" onclick="event.stopPropagation()">'+
'<button class="act-btn primary" onclick="openChat('+idx+')">💬 Chat</button>'+
'<button class="act-btn" onclick="askToAll(\''+escapeAttr(a.name)+'\')">📢 Broadcast</button>'+
'</div>'+
'</div>';
}).join("");
if(FILTERED.length>limit){ g.innerHTML+='<div class="empty" style="grid-column:1/-1;padding:20px">Affichage '+limit+'/'+FILTERED.length+' — affinez la recherche pour voir plus</div>'; }
}
// ========== CHAT ==========
function openChat(idx){
CURRENT_AGENT=AGENTS[idx];
if(!CURRENT_AGENT)return;
var m=catMeta(CURRENT_AGENT.cat);
ACTIVE_AGENTS.add(CURRENT_AGENT.name);
document.getElementById("s-active").textContent=ACTIVE_AGENTS.size;
document.getElementById("m-name").textContent=CURRENT_AGENT.name;
var av=document.getElementById("m-avatar");
av.textContent=(CURRENT_AGENT.icon&&CURRENT_AGENT.icon.length>=2)?CURRENT_AGENT.icon:(CURRENT_AGENT.name||"?").charAt(0).toUpperCase();
av.style.background="linear-gradient(135deg,"+m.color+","+m.color+"cc)";
var api=getAgentAPI(CURRENT_AGENT);
document.getElementById("m-api").textContent=m.label+" · "+api;
document.getElementById("m-chat").innerHTML='<div class="msg sys">🎉 Connecté à <strong>'+escapeHtml(CURRENT_AGENT.name)+'</strong><br><span style="font-size:10px;opacity:.7">'+escapeHtml(CURRENT_AGENT.desc||"")+'</span></div>';
document.getElementById("chat-modal").classList.add("on");
setTimeout(function(){document.getElementById("m-input").focus()},100);
}
function closeModal(){ document.getElementById("chat-modal").classList.remove("on"); }
async function sendMsg(){
var inp=document.getElementById("m-input");
var msg=inp.value.trim();
if(!msg||!CURRENT_AGENT)return;
var chat=document.getElementById("m-chat");
chat.innerHTML+='<div class="msg u">'+escapeHtml(msg)+'</div>';
inp.value="";
document.getElementById("m-send").disabled=true;
document.getElementById("m-typing").classList.add("on");
chat.scrollTop=chat.scrollHeight;
var api=getAgentAPI(CURRENT_AGENT);
var t0=Date.now();
try{
var r=await fetch(api,{
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify({message:msg,msg:msg,q:msg,provider:"cerebras",session_id:"cbsocial_"+Date.now(),caps:{kb:true,infra:true}})
});
var txt=await r.text();
var data;
try{ data=JSON.parse(txt); }catch(e){ data={response:txt.substring(0,600),error:"non-JSON"}; }
var reply=data.response||data.content||data.output||data.message||data.error||data.reply||"(réponse vide)";
if(typeof reply!=="string")reply=JSON.stringify(reply).substring(0,800);
var prov=data.provider||data.model||"unknown";
var ms=Date.now()-t0;
document.getElementById("m-typing").classList.remove("on");
chat.innerHTML+='<div class="msg a">'+escapeHtml(reply)+'<div class="msg-meta">⚡ '+escapeHtml(prov)+' · ⏱ '+ms+'ms</div></div>';
CONV_COUNT++;
document.getElementById("s-conv").textContent=CONV_COUNT;
}catch(e){
document.getElementById("m-typing").classList.remove("on");
chat.innerHTML+='<div class="msg sys">⚠️ '+escapeHtml(e.message)+'</div>';
}
document.getElementById("m-send").disabled=false;
chat.scrollTop=chat.scrollHeight;
}
// ========== ACTIONS ==========
function startMultiAgent(){
var q=prompt("❓ Question à broadcast (à 10 agents core+claudecode) :");
if(!q)return;
var sel=AGENTS.filter(function(a){return ["core","claudecode"].indexOf(a.cat)>=0}).slice(0,10);
sel.forEach(function(a,i){ setTimeout(function(){ openChat(AGENTS.indexOf(a)); document.getElementById("m-input").value=q; sendMsg(); setTimeout(closeModal,2500); }, i*3500); });
}
function askFavorites(){
var favs=["WEVIA Master","Ethica","Bladerazor","DeerFlow","Manager"];
var q=prompt("Question à poser à tes IA favorites (WEVIA Master, Ethica, Blade, DeerFlow, Manager) :");
if(!q)return;
var sel=[];
favs.forEach(function(n){ var a=AGENTS.find(function(x){return(x.name||"").toLowerCase().includes(n.toLowerCase())}); if(a)sel.push(a); });
sel.forEach(function(a,i){ setTimeout(function(){ openChat(AGENTS.indexOf(a)); document.getElementById("m-input").value=q; sendMsg(); setTimeout(closeModal,2500); }, i*3500); });
}
function askToAll(agentName){
var q=prompt("Question destinée à "+agentName+" (démarrage d un broadcast) :");
if(!q)return;
var a=AGENTS.find(function(x){return x.name===agentName});
if(a){ openChat(AGENTS.indexOf(a)); setTimeout(function(){ document.getElementById("m-input").value=q; sendMsg(); }, 300); }
}
function startCollab(){
var n1=prompt("Agent 1 (ex: WEVIA Master) :"); if(!n1)return;
var n2=prompt("Agent 2 (ex: Ethica) :"); if(!n2)return;
var topic=prompt("Sujet collab :"); if(!topic)return;
var a1=AGENTS.find(function(a){return(a.name||"").toLowerCase().includes(n1.toLowerCase())});
if(!a1){ alert("Agent "+n1+" non trouvé."); return; }
openChat(AGENTS.indexOf(a1));
setTimeout(function(){
document.getElementById("m-input").value="Analyse avec "+n2+" ce sujet : "+topic;
sendMsg();
},400);
}
// ========== UTILS ==========
function escapeHtml(s){ var d=document.createElement("div"); d.textContent=(s==null?"":String(s)); return d.innerHTML.replace(/\n/g,"<br>"); }
function escapeAttr(s){ return String(s||"").replace(/'/g,"").replace(/"/g,"").substring(0,40); }
function timeAgo(ts){
try{
var t=new Date(ts);
var s=Math.floor((Date.now()-t)/1000);
if(s<60)return s+"s";
if(s<3600)return Math.floor(s/60)+"min";
if(s<86400)return Math.floor(s/3600)+"h";
return Math.floor(s/86400)+"j";
}catch(e){return ts||""}
}
// ========== INIT + LIVE REFRESH ==========
loadAgents();
loadHealth();
loadTraining();
loadInfra();
loadLiveFeed();
// Rafraichissement toutes les 30s (feed live + infra)
setInterval(function(){ loadLiveFeed(); loadInfra(); }, 30000);
setInterval(function(){ loadHealth(); loadTraining(); }, 90000);
// Focus sur recherche avec /
document.addEventListener("keydown",function(e){
if(e.key==="/"&&document.activeElement.tagName!=="INPUT"){ e.preventDefault(); document.getElementById("q").focus(); }
if(e.key==="Escape"&&document.getElementById("chat-modal").classList.contains("on")){ closeModal(); }
});
// ============ DOCTRINE 143 LIVE SSE STREAMING v1 (additif) ============
var __SSE_ES = null;
var __SSE_CONN = false;
var __SSE_EVENTS = [];
function connectSSELive(){
if(__SSE_ES && __SSE_CONN)return;
try{
__SSE_ES = new EventSource("/api/cloudbot-social-feed.php");
__SSE_ES.addEventListener("hello", function(e){
__SSE_CONN = true;
try{
var d = JSON.parse(e.data);
console.log("[SSE Cloudbot] Connected", d);
var badge = document.getElementById("sse-live-badge");
if(badge){ badge.textContent = "LIVE"; badge.style.background = "#10b981"; badge.style.animation = "pulse 1.5s infinite"; }
}catch(ex){}
});
__SSE_ES.addEventListener("router_match", function(e){
try{
var d = JSON.parse(e.data);
pushSSEEvent({type:"router", msg:d.msg, ts:d.ts, pattern:d.pattern, agent:d.agent||"Router"});
}catch(ex){}
});
__SSE_ES.addEventListener("agent_msg", function(e){
try{
var d = JSON.parse(e.data);
pushSSEEvent({type:"conversation", role:d.role, msg:d.content, ts:d.ts, session:d.session, source:d.source, agent:d.agent});
}catch(ex){}
});
__SSE_ES.addEventListener("ecosystem_health", function(e){
try{
var d = JSON.parse(e.data);
var h = document.getElementById("sse-health-pulse");
if(h){ h.textContent = (d.agents_up||"-") + "/" + (d.agents_total||"-") + " agents"; h.style.animation = "flash 0.5s"; setTimeout(function(){h.style.animation=""},500);}
}catch(ex){}
});
__SSE_ES.addEventListener("ping", function(e){ /* keep alive */ });
__SSE_ES.addEventListener("bye", function(e){
__SSE_CONN = false;
if(__SSE_ES){ __SSE_ES.close(); __SSE_ES = null; }
setTimeout(connectSSELive, 2000); // auto reconnect
});
__SSE_ES.onerror = function(){
__SSE_CONN = false;
var badge = document.getElementById("sse-live-badge");
if(badge){ badge.textContent = "RECONNECT..."; badge.style.background = "#f59e0b"; }
setTimeout(function(){
if(__SSE_ES){ __SSE_ES.close(); __SSE_ES = null; }
connectSSELive();
}, 3000);
};
}catch(e){ console.warn("SSE init failed:", e); }
}
function pushSSEEvent(ev){
__SSE_EVENTS.unshift(ev);
if(__SSE_EVENTS.length > 50) __SSE_EVENTS = __SSE_EVENTS.slice(0, 50);
renderSSEFeed();
}
function renderSSEFeed(){
var feed = document.getElementById("live-feed");
if(!feed)return;
if(!__SSE_EVENTS.length){ return; }
var html = __SSE_EVENTS.slice(0, 12).map(function(ev){
var ago = timeAgo(ev.ts);
var icon = ev.type === "conversation" ? (ev.role === "user" ? "👤" : "🤖") : (ev.type === "router" ? "🎯" : "⚡");
var color = ev.type === "conversation" ? "#06d6ba" : (ev.type === "router" ? "#8b5cf6" : "#3b82f6");
var label = ev.agent || (ev.role === "user" ? "User" : "WEVIA");
var msg = (ev.msg||"").substring(0, 120);
var meta = ev.session ? "session " + ev.session : (ev.source ? "src:"+ev.source : (ev.pattern||"live"));
return '<div class="live-item" style="border-left-color:'+color+'">'+
'<div class="live-item-head">'+
'<div class="live-item-msg">'+icon+' <strong style="color:'+color+'">'+escapeHtml(label)+':</strong> '+escapeHtml(msg)+'</div>'+
'</div>'+
'<div class="live-item-meta">🕐 '+ago+' · <span style="font-family:monospace;opacity:.7">'+escapeHtml(meta)+'</span></div>'+
'</div>';
}).join("");
feed.innerHTML = html;
}
// Start SSE on page load
setTimeout(connectSSELive, 1000);
// ============ END SSE additif ============
function startCollab(){
// DOCTRINE 143 - Real inter-agent conversation via /api/cloudbot-interagent.php
var n1 = prompt("Nom agent 1 (ex: WEVIA, Ethica, WEVCODE, Blade, WEDROID, Manager, WEVAL MIND) :");
if(!n1) return;
var n2 = prompt("Nom agent 2 (different du premier) :");
if(!n2) return;
var topic = prompt("Topic de collaboration (question/sujet a discuter) :");
if(!topic) return;
var turns = prompt("Nombre de tours (2-4 recommande, max 6) :", "3");
turns = Math.min(6, Math.max(1, parseInt(turns)||3));
openInterAgentModal(n1, n2, topic, turns);
}
function openInterAgentModal(agent1, agent2, topic, turns){
var modal = document.getElementById("chat-modal");
document.getElementById("m-title").textContent = "🤝 "+agent1+" ↔ "+agent2;
document.getElementById("m-avatar").textContent = "🤝";
document.getElementById("m-avatar").style.background = "linear-gradient(135deg,#ec4899,#8b5cf6,#06d6ba)";
var chat = document.getElementById("m-chat");
chat.innerHTML = '<div class="msg sys">🤝 <strong>Conversation inter-agents en cours</strong> · '+agent1+' ↔ '+agent2+' · Topic: '+escapeHtml(topic)+' · '+turns+' tours</div>';
chat.innerHTML += '<div class="msg sys">⏳ Initialisation... (peut prendre 30-60 sec selon les APIs agents)</div>';
modal.classList.add("on");
document.getElementById("m-input").placeholder = "Conversation auto - attendez les reponses...";
document.getElementById("m-input").disabled = true;
document.getElementById("m-send").disabled = true;
fetch("/api/cloudbot-interagent.php", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({agent1: agent1, agent2: agent2, topic: topic, turns: turns})
}).then(function(r){ return r.json(); }).then(function(data){
chat.innerHTML = '<div class="msg sys">🤝 <strong>'+agent1+' ↔ '+agent2+'</strong> · Topic: '+escapeHtml(topic)+' · '+(data.turns_completed||0)+' tours</div>';
if(!data.dialogue || !data.dialogue.length){
chat.innerHTML += '<div class="msg sys" style="color:#ef4444">⚠️ Aucun dialogue (agent non trouve ou erreur API)</div>';
if(data.error) chat.innerHTML += '<div class="msg sys">ERR: '+escapeHtml(data.error)+'</div>';
document.getElementById("m-input").disabled = false;
document.getElementById("m-send").disabled = false;
return;
}
data.dialogue.forEach(function(t){
// Question de from -> to
chat.innerHTML += '<div class="msg u" style="max-width:85%"><div style="font-size:11px;font-weight:700;opacity:.9;margin-bottom:4px">🎯 '+escapeHtml(t.from)+' → '+escapeHtml(t.to)+' (tour '+t.turn+')</div>'+escapeHtml(t.message)+'</div>';
// Reponse
chat.innerHTML += '<div class="msg a"><div style="font-size:11px;font-weight:700;color:#06d6ba;margin-bottom:4px">🤖 '+escapeHtml(t.to)+' repond :</div>'+escapeHtml(t.response)+'<div class="msg-meta">via '+escapeHtml(t.provider)+' · '+t.latency_ms+'ms</div></div>';
});
chat.innerHTML += '<div class="msg sys">✅ Conversation terminee · '+(data.logged_to_db?"📝 loggee en PG (visible dans SSE feed)":"")+' · Session: '+(data.session_id||"").substring(0,30)+'</div>';
chat.scrollTop = chat.scrollHeight;
document.getElementById("m-input").disabled = false;
document.getElementById("m-send").disabled = false;
addActivity("🤝 Inter-Agent: "+agent1+" ↔ "+agent2+" sur "+topic.substring(0,30));
CONV_COUNT += data.dialogue.length;
var kc = document.getElementById("k-conv");
if(kc) kc.textContent = CONV_COUNT;
}).catch(function(e){
chat.innerHTML += '<div class="msg sys" style="color:#ef4444">⚠️ '+escapeHtml(e.message)+'</div>';
document.getElementById("m-input").disabled = false;
document.getElementById("m-send").disabled = false;
});
}
// === PAPERCLIP BRIDGE (real execution) ===
async function sendToPaperclip(){
var action = prompt("Action concrete pour Paperclip (ex: analyser logs nginx):");
if(!action) return;
var prmpt = prompt("Prompt detaille (instructions techniques):");
if(!prmpt) return;
try{
var r = await fetch("/api/paperclip-bridge.php", {
method:"POST",
headers:{"Content-Type":"application/json"},
body: JSON.stringify({source:"cloudbot-social",action:action,prompt:prmpt,agents_discussed: CURRENT_AGENT ? [CURRENT_AGENT.name] : ["Cloudbot Social"]})
});
var d = await r.json();
if(d.ok){
addActivity("Paperclip queued: " + action);
alert("OK! Action envoyee a Paperclip.\nID: " + d.id + "\nStatus: " + d.status);
} else alert("Erreur: " + (d.error || "fail"));
} catch(e){ alert("Erreur: " + e.message); }
}
async function viewPaperclipQueue(){
try{
var r = await fetch("/api/paperclip-bridge.php?action=list&limit=20");
var d = await r.json();
if(!d.ok || !d.actions || !d.actions.length){
alert("Queue Paperclip vide. Declenchez une action d abord.");
return;
}
var msg = "Queue Paperclip (" + d.count + " actions)\n\n";
d.actions.forEach(function(a){
msg += "[" + a.status + "] " + (a.reason||"").substring(0, 70) + "\n";
});
alert(msg);
} catch(e){ alert("Erreur: " + e.message); }
}
function sendChatToPaperclip(){
if(!CURRENT_AGENT) return;
var chat = document.getElementById("m-chat");
var msgs = Array.from(chat.querySelectorAll(".msg")).map(function(m){
return (m.classList.contains("u") ? "[USER] " : "[AGENT] ") + m.textContent.substring(0, 400);
}).join("\n\n");
if(!msgs){ alert("Aucune conversation."); return; }
var action = prompt("Action a executer par Paperclip:");
if(!action) return;
fetch("/api/paperclip-bridge.php", {
method:"POST",
headers:{"Content-Type":"application/json"},
body: JSON.stringify({source:"cloudbot-social",action:action,prompt:"Context chat avec " + CURRENT_AGENT.name + ":\n" + msgs + "\n\nAction: " + action,agents_discussed:[CURRENT_AGENT.name]})
}).then(function(r){return r.json()}).then(function(d){
if(d.ok){ addActivity("Chat->Paperclip: " + action.substring(0,40)); alert("Envoye! ID: " + d.id); }
else alert("Fail: " + (d.error||"?"));
});
}
</script>
</body>
</html>