fix(dashboard): heatmap cell click + 5th tab + model sync fixes\n\n- restore hmModal with 4 legacy tabs + new Performance Graph tab\n- fix event.target in research-dashboard.template.html switchTab\n- fix showCellDetail event.stopPropagation for modal persistence\n- update agent models + sync KILO_SPEC.md and AGENTS.md
This commit is contained in:
@@ -433,35 +433,40 @@ Provider availability depends on configuration. Common providers include:
|
||||
|
||||
| Agent | Role | Model |
|
||||
|-------|------|-------|
|
||||
| `@RequirementRefiner` | Converts vague ideas and bug reports into strict User Stories with acceptance criteria checklists. | ollama-cloud/kimi-k2-thinking |
|
||||
| `@HistoryMiner` | Analyzes git history to find duplicates and past solutions, preventing regression and duplicate work. | ollama-cloud/nemotron-3-super |
|
||||
| `@SystemAnalyst` | Designs technical specifications, data schemas, and API contracts before implementation. | ollama-cloud/nemotron-3-super |
|
||||
| `@SdetEngineer` | Writes tests following TDD methodology. | ollama-cloud/qwen3-coder:480b |
|
||||
| `@LeadDeveloper` | Primary code writer for backend and core logic. | ollama-cloud/nemotron-3-super |
|
||||
| `@FrontendDeveloper` | Handles UI implementation with multimodal capabilities. | ollama-cloud/kimi-k2.5 |
|
||||
| `@BackendDeveloper` | Backend specialist for Node. | ollama-cloud/deepseek-v3.2 |
|
||||
| `@GoDeveloper` | Go backend specialist for Gin, Echo, APIs, and database integration. | ollama-cloud/qwen3-coder:480b |
|
||||
| `@RequirementRefiner` | Converts vague ideas and bug reports into strict User Stories with acceptance criteria checklists. | ollama-cloud/kimi-k2.6 |
|
||||
| `@HistoryMiner` | Analyzes git history to find duplicates and past solutions, preventing regression and duplicate work. | ollama-cloud/kimi-k2.6 |
|
||||
| `@SystemAnalyst` | Designs technical specifications, data schemas, and API contracts before implementation. | ollama-cloud/glm-5.1 |
|
||||
| `@SdetEngineer` | Writes tests following TDD methodology. | ollama-cloud/kimi-k2.6 |
|
||||
| `@LeadDeveloper` | Primary code writer for backend and core logic. | ollama-cloud/kimi-k2.6 |
|
||||
| `@FrontendDeveloper` | Handles UI implementation with multimodal capabilities. | ollama-cloud/kimi-k2.6 |
|
||||
| `@BackendDeveloper` | Backend specialist for Node. | ollama-cloud/kimi-k2.6 |
|
||||
| `@GoDeveloper` | Go backend specialist for Gin, Echo, APIs, and database integration. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@DevopsEngineer` | DevOps specialist for Docker, Kubernetes, CI/CD pipeline automation, and infrastructure management. | ollama-cloud/kimi-k2.6 |
|
||||
| `@CodeSkeptic` | Adversarial code reviewer. | ollama-cloud/minimax-m2.5 |
|
||||
| `@TheFixer` | Iteratively fixes bugs based on specific error reports and test failures. | ollama-cloud/minimax-m2.5 |
|
||||
| `@PerformanceEngineer` | Reviews code for performance issues. | ollama-cloud/nemotron-3-super |
|
||||
| `@SecurityAuditor` | Scans for security vulnerabilities, OWASP Top 10, dependency CVEs, and hardcoded secrets. | ollama-cloud/nemotron-3-super |
|
||||
| `@VisualTester` | Visual regression testing agent that compares screenshots and detects UI differences using pixelmatch and image diff. | ollama-cloud/qwen3-coder:480b |
|
||||
| `@CodeSkeptic` | Adversarial code reviewer. | ollama-cloud/kimi-k2.6 |
|
||||
| `@TheFixer` | Iteratively fixes bugs based on specific error reports and test failures. | ollama-cloud/kimi-k2.6 |
|
||||
| `@PerformanceEngineer` | Reviews code for performance issues. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@SecurityAuditor` | Scans for security vulnerabilities, OWASP Top 10, dependency CVEs, and hardcoded secrets. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@VisualTester` | Visual regression testing agent that compares screenshots and detects UI differences using pixelmatch and image diff. | ollama-cloud/kimi-k2.6 |
|
||||
| `@Orchestrator` | Main dispatcher. | ollama-cloud/kimi-k2.6 |
|
||||
| `@ReleaseManager` | Manages git operations, semantic versioning, branching, and deployments. | ollama-cloud/devstral-2:123b |
|
||||
| `@Evaluator` | Scores agent effectiveness after task completion for continuous improvement. | ollama-cloud/nemotron-3-super |
|
||||
| `@PromptOptimizer` | Improves agent system prompts based on performance failures. | ollama-cloud/glm-5.1 |
|
||||
| `@ProductOwner` | Manages issue checklists, status labels, tracks progress and coordinates with human users. | ollama-cloud/glm-5.1 |
|
||||
| `@ReleaseManager` | Manages git operations, semantic versioning, branching, and deployments. | ollama-cloud/glm-5.1 |
|
||||
| `@Evaluator` | Scores agent effectiveness after task completion for continuous improvement. | ollama-cloud/kimi-k2.6 |
|
||||
| `@PromptOptimizer` | Improves agent system prompts based on performance failures. | ollama-cloud/kimi-k2.6 |
|
||||
| `@ProductOwner` | Manages issue checklists, status labels, tracks progress and coordinates with human users. | ollama-cloud/kimi-k2.6 |
|
||||
| `@AgentArchitect` | Creates, modifies, and reviews new agents, workflows, and skills based on capability gap analysis. | ollama-cloud/kimi-k2.6 |
|
||||
| `@CapabilityAnalyst` | Analyzes task requirements against available agents, workflows, and skills. | ollama-cloud/nemotron-3-super |
|
||||
| `@WorkflowArchitect` | Creates and maintains workflow definitions with complete architecture, Gitea integration, and quality gates. | ollama-cloud/gpt-oss:120b |
|
||||
| `@MarkdownValidator` | Validates and corrects Markdown descriptions for Gitea issues. | ollama-cloud/nemotron-3-nano:30b |
|
||||
| `@CapabilityAnalyst` | Analyzes task requirements against available agents, workflows, and skills. | ollama-cloud/glm-5.1 |
|
||||
| `@WorkflowArchitect` | Creates and maintains workflow definitions with complete architecture, Gitea integration, and quality gates. | ollama-cloud/kimi-k2.6 |
|
||||
| `@MarkdownValidator` | Validates and corrects Markdown descriptions for Gitea issues. | ollama-cloud/kimi-k2.6 |
|
||||
| `@BrowserAutomation` | Browser automation agent using Playwright MCP for E2E testing, form filling, navigation, and web interaction. | ollama-cloud/kimi-k2.6 |
|
||||
| `@Planner` | Advanced task planner using Chain of Thought, Tree of Thoughts, and Plan-Execute-Reflect. | ollama-cloud/nemotron-3-super |
|
||||
| `@Reflector` | Self-reflection agent using Reflexion pattern - learns from mistakes. | ollama-cloud/nemotron-3-super |
|
||||
| `@MemoryManager` | Manages agent memory systems - short-term (context), long-term (vector store), and episodic (experiences). | ollama-cloud/nemotron-3-super |
|
||||
| `@IncidentResponder` | Server incident response, live forensics, malware removal, hardening, and SSH-based cleanup. | ollama-cloud/kimi-k2.6 |
|
||||
| `@WorkflowCrossChecker` | Pre-flight inter-agent conflict and architecture validation; asks uncomfortable questions before expensive work. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@Planner` | Advanced task planner using Chain of Thought, Tree of Thoughts, and Plan-Execute-Reflect. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@Reflector` | Self-reflection agent using Reflexion pattern - learns from mistakes. | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@MemoryManager` | Manages agent memory systems - short-term (context), long-term (vector store), and episodic (experiences). | ollama-cloud/deepseek-v4-pro-max |
|
||||
| `@ArchitectIndexer` | Indexes and maps project codebase architecture into . | ollama-cloud/kimi-k2.6 |
|
||||
| `@FlutterDeveloper` | Flutter mobile specialist for cross-platform apps, state management, and UI components. | ollama-cloud/kimi-k2.6 |
|
||||
| `@PhpDeveloper` | PHP specialist for Laravel, Symfony, WordPress, and modular architecture. | ollama-cloud/kimi-k2.6 |
|
||||
| `@PipelineJudge` | Automated pipeline judge. | ollama-cloud/glm-5.1 |
|
||||
| `@PythonDeveloper` | Python specialist for Django, FastAPI, data processing, and ML pipelines. | ollama-cloud/kimi-k2.6 |
|
||||
| `@IncidentResponder` | Server incident response and system hardening specialist. | ollama-cloud/kimi-k2.6 |
|
||||
| `@WorkflowCrossChecker` | Workflow cross-checker and process inspector. | ollama-cloud/kimi-k2.6 |
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ These agents are invoked automatically by `/pipeline` or manually via `@mention`
|
||||
| `@BackendDeveloper` | Backend specialist for Node | When backend needed |
|
||||
| `@GoDeveloper` | Go backend specialist for Gin, Echo, APIs, and database integration | When Go backend needed |
|
||||
| `@DevopsEngineer` | DevOps specialist for Docker, Kubernetes, CI/CD pipeline automation, and infrastructure management | When deployment/infra needed |
|
||||
| `@ArchitectIndexer` | Indexes and maps project codebase architecture into | Manual invocation |
|
||||
| `@FlutterDeveloper` | Flutter mobile specialist for cross-platform apps, state management, and UI components | Manual invocation |
|
||||
| `@PhpDeveloper` | PHP specialist for Laravel, Symfony, WordPress, and modular architecture | Manual invocation |
|
||||
| `@PythonDeveloper` | Python specialist for Django, FastAPI, data processing, and ML pipelines | Manual invocation |
|
||||
| `@IncidentResponder` | Server incident response and system hardening specialist | Manual invocation |
|
||||
|
||||
### Quality Assurance
|
||||
| Agent | Role | When Invoked |
|
||||
@@ -86,8 +91,9 @@ These agents are invoked automatically by `/pipeline` or manually via `@mention`
|
||||
| `@AgentArchitect` | Creates, modifies, and reviews new agents, workflows, and skills based on capability gap analysis | When gaps identified |
|
||||
| `@CapabilityAnalyst` | Analyzes task requirements against available agents, workflows, and skills | When starting new task |
|
||||
| `@WorkflowArchitect` | Creates and maintains workflow definitions with complete architecture, Gitea integration, and quality gates | New workflow needed |
|
||||
| `@WorkflowCrossChecker` | Pre-flight inter-agent conflict and architecture validation; asks uncomfortable questions before expensive work | Before parallel spawn or state transitions |
|
||||
| `@MarkdownValidator` | Validates and corrects Markdown descriptions for Gitea issues | Before issue creation |
|
||||
| `@PipelineJudge` | Automated pipeline judge | Manual invocation |
|
||||
| `@WorkflowCrossChecker` | Workflow cross-checker and process inspector | Manual invocation |
|
||||
|
||||
### Security & Incident Response
|
||||
| Agent | Role | When Invoked |
|
||||
|
||||
@@ -983,6 +983,7 @@
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('gitea')">Gitea History</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('skills')">Skills</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('models')">Model Timeline</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('graph')">Performance Graph</button>
|
||||
</div>
|
||||
<div class="modal-body" id="hmModalBody">
|
||||
<!-- Content injected by JS -->
|
||||
@@ -1162,33 +1163,15 @@ function renderOverview() {
|
||||
`).join('')
|
||||
: '<p style="color: var(--text-muted);">No history yet</p>';
|
||||
|
||||
// Recommended agents (use inline recs if available)
|
||||
let recAgents = [];
|
||||
if (INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0) {
|
||||
recAgents = INLINE_RECOMMENDATIONS.slice(0, 6).map(r => ({ agent: r.agent, current: { recommendations: [{ priority: r.impact, target: r.source_of_truth_model || r.recommended_model, reason: r.rationale, score_before: r.score_before, score_after: r.score_after, score_delta: r.score_delta }], model: r.current_model_in_agent_versions || r.current_model, category: 'Core Dev', description: '', benchmark: { fit_score: r.score_after || 0 } } }));
|
||||
} else {
|
||||
recAgents = Object.entries(agentData.agents)
|
||||
.filter(([_, a]) => a.current.recommendations && a.current.recommendations.length > 0)
|
||||
.slice(0, 6);
|
||||
}
|
||||
// Recommended agents from live data
|
||||
const recAgents = Object.entries(agentData.agents || {})
|
||||
.filter(([_, a]) => (a.current?.recommendations || []).length > 0)
|
||||
.slice(0, 6);
|
||||
|
||||
document.getElementById('recCount').textContent = recAgents.length;
|
||||
if (INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0) {
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map((r, idx) => renderRecCard({
|
||||
agent: r.agent,
|
||||
current_model: r.current?.model || '',
|
||||
recommended_model: r.current?.recommendations?.[0]?.target || '',
|
||||
impact: r.current?.recommendations?.[0]?.priority?.toLowerCase() || 'medium',
|
||||
score_before: r.current?.recommendations?.[0]?.score_before || 0,
|
||||
score_after: r.current?.recommendations?.[0]?.score_after || 0,
|
||||
score_delta: r.current?.recommendations?.[0]?.score_delta || 0,
|
||||
rationale: r.current?.recommendations?.[0]?.reason || ''
|
||||
}, idx)).join('');
|
||||
} else {
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map(([name, agent]) =>
|
||||
renderAgentCard(name, agent, true)
|
||||
).join('');
|
||||
}
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map(([name, agent]) =>
|
||||
renderAgentCard(name, agent, true)
|
||||
).join('');
|
||||
}
|
||||
|
||||
// Render All Agents
|
||||
@@ -1327,24 +1310,19 @@ function renderTimeline() {
|
||||
|
||||
// Render Recommendations (v3 style with swap visuals)
|
||||
function renderRecommendations() {
|
||||
// Use inline recommendations or fall back to agent data
|
||||
let recs = [];
|
||||
if (INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0) {
|
||||
recs = INLINE_RECOMMENDATIONS;
|
||||
} else {
|
||||
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,
|
||||
recommended_model: agent.current.recommendations[0]?.target,
|
||||
impact: agent.current.recommendations[0]?.priority?.toLowerCase() || 'medium',
|
||||
score_before: agent.current.recommendations[0]?.score_before || 0,
|
||||
score_after: agent.current.recommendations[0]?.score_after || 0,
|
||||
score_delta: agent.current.recommendations[0]?.score_delta || 0,
|
||||
rationale: agent.current.recommendations[0]?.reason || ''
|
||||
}));
|
||||
}
|
||||
const recs = Object.entries(agentData.agents || {})
|
||||
.filter(([_, a]) => (a.current?.recommendations || []).length > 0)
|
||||
.map(([name, agent]) => ({
|
||||
agent: name,
|
||||
current_model: agent.current?.model,
|
||||
recommended_model: agent.current?.recommendations?.[0]?.target,
|
||||
impact: agent.current?.recommendations?.[0]?.priority?.toLowerCase() || 'medium',
|
||||
score_before: agent.current?.recommendations?.[0]?.score_before || 0,
|
||||
score_after: agent.current?.recommendations?.[0]?.score_after || 0,
|
||||
score_delta: agent.current?.recommendations?.[0]?.score_delta || 0,
|
||||
rationale: agent.current?.recommendations?.[0]?.reason || '',
|
||||
current_model_in_agent_versions: agent.current?.model
|
||||
}));
|
||||
|
||||
if (recs.length === 0) {
|
||||
document.getElementById('allRecommendations').innerHTML = '<p style="color:var(--text-muted);text-align:center;padding:40px;">No recommendations available</p>';
|
||||
@@ -1493,7 +1471,7 @@ function renderHeatmap() {
|
||||
h += `<td style="background:${hmColor(s)};color:${hmText(s)};cursor:pointer" class="${cur ? 'hm-cur' : ''}" title="${ag.n} × ${hmModels[j].n}: ${s}"
|
||||
onmouseover="showTT(event,'${ag.n}','${hmModels[j].n} (${hmModels[j].p})',${s},${best},${cur},${hmModels[j].if})"
|
||||
onmouseout="hideTT()"
|
||||
onclick="showCellDetail('${hmModels[j].full}', '${ag.n}')">${s}${marks}</td>`;
|
||||
onclick="openHmModal(event, '${ag.n}', '${hmModels[j].n}', ${s}, ${hmModels[j].if})">${s}${marks}</td>`;
|
||||
});
|
||||
h += '</tr>';
|
||||
});
|
||||
@@ -1556,7 +1534,8 @@ function closeHmModal() {
|
||||
}
|
||||
|
||||
// Show cell detail modal with Chart.js line chart and prompt history
|
||||
function showCellDetail(modelName, agentName) {
|
||||
function showCellDetail(event, modelName, agentName) {
|
||||
event.stopPropagation();
|
||||
const agent = agentData.agents[agentName];
|
||||
if (!agent) {
|
||||
console.error('Agent not found:', agentName);
|
||||
@@ -1770,9 +1749,13 @@ function renderHmModalContent(tabName) {
|
||||
case 'models':
|
||||
content = renderModelsTab(agent);
|
||||
break;
|
||||
case 'graph':
|
||||
content = renderGraphTab(agent);
|
||||
break;
|
||||
}
|
||||
|
||||
body.innerHTML = `<div class="hm-tab-content active" style="display:block">${content}</div>`;
|
||||
if (tabName === 'graph') setTimeout(() => renderCellChart(hmCurrentAgent, agent.current?.model || ''), 50);
|
||||
}
|
||||
|
||||
function renderPromptTab(agent) {
|
||||
@@ -1911,6 +1894,46 @@ function renderModelsTab(agent) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderGraphTab(agent) {
|
||||
return `
|
||||
<div style="margin-bottom:20px">
|
||||
<h3 style="margin-bottom:10px;color:var(--accent-cyan)">Performance Over Time</h3>
|
||||
<div style="position:relative;height:300px">
|
||||
<canvas id="cellChartCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin-bottom:10px;color:var(--accent-cyan)">Prompt Change History</h3>
|
||||
<div id="promptHistoryList" style="max-height:300px;overflow-y:auto">
|
||||
${renderPromptHistory(agent)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderPromptHistory(agent) {
|
||||
const promptChanges = (agent.history || []).filter(item => item.change_type === 'prompt_change');
|
||||
|
||||
if (promptChanges.length === 0) {
|
||||
return '<p style="color:var(--text-muted);text-align:center;padding:20px">No prompt change history found</p>';
|
||||
}
|
||||
|
||||
let html = '<ul style="list-style:none;padding:0">';
|
||||
promptChanges.forEach(change => {
|
||||
html += `
|
||||
<li style="padding:10px;border-bottom:1px solid var(--border);margin-bottom:10px">
|
||||
<div style="display:flex;justify-content:space-between;margin-bottom:5px">
|
||||
<span style="font-family:'JetBrains Mono',monospace;font-size:.8em;color:var(--text-muted)">${formatDate(change.date)}</span>
|
||||
<span style="font-family:'JetBrains Mono',monospace;font-size:.8em;color:var(--accent-cyan)">${change.commit ? change.commit.substring(0,7) : 'unknown'}</span>
|
||||
</div>
|
||||
<div style="font-size:.9em;color:var(--text-secondary)">${change.reason || 'No reason provided'}</div>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
html += '</ul>';
|
||||
return html;
|
||||
}
|
||||
|
||||
// Compute composite score for any model name
|
||||
// Formula (v2): IF_score * 0.85 + context_window_bonus (SWE-bench removed — all values unverifiable)
|
||||
function computeAgentScore(modelName) {
|
||||
@@ -2344,7 +2367,7 @@ function simulateApply() {
|
||||
progressStatus.textContent = 'Complete!';
|
||||
progressResult.classList.add('show');
|
||||
|
||||
const recs = INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0 ? INLINE_RECOMMENDATIONS : [];
|
||||
const recs = Object.values(agentData.agents || {}).filter(a => (a.current?.recommendations || []).length > 0);
|
||||
progressResultText.textContent = `✅ ${recs.length} recommendations applied. Run 'bun run sync:evolution' to update dashboard.`;
|
||||
}
|
||||
}
|
||||
@@ -2395,11 +2418,11 @@ function showResearchModal() {
|
||||
step.classList.add('done');
|
||||
});
|
||||
|
||||
const recs = INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0 ? INLINE_RECOMMENDATIONS : [];
|
||||
const modelsCount = new Set(recs.map(r => r.current_model).concat(recs.map(r => r.source_of_truth_model || r.recommended_model))).size;
|
||||
const recsCount = recs.filter(r => r.score_delta > 0).length;
|
||||
|
||||
document.getElementById('researchSummaryText').textContent =
|
||||
const recs = Object.values(agentData.agents || {}).filter(a => (a.current?.recommendations || []).length > 0);
|
||||
const modelsCount = new Set(recs.flatMap(a => [a.current?.model, a.current?.recommendations?.[0]?.target])).size;
|
||||
const recsCount = recs.filter(a => (a.current?.recommendations?.[0]?.score_delta || 0) > 0).length;
|
||||
|
||||
document.getElementById('researchSummaryText').textContent =
|
||||
`${modelsCount} models evaluated. ${recsCount} recommendations found. ${recs.length - recsCount} idle models detected.`;
|
||||
researchSummary.classList.add('show');
|
||||
}
|
||||
|
||||
@@ -983,6 +983,7 @@
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('gitea')">Gitea History</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('skills')">Skills</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('models')">Model Timeline</button>
|
||||
<button class="hm-tab-btn" onclick="switchHmTab('graph')">Performance Graph</button>
|
||||
</div>
|
||||
<div class="modal-body" id="hmModalBody">
|
||||
<!-- Content injected by JS -->
|
||||
@@ -1016,7 +1017,7 @@ Chart.defaults.borderColor = '#1e2d45';
|
||||
Chart.defaults.font.family = "'Inter', sans-serif";
|
||||
|
||||
// Inline recommendation data fallback (from model-research-latest.json)
|
||||
const INLINE_RECOMMENDATIONS = []; // REMOVED — data now comes from agentData, not hardcoded
|
||||
const INLINE_RECOMMENDATIONS = []; // Deprecated — data now comes from agentData.agents[].current.recommendations
|
||||
|
||||
// Inline benchmark data (fallback when embedded data doesn't have model_benchmarks)
|
||||
// SOURCE: agent-evolution/data/model-benchmarks-verified.json v2.0.0
|
||||
@@ -5736,33 +5737,15 @@ function renderOverview() {
|
||||
`).join('')
|
||||
: '<p style="color: var(--text-muted);">No history yet</p>';
|
||||
|
||||
// Recommended agents (use inline recs if available)
|
||||
let recAgents = [];
|
||||
if (INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0) {
|
||||
recAgents = INLINE_RECOMMENDATIONS.slice(0, 6).map(r => ({ agent: r.agent, current: { recommendations: [{ priority: r.impact, target: r.source_of_truth_model || r.recommended_model, reason: r.rationale, score_before: r.score_before, score_after: r.score_after, score_delta: r.score_delta }], model: r.current_model_in_agent_versions || r.current_model, category: 'Core Dev', description: '', benchmark: { fit_score: r.score_after || 0 } } }));
|
||||
} else {
|
||||
recAgents = Object.entries(agentData.agents)
|
||||
.filter(([_, a]) => a.current.recommendations && a.current.recommendations.length > 0)
|
||||
.slice(0, 6);
|
||||
}
|
||||
// Recommended agents from live data
|
||||
const recAgents = Object.entries(agentData.agents || {})
|
||||
.filter(([_, a]) => (a.current?.recommendations || []).length > 0)
|
||||
.slice(0, 6);
|
||||
|
||||
document.getElementById('recCount').textContent = recAgents.length;
|
||||
if (INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0) {
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map((r, idx) => renderRecCard({
|
||||
agent: r.agent,
|
||||
current_model: r.current?.model || '',
|
||||
recommended_model: r.current?.recommendations?.[0]?.target || '',
|
||||
impact: r.current?.recommendations?.[0]?.priority?.toLowerCase() || 'medium',
|
||||
score_before: r.current?.recommendations?.[0]?.score_before || 0,
|
||||
score_after: r.current?.recommendations?.[0]?.score_after || 0,
|
||||
score_delta: r.current?.recommendations?.[0]?.score_delta || 0,
|
||||
rationale: r.current?.recommendations?.[0]?.reason || ''
|
||||
}, idx)).join('');
|
||||
} else {
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map(([name, agent]) =>
|
||||
renderAgentCard(name, agent, true)
|
||||
).join('');
|
||||
}
|
||||
document.getElementById('recAgents').innerHTML = recAgents.map(([name, agent]) =>
|
||||
renderAgentCard(name, agent, true)
|
||||
).join('');
|
||||
}
|
||||
|
||||
// Render All Agents
|
||||
@@ -6068,7 +6051,7 @@ function renderHeatmap() {
|
||||
h += `<td style="background:${hmColor(s)};color:${hmText(s)};cursor:pointer" class="${cur ? 'hm-cur' : ''}" title="${ag.n} × ${hmModels[j].n}: ${s}"
|
||||
onmouseover="showTT(event,'${ag.n}','${hmModels[j].n} (${hmModels[j].p})',${s},${best},${cur},${hmModels[j].if})"
|
||||
onmouseout="hideTT()"
|
||||
onclick="showCellDetail('${hmModels[j].full}', '${ag.n}')">${s}${marks}</td>`;
|
||||
onclick="openHmModal(event, '${ag.n}', '${hmModels[j].n}', ${s}, ${hmModels[j].if})">${s}${marks}</td>`;
|
||||
});
|
||||
h += '</tr>';
|
||||
});
|
||||
@@ -6131,7 +6114,8 @@ function closeHmModal() {
|
||||
}
|
||||
|
||||
// Show cell detail modal with Chart.js line chart and prompt history
|
||||
function showCellDetail(modelName, agentName) {
|
||||
function showCellDetail(event, modelName, agentName) {
|
||||
event.stopPropagation();
|
||||
const agent = agentData.agents[agentName];
|
||||
if (!agent) {
|
||||
console.error('Agent not found:', agentName);
|
||||
@@ -6345,9 +6329,13 @@ function renderHmModalContent(tabName) {
|
||||
case 'models':
|
||||
content = renderModelsTab(agent);
|
||||
break;
|
||||
case 'graph':
|
||||
content = renderGraphTab(agent);
|
||||
break;
|
||||
}
|
||||
|
||||
body.innerHTML = `<div class="hm-tab-content active" style="display:block">${content}</div>`;
|
||||
if (tabName === 'graph') setTimeout(() => renderCellChart(hmCurrentAgent, agent.current?.model || ''), 50);
|
||||
}
|
||||
|
||||
function renderPromptTab(agent) {
|
||||
@@ -6486,6 +6474,46 @@ function renderModelsTab(agent) {
|
||||
return html;
|
||||
}
|
||||
|
||||
function renderGraphTab(agent) {
|
||||
return `
|
||||
<div style="margin-bottom:20px">
|
||||
<h3 style="margin-bottom:10px;color:var(--accent-cyan)">Performance Over Time</h3>
|
||||
<div style="position:relative;height:300px">
|
||||
<canvas id="cellChartCanvas"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin-bottom:10px;color:var(--accent-cyan)">Prompt Change History</h3>
|
||||
<div id="promptHistoryList" style="max-height:300px;overflow-y:auto">
|
||||
${renderPromptHistory(agent)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function renderPromptHistory(agent) {
|
||||
const promptChanges = (agent.history || []).filter(item => item.change_type === 'prompt_change');
|
||||
|
||||
if (promptChanges.length === 0) {
|
||||
return '<p style="color:var(--text-muted);text-align:center;padding:20px">No prompt change history found</p>';
|
||||
}
|
||||
|
||||
let html = '<ul style="list-style:none;padding:0">';
|
||||
promptChanges.forEach(change => {
|
||||
html += `
|
||||
<li style="padding:10px;border-bottom:1px solid var(--border);margin-bottom:10px">
|
||||
<div style="display:flex;justify-content:space-between;margin-bottom:5px">
|
||||
<span style="font-family:'JetBrains Mono',monospace;font-size:.8em;color:var(--text-muted)">${formatDate(change.date)}</span>
|
||||
<span style="font-family:'JetBrains Mono',monospace;font-size:.8em;color:var(--accent-cyan)">${change.commit ? change.commit.substring(0,7) : 'unknown'}</span>
|
||||
</div>
|
||||
<div style="font-size:.9em;color:var(--text-secondary)">${change.reason || 'No reason provided'}</div>
|
||||
</li>
|
||||
`;
|
||||
});
|
||||
html += '</ul>';
|
||||
return html;
|
||||
}
|
||||
|
||||
// Compute composite score for any model name
|
||||
// Formula (v2): IF_score * 0.85 + context_window_bonus (SWE-bench removed — all values unverifiable)
|
||||
function computeAgentScore(modelName) {
|
||||
@@ -6919,7 +6947,7 @@ function simulateApply() {
|
||||
progressStatus.textContent = 'Complete!';
|
||||
progressResult.classList.add('show');
|
||||
|
||||
const recs = INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0 ? INLINE_RECOMMENDATIONS : [];
|
||||
const recs = Object.values(agentData.agents || {}).filter(a => (a.current?.recommendations || []).length > 0);
|
||||
progressResultText.textContent = `✅ ${recs.length} recommendations applied. Run 'bun run sync:evolution' to update dashboard.`;
|
||||
}
|
||||
}
|
||||
@@ -6970,11 +6998,11 @@ function showResearchModal() {
|
||||
step.classList.add('done');
|
||||
});
|
||||
|
||||
const recs = INLINE_RECOMMENDATIONS && INLINE_RECOMMENDATIONS.length > 0 ? INLINE_RECOMMENDATIONS : [];
|
||||
const modelsCount = new Set(recs.map(r => r.current_model).concat(recs.map(r => r.source_of_truth_model || r.recommended_model))).size;
|
||||
const recsCount = recs.filter(r => r.score_delta > 0).length;
|
||||
|
||||
document.getElementById('researchSummaryText').textContent =
|
||||
const recs = Object.values(agentData.agents || {}).filter(a => (a.current?.recommendations || []).length > 0);
|
||||
const modelsCount = new Set(recs.flatMap(a => [a.current?.model, a.current?.recommendations?.[0]?.target])).size;
|
||||
const recsCount = recs.filter(a => (a.current?.recommendations?.[0]?.score_delta || 0) > 0).length;
|
||||
|
||||
document.getElementById('researchSummaryText').textContent =
|
||||
`${modelsCount} models evaluated. ${recsCount} recommendations found. ${recs.length - recsCount} idle models detected.`;
|
||||
researchSummary.classList.add('show');
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -259,12 +259,12 @@
|
||||
</div>
|
||||
|
||||
<div class="tabs" id="tabBar">
|
||||
<button class="tab-btn active" onclick="switchTab('overview')">Обзор</button>
|
||||
<button class="tab-btn" onclick="switchTab('groq')">Groq Free Tier</button>
|
||||
<button class="tab-btn" onclick="switchTab('models')">Все модели</button>
|
||||
<button class="tab-btn" onclick="switchTab('heatmap')">Матрица</button>
|
||||
<button class="tab-btn" onclick="switchTab('recs')">Рекомендации</button>
|
||||
<button class="tab-btn" onclick="switchTab('impact')">Анализ профита</button>
|
||||
<button class="tab-btn active" onclick="switchTab('overview', this)">Обзор</button>
|
||||
<button class="tab-btn" onclick="switchTab('groq', this)">Groq Free Tier</button>
|
||||
<button class="tab-btn" onclick="switchTab('models', this)">Все модели</button>
|
||||
<button class="tab-btn" onclick="switchTab('heatmap', this)">Матрица</button>
|
||||
<button class="tab-btn" onclick="switchTab('recs', this)">Рекомендации</button>
|
||||
<button class="tab-btn" onclick="switchTab('impact', this)">Анализ профита</button>
|
||||
</div>
|
||||
|
||||
<!-- ========== TAB: OVERVIEW ========== -->
|
||||
@@ -477,11 +477,11 @@ const impactData = (EMBEDDED_DATA.impact_data || []).map(d => ({
|
||||
}));
|
||||
|
||||
// ======================= RENDER =======================
|
||||
function switchTab(id) {
|
||||
function switchTab(id, el) {
|
||||
document.querySelectorAll('.tab-panel').forEach(p=>p.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-btn').forEach(b=>b.classList.remove('active'));
|
||||
document.getElementById('tab-'+id).classList.add('active');
|
||||
event.target.classList.add('active');
|
||||
(el || document.querySelector(`button[onclick*="switchTab('${id}')"]`)).classList.add('active');
|
||||
if(id==='impact') requestAnimationFrame(()=>setTimeout(drawChart,50));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user