Files
APAW/agent-evolution/index.standalone.html
¨NW¨ 3badb259cc feat: bidirectional research dashboard + agent config fixes
- Integrate apaw_agent_model_research_v3.html as standalone dashboard
- Add model-benchmarks.json with 32 agents, 11 scored models, 11 recommendations
- Add build-research-dashboard.ts: inject live data into template → standalone HTML
- Add rebuild-template.cjs: regenerate template from v3.html source
- Add sync-benchmarks-from-yaml.cjs: sync YAML → JSON round-trip
- Add sync-model-research.ts: apply recommendation matrix to config files
- Add model-benchmarks.schema.json and model-research.schema.json for validation
- Add bidirectional-data-flow.md architecture documentation
- Add log-execution.cjs pipeline hook
- Update capability-index.yaml: add fallback_models, failover_strategy
- Update kilo-meta.json, kilo.jsonc, KILO_SPEC.md with synced models
- Update evolution.md / research.md / self-evolution.md / evolutionary-sync.md docs
- Fix security-auditor.md: quote YAML color (#DC2626)
- Fix orchestrator.md: remove duplicate devops-engineer key
- Build research-dashboard.html (106KB standalone) + dated archive
2026-04-29 21:04:22 +01:00

1998 lines
66 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>APAW Agent Evolution Dashboard</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<style>
:root {
--bg-deep: #0a0f1a;
--bg-panel: #0f1525;
--bg-card: #141c2e;
--bg-card-hover: #1a2540;
--border: #1e2d45;
--border-bright: #2a4060;
--text-primary: #e8f1ff;
--text-secondary: #8ba3c0;
--text-muted: #5a7090;
--accent-cyan: #00d4ff;
--accent-green: #00ff94;
--accent-orange: #ff9f43;
--accent-red: #ff4757;
--accent-purple: #a855f7;
--accent-blue: #3b82f6;
--accent-yellow: #facc15;
--glow-cyan: rgba(0,212,255,0.15);
--glow-green: rgba(0,255,148,0.1);
--glow-purple: rgba(168,85,247,0.1);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', sans-serif;
background: var(--bg-deep);
color: var(--text-primary);
min-height: 100vh;
}
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 20% 20%, rgba(0,212,255,0.08) 0%, transparent 50%),
radial-gradient(ellipse at 80% 80%, rgba(168,85,247,0.06) 0%, transparent 50%);
pointer-events: none;
z-index: 0;
}
.container {
max-width: 1600px;
margin: 0 auto;
padding: 24px 16px;
position: relative;
z-index: 1;
}
/* Header */
.header { text-align: center; margin-bottom: 32px; }
.header h1 {
font-size: 2.2em;
font-weight: 800;
background: linear-gradient(135deg, var(--accent-cyan), var(--accent-green));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 8px;
}
.header .sub {
font-family: 'JetBrains Mono', monospace;
font-size: 0.85em;
color: var(--text-muted);
}
.header .meta {
display: flex;
justify-content: center;
gap: 24px;
margin-top: 12px;
font-size: 0.8em;
color: var(--text-secondary);
}
/* Tabs */
.tabs {
display: flex;
gap: 4px;
background: var(--bg-panel);
border: 1px solid var(--border);
border-radius: 12px;
padding: 4px;
margin-bottom: 24px;
overflow-x: auto;
}
.tab-btn {
flex: 1;
min-width: 100px;
padding: 10px 16px;
background: none;
border: none;
color: var(--text-secondary);
font-family: 'Inter', sans-serif;
font-size: 0.85em;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
transition: all 0.25s;
white-space: nowrap;
}
.tab-btn:hover { color: var(--text-primary); background: var(--bg-card); }
.tab-btn.active {
color: var(--bg-deep);
background: linear-gradient(135deg, var(--accent-cyan), var(--accent-green));
box-shadow: 0 0 20px var(--glow-cyan);
}
.tab-panel { display: none; animation: fadeUp 0.4s ease-out; }
.tab-panel.active { display: block; }
@keyframes fadeUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
/* Stats */
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 14px;
margin-bottom: 24px;
}
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 18px;
position: relative;
overflow: hidden;
transition: all 0.3s;
}
.stat-card:hover {
border-color: var(--accent-cyan);
transform: translateY(-2px);
box-shadow: 0 8px 32px var(--glow-cyan);
}
.stat-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.65em;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 6px;
}
.stat-value { font-size: 2em; font-weight: 800; }
.stat-sub { font-size: 0.75em; color: var(--text-secondary); margin-top: 4px; }
.grad-cyan { background: linear-gradient(135deg, var(--accent-cyan), var(--accent-green)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.grad-orange { background: linear-gradient(135deg, var(--accent-orange), var(--accent-yellow)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.grad-purple { background: linear-gradient(135deg, var(--accent-purple), #e879f9); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.grad-green { background: linear-gradient(135deg, var(--accent-green), #4ade80); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.grad-red { background: linear-gradient(135deg, var(--accent-red), #ff6b81); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
/* Agent Grid */
.agents-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: 16px;
}
.agent-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
transition: all 0.3s;
position: relative;
overflow: hidden;
}
.agent-card:hover {
border-color: var(--accent-cyan);
transform: translateY(-2px);
box-shadow: 0 8px 32px var(--glow-cyan);
}
.agent-card.has-history { border-left: 3px solid var(--accent-green); }
.agent-card.needs-update { border-left: 3px solid var(--accent-orange); }
.agent-card.is-new { border-left: 3px solid var(--accent-purple); }
.agent-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 12px;
}
.agent-name {
font-weight: 700;
font-size: 1.05em;
display: flex;
align-items: center;
gap: 8px;
}
.agent-color {
width: 12px;
height: 12px;
border-radius: 3px;
flex-shrink: 0;
}
.agent-category {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7em;
padding: 3px 8px;
border-radius: 12px;
background: rgba(0,212,255,0.1);
color: var(--accent-cyan);
}
.agent-model {
font-family: 'JetBrains Mono', monospace;
font-size: 0.78em;
color: var(--accent-green);
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
.agent-provider {
font-size: 0.7em;
padding: 2px 6px;
border-radius: 4px;
background: rgba(0,255,148,0.1);
color: var(--accent-green);
}
.agent-desc {
font-size: 0.85em;
color: var(--text-secondary);
line-height: 1.5;
margin-bottom: 12px;
}
.agent-meta {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
padding-top: 12px;
border-top: 1px solid var(--border);
}
.agent-meta-item {
text-align: center;
}
.agent-meta-label {
font-size: 0.6em;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.agent-meta-value {
font-family: 'JetBrains Mono', monospace;
font-size: 0.9em;
font-weight: 600;
color: var(--text-primary);
}
.agent-history {
margin-top: 12px;
padding-top: 12px;
border-top: 1px dashed var(--border);
}
.history-title {
font-size: 0.7em;
color: var(--text-muted);
text-transform: uppercase;
margin-bottom: 8px;
}
.history-item {
display: flex;
align-items: center;
gap: 10px;
font-size: 0.75em;
padding: 6px 0;
border-bottom: 1px solid rgba(30,45,69,0.5);
}
.history-item:last-child { border-bottom: none; }
.history-date {
font-family: 'JetBrains Mono', monospace;
color: var(--text-muted);
min-width: 100px;
}
.history-type {
padding: 2px 6px;
border-radius: 4px;
font-size: 0.85em;
}
.history-type.model_change { background: rgba(0,212,255,0.15); color: var(--accent-cyan); }
.history-type.prompt_change { background: rgba(168,85,247,0.15); color: var(--accent-purple); }
.history-type.agent_created { background: rgba(0,255,148,0.15); color: var(--accent-green); }
/* Category Section */
.category-section { margin-bottom: 32px; }
.category-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border);
}
.category-title {
font-size: 1.1em;
font-weight: 700;
}
.category-count {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7em;
padding: 3px 8px;
border-radius: 12px;
background: rgba(168,85,247,0.15);
color: var(--accent-purple);
}
/* Evolution Timeline */
.timeline-wrap {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin-bottom: 24px;
}
.timeline-title {
font-size: 1.1em;
font-weight: 700;
margin-bottom: 16px;
}
.timeline {
position: relative;
padding-left: 24px;
}
.timeline::before {
content: '';
position: absolute;
left: 8px;
top: 0;
bottom: 0;
width: 2px;
background: var(--border);
}
.timeline-item {
position: relative;
padding: 12px 0 12px 24px;
border-bottom: 1px solid var(--border);
}
.timeline-item:last-child { border-bottom: none; }
.timeline-item::before {
content: '';
position: absolute;
left: -20px;
top: 18px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--accent-cyan);
border: 2px solid var(--border);
}
.timeline-date {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75em;
color: var(--text-muted);
}
.timeline-content {
font-size: 0.9em;
margin-top: 4px;
}
.timeline-agent {
font-weight: 600;
color: var(--accent-cyan);
}
.timeline-change {
color: var(--text-secondary);
}
/* Filter Row */
.filter-row {
display: flex;
gap: 8px;
flex-wrap: wrap;
margin-bottom: 16px;
}
.filter-btn {
padding: 6px 14px;
background: var(--bg-card);
border: 1px solid var(--border);
color: var(--text-secondary);
border-radius: 20px;
font-size: 0.8em;
cursor: pointer;
transition: all 0.2s;
font-family: 'Inter', sans-serif;
}
.filter-btn:hover, .filter-btn.active {
border-color: var(--accent-cyan);
color: var(--accent-cyan);
background: rgba(0,212,255,0.05);
}
/* Search */
.search-box {
position: relative;
margin-bottom: 20px;
}
.search-input {
width: 100%;
padding: 12px 16px 12px 40px;
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-primary);
font-family: 'Inter', sans-serif;
font-size: 0.9em;
}
.search-input:focus {
outline: none;
border-color: var(--accent-cyan);
}
.search-icon {
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
}
/* Model Matrix */
.matrix-wrap {
overflow-x: auto;
border-radius: 12px;
border: 1px solid var(--border);
background: var(--bg-card);
padding: 20px;
}
.matrix-title {
font-size: 1.1em;
font-weight: 700;
margin-bottom: 16px;
}
.matrix-table {
width: 100%;
border-collapse: collapse;
font-size: 0.8em;
}
.matrix-table th {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7em;
color: var(--text-muted);
text-transform: uppercase;
padding: 10px 8px;
text-align: left;
border-bottom: 2px solid var(--border);
position: sticky;
top: 0;
background: var(--bg-panel);
}
.matrix-table td {
padding: 10px 8px;
border-bottom: 1px solid var(--border);
}
.matrix-table tr:hover td {
background: var(--bg-card-hover);
}
.score-bar {
display: flex;
align-items: center;
gap: 6px;
}
.score-bg {
width: 50px;
height: 5px;
background: var(--border);
border-radius: 3px;
overflow: hidden;
}
.score-fill {
height: 100%;
border-radius: 3px;
}
.score-fill.high { background: linear-gradient(90deg, var(--accent-green), #00ff94); }
.score-fill.medium { background: linear-gradient(90deg, var(--accent-orange), #ffc048); }
.score-fill.low { background: linear-gradient(90deg, var(--accent-red), #ff6b81); }
/* Export */
.actions-row {
display: flex;
gap: 10px;
margin-bottom: 20px;
}
.action-btn {
padding: 8px 16px;
background: var(--bg-card);
border: 1px solid var(--border);
color: var(--text-primary);
border-radius: 8px;
font-family: 'Inter', sans-serif;
font-size: 0.85em;
cursor: pointer;
transition: all 0.25s;
display: inline-flex;
align-items: center;
gap: 8px;
}
.action-btn:hover {
border-color: var(--accent-cyan);
color: var(--accent-cyan);
}
.action-btn.primary {
background: linear-gradient(135deg, rgba(0,212,255,0.15), rgba(0,255,148,0.1));
border-color: var(--accent-cyan);
color: var(--accent-cyan);
}
.action-btn.primary:hover {
box-shadow: 0 0 20px var(--glow-cyan);
}
/* Modal */
.modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0,0,0,0.7);
z-index: 9999;
justify-content: center;
align-items: center;
padding: 20px;
}
.modal.show { display: flex; }
.modal-content {
background: var(--bg-panel);
border: 1px solid var(--accent-cyan);
border-radius: 14px;
max-width: 900px;
width: 100%;
max-height: 85vh;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 18px 22px;
border-bottom: 1px solid var(--border);
}
.modal-title { font-weight: 700; font-size: 1.05em; }
.modal-actions { display: flex; gap: 8px; }
.modal-body {
flex: 1;
overflow: auto;
padding: 18px 22px;
}
.modal-pre {
font-family: 'JetBrains Mono', monospace;
font-size: 0.78em;
line-height: 1.6;
color: var(--accent-green);
white-space: pre-wrap;
}
@media (max-width: 768px) {
.header h1 { font-size: 1.5em; }
.tabs { flex-wrap: wrap; }
.agents-grid { grid-template-columns: 1fr; }
.stats-row { grid-template-columns: repeat(2, 1fr); }
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>APAW Agent Evolution</h1>
<div class="sub">Real-time agent model & performance tracking</div>
<div class="meta">
<span id="lastSync">Loading...</span>
<span></span>
<span id="agentCount">0 agents</span>
<span></span>
<span id="historyCount">0 with history</span>
</div>
</div>
<div class="tabs" id="tabBar">
<button class="tab-btn active" onclick="switchTab('overview')">Overview</button>
<button class="tab-btn" onclick="switchTab('agents')">All Agents</button>
<button class="tab-btn" onclick="switchTab('history')">Timeline</button>
<button class="tab-btn" onclick="switchTab('recommendations')">Recommendations</button>
<button class="tab-btn" onclick="switchTab('matrix')">Model Matrix</button>
</div>
<!-- Overview Tab -->
<div id="tab-overview" class="tab-panel active">
<div class="stats-row" id="statsRow"></div>
<div class="category-section">
<div class="category-header">
<h2 class="category-title">Recent Changes</h2>
<span class="category-count" id="recentCount">0</span>
</div>
<div class="timeline-wrap">
<div class="timeline" id="recentTimeline"></div>
</div>
</div>
<div class="category-section">
<div class="category-header">
<h2 class="category-title">Pending Recommendations</h2>
<span class="category-count" id="recCount">0</span>
</div>
<div class="agents-grid" id="recAgents"></div>
</div>
</div>
<!-- All Agents Tab -->
<div id="tab-agents" class="tab-panel">
<div class="search-box">
<span class="search-icon">🔍</span>
<input type="text" class="search-input" id="agentSearch" placeholder="Search agents..." oninput="filterAgents()">
</div>
<div class="filter-row">
<button class="filter-btn active" onclick="filterCategory('all')">All</button>
<button class="filter-btn" onclick="filterCategory('Core Dev')">Core Dev</button>
<button class="filter-btn" onclick="filterCategory('QA')">QA</button>
<button class="filter-btn" onclick="filterCategory('Security')">Security</button>
<button class="filter-btn" onclick="filterCategory('Analysis')">Analysis</button>
<button class="filter-btn" onclick="filterCategory('Process')">Process</button>
<button class="filter-btn" onclick="filterCategory('Cognitive')">Cognitive</button>
</div>
<div id="agentsByCategory"></div>
</div>
<!-- History Tab -->
<div id="tab-history" class="tab-panel">
<div class="timeline-wrap">
<h2 class="timeline-title">Evolution Timeline</h2>
<div class="timeline" id="fullTimeline"></div>
</div>
</div>
<!-- Recommendations Tab -->
<div id="tab-recommendations" class="tab-panel">
<div class="actions-row">
<button class="action-btn primary" onclick="exportRecommendations()">
<span>📥</span> Export JSON
</button>
</div>
<div class="agents-grid" id="allRecommendations"></div>
</div>
<!-- Matrix Tab -->
<div id="tab-matrix" class="tab-panel">
<div class="matrix-wrap">
<h2 class="matrix-title">Agent × Model Matrix</h2>
<table class="matrix-table" id="matrixTable">
<thead id="matrixHead"></thead>
<tbody id="matrixBody"></tbody>
</table>
</div>
</div>
</div>
<!-- Export Modal -->
<div class="modal" id="exportModal">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">Export Recommendations</div>
<div class="modal-actions">
<button class="action-btn" onclick="copyToClipboard()">📋 Copy</button>
<button class="action-btn primary" onclick="downloadJSON()">⬇ Download</button>
<button class="action-btn" onclick="closeModal()" style="border-color: #ff4757; color: #ff6b81;"></button>
</div>
</div>
<div class="modal-body">
<pre class="modal-pre" id="exportContent"></pre>
</div>
</div>
</div>
<script>
// Agent Evolution Dashboard
// Supports both server and file:// mode
let agentData = {};
// Embedded data (generated 2026-04-27T20:28:59.112Z)
const EMBEDDED_DATA = {
"version": "1.0.0",
"lastUpdated": "2026-04-27T20:28:58.592Z",
"agents": {
"lead-developer": {
"current": {
"description": "Primary code writer for backend and core logic. Writes implementation to pass tests",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#DC2626\"",
"category": "General",
"capabilities": [
"code_writing",
"refactoring",
"bug_fixing",
"implementation"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": null,
"to": "ollama-cloud/qwen3-coder:480b",
"reason": "Initial configuration from capability-index.yaml",
"source": "git"
},
{
"date": "2026-04-27T16:56:09.013Z",
"commit": "model-research-sync",
"type": "model_change",
"from": "ollama-cloud/qwen3-coder:480b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Nemotron 3 Super has better reasoning for core development tasks and RULER@1M context window. SWE-bench 68% vs Qwen's 66.5%.",
"source": "research"
},
{
"date": "2026-04-27T20:28:58.592Z",
"commit": "model-research-sync",
"type": "model_change",
"from": "ollama-cloud/qwen3-coder:480b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Nemotron 3 Super has better reasoning for core development tasks and RULER@1M context window. SWE-bench 68% vs Qwen's 66.5%.",
"source": "research"
}
],
"performance_log": []
},
"frontend-developer": {
"current": {
"description": "Handles UI implementation with multimodal capabilities. Accepts visual references like screenshots and mockups",
"mode": "all",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#0EA5E9\"",
"category": "General",
"capabilities": [
"ui_implementation",
"component_creation",
"styling",
"responsive_design",
"nextjs_development",
"vue_nuxt_development",
"react_development"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "af5f401",
"type": "agent_created",
"from": null,
"to": "ollama-cloud/qwen3-coder:480b",
"reason": "Flutter development support added",
"source": "git"
}
],
"performance_log": []
},
"backend-developer": {
"current": {
"description": "Backend specialist for Node.js, Express, APIs, and database integration",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#10B981\"",
"category": "General",
"capabilities": [
"api_development",
"database_design",
"server_logic",
"authentication",
"postgresql_integration",
"sqlite_integration"
]
},
"history": [],
"performance_log": []
},
"go-developer": {
"current": {
"description": "Go backend specialist for Gin, Echo, APIs, and database integration",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#00ADD8\"",
"category": "General",
"capabilities": [
"go_api_development",
"go_database_design",
"go_concurrent_programming",
"go_authentication",
"go_microservices",
"postgresql_integration",
"sqlite_integration",
"clickhouse_integration"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/deepseek-v3.2",
"to": "ollama-cloud/qwen3-coder:480b",
"reason": "Qwen3-Coder optimized for Go development",
"source": "git"
}
],
"performance_log": []
},
"sdet-engineer": {
"current": {
"description": "Writes tests following TDD methodology. Tests MUST fail initially (Red phase)",
"mode": "all",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#8B5CF6\"",
"category": "General",
"capabilities": [
"unit_tests",
"integration_tests",
"e2e_tests",
"test_planning",
"visual_regression"
]
},
"history": [],
"performance_log": []
},
"code-skeptic": {
"current": {
"description": "Adversarial code reviewer. Finds problems and issues. Does NOT suggest implementations",
"mode": "subagent",
"model": "ollama-cloud/minimax-m2.5",
"provider": "Ollama",
"color": "\"#E11D48\"",
"category": "General",
"capabilities": [
"code_review",
"security_review",
"style_check",
"issue_identification"
]
},
"history": [],
"performance_log": []
},
"security-auditor": {
"current": {
"description": "Scans for security vulnerabilities, OWASP Top 10, dependency CVEs, and hardcoded secrets",
"mode": "all",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#7F1D1D\"",
"category": "General",
"capabilities": [
"vulnerability_scan",
"owasp_check",
"secret_detection",
"auth_review"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/deepseek-v3.2",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Nemotron 3 Super optimized for security analysis with RULER@1M",
"source": "git"
}
],
"performance_log": []
},
"performance-engineer": {
"current": {
"description": "Reviews code for performance issues. Focuses on efficiency, N+1 queries, memory leaks, and algorithmic complexity",
"mode": "all",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#0D9488\"",
"category": "General",
"capabilities": [
"performance_analysis",
"n_plus_one_detection",
"memory_leak_check",
"algorithm_analysis"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Better reasoning for performance analysis",
"source": "git"
}
],
"performance_log": []
},
"browser-automation": {
"current": {
"description": "Browser automation agent using Playwright MCP for E2E testing, form filling, navigation, and web interaction",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#1E88E5\"",
"category": "General",
"capabilities": [
"e2e_browser_tests",
"form_filling",
"navigation_testing",
"screenshot_capture"
]
},
"history": [],
"performance_log": []
},
"visual-tester": {
"current": {
"description": "Visual regression testing agent that captures screenshots, extracts UI elements with bounding boxes, compares via pixelmatch, and detects console/network errors",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#E91E63\"",
"category": "General",
"capabilities": [
"visual_regression",
"pixel_comparison",
"screenshot_diff",
"ui_validation",
"bbox_element_extraction",
"console_error_detection",
"network_error_detection",
"responsive_layout_check",
"button_overflow_detection",
"gitea_integration",
"docker_networking"
]
},
"history": [],
"performance_log": []
},
"system-analyst": {
"current": {
"description": "Designs technical specifications, data schemas, and API contracts before implementation",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#0891B2\"",
"category": "General",
"capabilities": [
"architecture_design",
"api_specification",
"database_modeling",
"technical_documentation"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/glm-5",
"reason": "GLM-5 better for system engineering and architecture",
"source": "git"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
},
{
"date": "2026-04-27T16:59:52.825Z",
"commit": "model-research-sync",
"type": "model_change",
"from": "ollama-cloud/glm-5.1",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Test recommendation for model research sync script",
"source": "research"
}
],
"performance_log": []
},
"requirement-refiner": {
"current": {
"description": "Converts vague ideas and bug reports into strict User Stories with acceptance criteria checklists",
"mode": "all",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#4F46E5\"",
"category": "General",
"capabilities": [
"requirement_analysis",
"user_story_creation",
"acceptance_criteria",
"clarification"
]
},
"history": [
{
"date": "2026-04-05T22:30:00Z",
"commit": "auto",
"type": "model_change",
"from": "ollama-cloud/nemotron-3-super",
"to": "ollama-cloud/glm-5",
"reason": "+33% quality. GLM-5 excels at requirement analysis and system engineering",
"source": "research"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"history-miner": {
"current": {
"description": "Analyzes git history to find duplicates and past solutions, preventing regression and duplicate work",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#059669\"",
"category": "General",
"capabilities": [
"git_search",
"duplicate_detection",
"past_solution_finder",
"pattern_identification"
]
},
"history": [
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"capability-analyst": {
"current": {
"description": "Analyzes task requirements against available agents, workflows, and skills. Identifies gaps and recommends new components.",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"color": "\"#6366F1\"",
"category": "General",
"capabilities": [
"gap_analysis",
"capability_mapping",
"recommendation_generation",
"coverage_analysis"
]
},
"history": [
{
"date": "2026-04-05T22:30:00Z",
"commit": "auto",
"type": "model_change",
"from": "ollama-cloud/nemotron-3-super",
"to": "openrouter/qwen/qwen3.6-plus:free",
"reason": "+23% quality, IF:90 score, 1M context, FREE via OpenRouter",
"source": "research"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"orchestrator": {
"current": {
"description": "Main dispatcher. Routes tasks between agents based on Issue status and manages the workflow state machine. IF:90 for optimal routing accuracy.",
"mode": "all",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#7C3AED\"",
"category": "General",
"capabilities": [
"task_routing",
"state_management",
"agent_coordination",
"workflow_execution"
]
},
"history": [
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"release-manager": {
"current": {
"description": "Manages git operations, semantic versioning, branching, and deployments. Ensures clean history",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"color": "\"#581C87\"",
"category": "General",
"capabilities": [
"git_operations",
"version_management",
"changelog_creation",
"deployment"
]
},
"history": [
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/devstral-2:123b",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"evaluator": {
"current": {
"description": "Scores agent effectiveness after task completion for continuous improvement",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#047857\"",
"category": "General",
"capabilities": [
"performance_scoring",
"process_analysis",
"pattern_identification",
"improvement_recommendations"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Nemotron 3 Super better for evaluation tasks",
"source": "git"
},
{
"date": "2026-04-05T22:30:00Z",
"commit": "auto",
"type": "model_change",
"from": "ollama-cloud/nemotron-3-super",
"to": "openrouter/qwen/qwen3.6-plus:free",
"reason": "+4% quality, IF:90 for scoring accuracy, FREE",
"source": "research"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"prompt-optimizer": {
"current": {
"description": "Improves agent system prompts based on performance failures. Meta-learner for prompt optimization",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "instant",
"color": "\"#BE185D\"",
"category": "General",
"capabilities": [
"prompt_analysis",
"prompt_improvement",
"failure_pattern_detection"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Research recommendation applied",
"source": "git"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/nemotron-3-super",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"the-fixer": {
"current": {
"description": "Iteratively fixes bugs based on specific error reports and test failures",
"mode": "all",
"model": "ollama-cloud/minimax-m2.5",
"provider": "Ollama",
"color": "\"#F59E0B\"",
"category": "General",
"capabilities": [
"bug_fixing",
"issue_resolution",
"code_correction"
]
},
"history": [],
"performance_log": []
},
"product-owner": {
"current": {
"description": "Manages issue checklists, status labels, tracks progress and coordinates with human users",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"color": "\"#EA580C\"",
"category": "General",
"capabilities": [
"issue_management",
"prioritization",
"backlog_management",
"workflow_completion"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/glm-5",
"reason": "GLM-5 good for management tasks",
"source": "git"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"workflow-architect": {
"current": {
"description": "Creates and maintains workflow definitions with complete architecture, Gitea integration, and quality gates",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#EC4899\"",
"category": "General",
"capabilities": [
"workflow_design",
"process_definition",
"automation_setup"
]
},
"history": [
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "ollama-cloud/glm-5",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"markdown-validator": {
"current": {
"description": "Validates and corrects Markdown descriptions for Gitea issues",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-nano:30b",
"provider": "Ollama",
"color": "\"#F97316\"",
"category": "General",
"capabilities": [
"markdown_validation",
"formatting_check",
"link_validation"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/nemotron-3-nano:30b",
"reason": "Nano efficient for lightweight validation tasks",
"source": "git"
}
],
"performance_log": []
},
"agent-architect": {
"current": {
"name": "Agent Architect",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"description": "Creates, modifies, and reviews new agents, workflows, and skills based on capability gap analysis",
"color": "\"#8B5CF6\"",
"category": "General",
"capabilities": [
"agent_design",
"prompt_engineering",
"capability_definition"
]
},
"history": [
{
"date": "2026-04-05T22:30:00Z",
"commit": "auto",
"type": "model_change",
"from": "ollama-cloud/nemotron-3-super",
"to": "openrouter/qwen/qwen3.6-plus:free",
"reason": "+22% quality, IF:90 for YAML frontmatter generation, 1M context for all agents analysis",
"source": "research"
},
{
"date": "2026-04-23T06:24:32.546Z",
"commit": "sync",
"type": "model_change",
"from": "openrouter/qwen/qwen3.6-plus:free",
"to": "ollama-cloud/glm-5.1",
"reason": "Model update from sync",
"source": "git"
}
],
"performance_log": []
},
"planner": {
"current": {
"description": "Advanced task planner using Chain of Thought, Tree of Thoughts, and Plan-Execute-Reflect",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#F59E0B\"",
"category": "General",
"capabilities": [
"task_decomposition",
"chain_of_thought",
"tree_of_thoughts",
"plan_execute_reflect",
"dependency_analysis"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Nemotron 3 Super excels at planning",
"source": "git"
}
],
"performance_log": []
},
"reflector": {
"current": {
"description": "Self-reflection agent using Reflexion pattern - learns from mistakes",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#10B981\"",
"category": "General",
"capabilities": [
"self_reflection",
"mistake_analysis",
"lesson_extraction",
"trajectory_analysis",
"heuristic_evaluation"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "Better for reflection tasks",
"source": "git"
}
],
"performance_log": []
},
"memory-manager": {
"current": {
"description": "Manages agent memory systems - short-term (context), long-term (vector store), and episodic (experiences)",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#8B5CF6\"",
"category": "General",
"capabilities": [
"memory_retrieval",
"memory_storage",
"memory_consolidation",
"relevance_scoring",
"episodic_management"
]
},
"history": [
{
"date": "2026-04-05T05:21:00Z",
"commit": "caf77f53c8",
"type": "model_change",
"from": "ollama-cloud/gpt-oss:120b",
"to": "ollama-cloud/nemotron-3-super",
"reason": "RULER@1M critical for memory ctx",
"source": "git"
}
],
"performance_log": []
},
"devops-engineer": {
"current": {
"description": "DevOps specialist for Docker, Kubernetes, CI/CD pipeline automation, and infrastructure management",
"mode": "subagent",
"model": "ollama-cloud/nemotron-3-super",
"provider": "Ollama",
"color": "\"#FF6B35\"",
"category": "General",
"capabilities": [
"docker_configuration",
"kubernetes_setup",
"ci_cd_pipeline",
"infrastructure_automation",
"container_optimization"
]
},
"history": [],
"performance_log": []
},
"flutter-developer": {
"current": {
"description": "Flutter mobile specialist for cross-platform apps, state management, and UI components",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"color": "\"#02569B\"",
"category": "General",
"capabilities": [
"dart_programming",
"flutter_ui",
"mobile_app_development",
"widget_creation",
"state_management"
]
},
"history": [
{
"date": "2026-04-05T15:00:00Z",
"commit": "af5f401",
"type": "agent_created",
"from": null,
"to": "ollama-cloud/qwen3-coder:480b",
"reason": "New agent for Flutter development",
"source": "git"
}
],
"performance_log": []
},
"architect-indexer": {
"current": {
"description": "Indexes and maps project codebase architecture into .architect/ directory. Creates and maintains structured documentation of entities, APIs, DB schema, file graphs, and conventions.",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#10B981\"",
"category": "General",
"capabilities": [
"codebase_indexing",
"project_mapping",
"architecture_documentation",
"dependency_analysis",
"entity_extraction",
"api_surface_discovery",
"convention_detection",
"staleness_detection"
]
},
"history": [],
"performance_log": []
},
"php-developer": {
"current": {
"description": "PHP backend specialist for Laravel, Symfony, WordPress, and full-stack web applications",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#8B5CF6\"",
"category": "General",
"capabilities": [
"php_web_development",
"laravel_development",
"symfony_development",
"wordpress_development",
"php_api_development",
"php_database_design",
"php_authentication",
"php_modular_architecture",
"php_testing",
"php_security"
]
},
"history": [],
"performance_log": []
},
"pipeline-judge": {
"current": {
"description": "Automated pipeline judge. Evaluates workflow execution by running tests, measuring token cost and wall-clock time. Produces objective fitness scores. Never writes code - only measures and scores.",
"mode": "subagent",
"model": "ollama-cloud/glm-5.1",
"provider": "Ollama",
"color": "\"#DC2626\"",
"category": "General",
"capabilities": [
"test_execution",
"fitness_scoring",
"metric_collection",
"bottleneck_detection"
]
},
"history": [
{
"date": "2026-04-06T00:23:50 +0100Z",
"commit": "fa68141d",
"type": "agent_created",
"from": null,
"to": "",
"reason": "feat: add pipeline-judge agent and evolution workflow system",
"source": "git"
}
],
"performance_log": []
},
"python-developer": {
"current": {
"description": "Python backend specialist for Django, FastAPI, data science, and API development",
"mode": "subagent",
"model": "ollama-cloud/qwen3-coder:480b",
"provider": "Ollama",
"variant": "thinking",
"color": "\"#3776AB\"",
"category": "General",
"capabilities": [
"python_web_development",
"django_development",
"fastapi_development",
"python_api_development",
"python_database_design",
"python_authentication",
"python_async_patterns",
"python_testing",
"python_security"
]
},
"history": [],
"performance_log": []
}
},
"providers": {
"Ollama": {
"models": []
},
"OpenRouter": {
"models": []
},
"Groq": {
"models": []
}
},
"evolution_metrics": {
"total_agents": 32,
"agents_with_history": 22,
"pending_recommendations": 0,
"last_sync": "2026-04-23T06:24:32.546Z",
"sync_sources": [
"git",
"capability-index.yaml",
"kilo.jsonc"
]
}
};
// Initialize
async function init() {
// Use embedded data directly (works with file://)
agentData = EMBEDDED_DATA;
try {
document.getElementById('lastSync').textContent = formatDate(agentData.lastUpdated);
document.getElementById('agentCount').textContent = agentData.evolution_metrics.total_agents + ' agents';
document.getElementById('historyCount').textContent = agentData.evolution_metrics.agents_with_history + ' with history';
if (agentData.evolution_metrics.total_agents === 0) {
document.getElementById('lastSync').textContent = 'No data - run sync:evolution';
return;
}
renderOverview();
renderAllAgents();
renderTimeline();
renderRecommendations();
renderMatrix();
} catch (error) {
console.error('Failed to render dashboard:', error);
document.getElementById('lastSync').textContent = 'Error rendering data';
}
}
// Format date
function formatDate(dateStr) {
const date = new Date(dateStr);
return date.toLocaleDateString('ru-RU', {
day: '2-digit',
month: 'short',
hour: '2-digit',
minute: '2-digit'
});
}
// Render Overview
function renderOverview() {
const stats = [
{ label: 'Total Agents', value: agentData.evolution_metrics.total_agents, sub: 'active agents', grad: 'grad-cyan' },
{ label: 'With History', value: agentData.evolution_metrics.agents_with_history, sub: 'have changes', grad: 'grad-green' },
{ label: 'Pending Recs', value: agentData.evolution_metrics.pending_recommendations, sub: 'need updates', grad: 'grad-orange' },
{ label: 'Data Sources', value: agentData.evolution_metrics.sync_sources.length, sub: 'git, yaml, jsonc', grad: 'grad-purple' },
];
document.getElementById('statsRow').innerHTML = stats.map(s => `
<div class="stat-card">
<div class="stat-label">${s.label}</div>
<div class="stat-value ${s.grad}">${s.value}</div>
<div class="stat-sub">${s.sub}</div>
</div>
`).join('');
// Recent changes
const allHistory = [];
for (const [name, agent] of Object.entries(agentData.agents)) {
for (const h of agent.history) {
allHistory.push({ ...h, agent: name });
}
}
allHistory.sort((a, b) => new Date(b.date) - new Date(a.date));
const recent = allHistory.slice(0, 10);
document.getElementById('recentCount').textContent = recent.length;
document.getElementById('recentTimeline').innerHTML = recent.length > 0
? recent.map(h => `
<div class="timeline-item">
<div class="timeline-date">${formatDate(h.date)}</div>
<div class="timeline-content">
<span class="timeline-agent">${h.agent}</span>
<span class="timeline-change">: ${h.type.replace('_', ' ')} from ${h.from || 'none'} to ${h.to}</span>
</div>
</div>
`).join('')
: '<p style="color: var(--text-muted);">No history yet</p>';
// Recommended agents
const recAgents = Object.entries(agentData.agents)
.filter(([_, a]) => a.current.recommendations && a.current.recommendations.length > 0)
.slice(0, 6);
document.getElementById('recCount').textContent = recAgents.length;
document.getElementById('recAgents').innerHTML = recAgents.map(([name, agent]) =>
renderAgentCard(name, agent, true)
).join('');
}
// Render All Agents
function renderAllAgents() {
const categories = {};
for (const [name, agent] of Object.entries(agentData.agents)) {
const cat = agent.current.category || 'General';
if (!categories[cat]) categories[cat] = [];
categories[cat].push([name, agent]);
}
let html = '';
for (const [cat, agents] of Object.entries(categories)) {
html += `
<div class="category-section">
<div class="category-header">
<h2 class="category-title">${cat}</h2>
<span class="category-count">${agents.length}</span>
</div>
<div class="agents-grid">
${agents.map(([name, agent]) => renderAgentCard(name, agent)).join('')}
</div>
</div>
`;
}
document.getElementById('agentsByCategory').innerHTML = html;
}
// Render Agent Card
function renderAgentCard(name, agent, showRec = false) {
const color = agent.current.color || '#6B7280';
const hasHistory = agent.history && agent.history.length > 0;
const needsUpdate = agent.current.recommendations && agent.current.recommendations.length > 0;
const isNew = agent.current.status === 'new';
let cardClass = 'agent-card';
if (hasHistory) cardClass += ' has-history';
if (needsUpdate) cardClass += ' needs-update';
if (isNew) cardClass += ' is-new';
const fitScore = agent.current.benchmark?.fit_score || 0;
const scoreClass = fitScore >= 80 ? 'high' : fitScore >= 60 ? 'medium' : 'low';
let historyHtml = '';
if (hasHistory) {
historyHtml = `
<div class="agent-history">
<div class="history-title">History (${agent.history.length} changes)</div>
${agent.history.slice(0, 3).map(h => `
<div class="history-item">
<span class="history-date">${formatDate(h.date)}</span>
<span class="history-type ${h.type}">${h.type.replace('_', ' ')}</span>
<span>${h.from || 'none'}${h.to}</span>
</div>
`).join('')}
</div>
`;
}
let recHtml = '';
if (showRec && agent.current.recommendations) {
recHtml = agent.current.recommendations.map(r => `
<div style="margin-top:8px;padding:8px;background:rgba(255,159,67,0.1);border-radius:6px;font-size:0.8em;">
<strong style="color:var(--accent-orange);">${r.priority.toUpperCase()}</strong>:
Switch to <code>${r.target}</code><br>
<span style="color:var(--text-muted)">${r.reason}</span>
</div>
`).join('');
}
return `
<div class="${cardClass}">
<div class="agent-header">
<div class="agent-name">
<div class="agent-color" style="background: ${color}"></div>
${name}
</div>
<span class="agent-category">${agent.current.category}</span>
</div>
<div class="agent-model">
<span>${agent.current.model || 'not set'}</span>
${agent.current.provider ? `<span class="agent-provider">${agent.current.provider}</span>` : ''}
</div>
<div class="agent-desc">${agent.current.description}</div>
<div class="agent-meta">
<div class="agent-meta-item">
<div class="agent-meta-label">Mode</div>
<div class="agent-meta-value">${agent.current.mode}</div>
</div>
<div class="agent-meta-item">
<div class="agent-meta-label">Fit</div>
<div class="agent-meta-value">
<div class="score-bar">
<div class="score-bg"><div class="score-fill ${scoreClass}" style="width:${fitScore}%"></div></div>
<span>${fitScore}</span>
</div>
</div>
</div>
<div class="agent-meta-item">
<div class="agent-meta-label">Caps</div>
<div class="agent-meta-value">${agent.current.capabilities?.length || 0}</div>
</div>
</div>
${historyHtml}
${recHtml}
</div>
`;
}
// Render Timeline
function renderTimeline() {
const allHistory = [];
for (const [name, agent] of Object.entries(agentData.agents)) {
for (const h of agent.history) {
allHistory.push({ ...h, agent: name });
}
}
allHistory.sort((a, b) => new Date(b.date) - new Date(a.date));
document.getElementById('fullTimeline').innerHTML = allHistory.length > 0
? allHistory.map(h => `
<div class="timeline-item">
<div class="timeline-date">${formatDate(h.date)}${h.commit}</div>
<div class="timeline-content">
<span class="timeline-agent">${h.agent}</span>
<span class="timeline-type ${h.type}" style="margin-left:8px;padding:2px 6px;border-radius:4px;font-size:0.8em;background:rgba(0,212,255,0.1);color:var(--accent-cyan)">${h.type.replace('_', ' ')}</span>
<div style="margin-top:4px;color:var(--text-secondary)">
${h.from ? `<code>${h.from}</code> → ` : ''}<code style="color:var(--accent-green)">${h.to}</code>
</div>
<div style="margin-top:4px;color:var(--text-muted);font-size:0.85em">${h.reason}</div>
</div>
</div>
`).join('')
: '<p style="color:var(--text-muted)">No history recorded yet.</p>';
}
// Render Recommendations
function renderRecommendations() {
const recs = Object.entries(agentData.agents)
.filter(([_, a]) => a.current.recommendations && a.current.recommendations.length > 0);
document.getElementById('allRecommendations').innerHTML = recs.map(([name, agent]) =>
renderAgentCard(name, agent, true)
).join('');
}
// Render Matrix
function renderMatrix() {
const agents = Object.entries(agentData.agents);
const models = [...new Set(agents.map(([_, a]) => a.current.model).filter(Boolean))];
// Header
document.getElementById('matrixHead').innerHTML = `
<tr>
<th>Agent</th>
<th>Model</th>
<th>Provider</th>
<th>Fit Score</th>
<th>Category</th>
<th>Status</th>
</tr>
`;
// Body
document.getElementById('matrixBody').innerHTML = agents.map(([name, agent]) => {
const fit = agent.current.benchmark?.fit_score || 0;
const scoreClass = fit >= 80 ? 'high' : fit >= 60 ? 'medium' : 'low';
const status = agent.current.status === 'new' ? '🆕 New' :
agent.current.recommendations?.length > 0 ? '⚠️ Update' : '✅ OK';
return `
<tr>
<td><strong>${name}</strong></td>
<td><code style="color:var(--accent-green)">${agent.current.model || '—'}</code></td>
<td>${agent.current.provider || '—'}</td>
<td>
<div class="score-bar">
<div class="score-bg"><div class="score-fill ${scoreClass}" style="width:${fit}%"></div></div>
<span>${fit}</span>
</div>
</td>
<td>${agent.current.category}</td>
<td>${status}</td>
</tr>
`;
}).join('');
}
// Filter Agents
function filterAgents() {
const search = document.getElementById('agentSearch').value.toLowerCase();
const cards = document.querySelectorAll('.agent-card');
cards.forEach(card => {
const text = card.textContent.toLowerCase();
card.style.display = text.includes(search) ? '' : 'none';
});
}
function filterCategory(category) {
document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active'));
event.target.classList.add('active');
if (category === 'all') {
document.querySelectorAll('.agent-card').forEach(card => card.style.display = '');
} else {
document.querySelectorAll('.category-section').forEach(section => {
const title = section.querySelector('.category-title')?.textContent;
section.style.display = title === category ? '' : 'none';
});
}
}
// Export
function exportRecommendations() {
const recs = Object.entries(agentData.agents)
.filter(([_, a]) => a.current.recommendations && a.current.recommendations.length > 0)
.map(([name, agent]) => ({
agent: name,
current_model: agent.current.model,
recommendations: agent.current.recommendations
}));
const output = {
timestamp: new Date().toISOString(),
total_recommendations: recs.length,
recommendations: recs
};
document.getElementById('exportContent').textContent = JSON.stringify(output, null, 2);
document.getElementById('exportModal').classList.add('show');
}
function copyToClipboard() {
const text = document.getElementById('exportContent').textContent;
navigator.clipboard.writeText(text);
alert('Copied to clipboard!');
}
function downloadJSON() {
const text = document.getElementById('exportContent').textContent;
const blob = new Blob([text], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'agent-recommendations.json';
a.click();
URL.revokeObjectURL(url);
}
function closeModal() {
document.getElementById('exportModal').classList.remove('show');
}
// Tab switching
function switchTab(tabId) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.tab-panel').forEach(panel => panel.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('tab-' + tabId).classList.add('active');
}
// Initialize on load
init();
</script>
</body>
</html>