feat: add Agent Evolution Dashboard
- Create agent-evolution/ directory with standalone dashboard - Add interactive HTML dashboard with agent/model matrix - Add heatmap view for agent-model compatibility scores - Add recommendations tab with optimization suggestions - Add Gitea integration preparation (history timeline) - Add Docker configuration for deployment - Add build scripts for standalone HTML generation - Add sync scripts for agent data synchronization - Add milestone and issues documentation - Add skills and rules for evolution sync - Update AGENTS.md with dashboard documentation - Update package.json with evolution scripts Features: - 28 agents with model assignments and fit scores - 8 models with benchmarks (SWE-bench, RULER, Terminal) - 11 recommendations for model optimization - History timeline with agent changes - Interactive modal windows for model details - Filter and search functionality - Russian language interface - Works offline (file://) with embedded data Docker: - Dockerfile for standalone deployment - docker-compose.evolution.yml - docker-run.sh/docker-run.bat scripts NPM scripts: - sync:evolution - sync and build dashboard - evolution:open - open in browser - evolution:dashboard - start dev server Status: PAUSED - foundation complete, Gitea integration pending
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
"paths": [".kilo/skills"]
|
||||
},
|
||||
"model": "qwen/qwen3.6-plus:free",
|
||||
"small_model": "llama-3.1-8b-instant",
|
||||
"small_model": "kilo-auto/free",
|
||||
"default_agent": "orchestrator",
|
||||
"agent": {
|
||||
"orchestrator": {
|
||||
|
||||
283
.kilo/rules/evolutionary-sync.md
Normal file
283
.kilo/rules/evolutionary-sync.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Evolutionary Sync Rules
|
||||
|
||||
Rules for synchronizing agent evolution data automatically.
|
||||
|
||||
## When to Sync
|
||||
|
||||
### Automatic Sync Triggers
|
||||
|
||||
1. **After each completed issue**
|
||||
- When agent completes task and posts Gitea comment
|
||||
- Extract performance metrics from comment
|
||||
|
||||
2. **On model change**
|
||||
- When agent model is updated in kilo.jsonc
|
||||
- When capability-index.yaml is modified
|
||||
|
||||
3. **On agent file change**
|
||||
- When .kilo/agents/*.md files are modified
|
||||
- On create/delete of agent files
|
||||
|
||||
4. **On prompt update**
|
||||
- When agent receives prompt optimization
|
||||
- Track optimization improvements
|
||||
|
||||
### Manual Sync Triggers
|
||||
|
||||
```bash
|
||||
# Sync from all sources
|
||||
bun run sync:evolution
|
||||
|
||||
# Sync specific source
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts --source git
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts --source gitea
|
||||
|
||||
# Open dashboard
|
||||
bun run evolution:dashboard
|
||||
bun run evolution:open
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Data Sources │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ .kilo/agents/*.md ──► Parse frontmatter, model │
|
||||
│ .kilo/kilo.jsonc ──► Model assignments │
|
||||
│ .kilo/capability-index.yaml ──► Capabilities, routing │
|
||||
│ Git History ──► Change timeline │
|
||||
│ Gitea Issue Comments ──► Performance scores │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ agent-evolution/data/ │
|
||||
│ agent-versions.json │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ { │
|
||||
│ "agents": { │
|
||||
│ "lead-developer": { │
|
||||
│ "current": { model, provider, fit_score, ... }, │
|
||||
│ "history": [ { model_change, ... } ], │
|
||||
│ "performance_log": [ { score, issue, ... } ] │
|
||||
│ } │
|
||||
│ } │
|
||||
│ } │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ agent-evolution/index.html │
|
||||
│ Interactive Dashboard │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ • Overview - Stats, recent changes, recommendations │
|
||||
│ • All Agents - Filterable cards with history │
|
||||
│ • Timeline - Full evolution history │
|
||||
│ • Recommendations - Export, priority-based view │
|
||||
│ • Model Matrix - Agent × Model mapping │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Recording Changes
|
||||
|
||||
### From Gitea Comments
|
||||
|
||||
Agent comments should follow this format:
|
||||
|
||||
```markdown
|
||||
## ✅ agent-name completed
|
||||
|
||||
**Score**: X/10
|
||||
**Duration**: X.Xh
|
||||
**Files**: file1.ts, file2.ts
|
||||
|
||||
### Notes
|
||||
- Description of work done
|
||||
- Key decisions made
|
||||
- Issues encountered
|
||||
```
|
||||
|
||||
Extraction:
|
||||
- `agent-name` → agent name
|
||||
- `Score` → performance score (1-10)
|
||||
- `Duration` → execution time
|
||||
- `Files` → files modified
|
||||
|
||||
### From Git Commits
|
||||
|
||||
Commit message patterns:
|
||||
- `feat: add flutter-developer agent` → agent_created
|
||||
- `fix: update security-auditor model to nemotron-3-super` → model_change
|
||||
- `docs: update lead-developer prompt` → prompt_change
|
||||
|
||||
## Gitea Webhook Setup
|
||||
|
||||
1. **Create webhook in Gitea**
|
||||
- Target URL: `http://localhost:3000/api/evolution/webhook`
|
||||
- Events: `issue_comment`, `issues`
|
||||
|
||||
2. **Webhook payload handling**
|
||||
```typescript
|
||||
// In agent-evolution/scripts/gitea-webhook.ts
|
||||
app.post('/api/evolution/webhook', async (req, res) => {
|
||||
const { action, issue, comment } = req.body;
|
||||
|
||||
if (action === 'created' && comment?.body.includes('## ✅')) {
|
||||
await recordAgentPerformance(issue, comment);
|
||||
}
|
||||
|
||||
res.json({ success: true });
|
||||
});
|
||||
```
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
### Tracked Metrics
|
||||
|
||||
For each agent execution:
|
||||
|
||||
| Metric | Source | Format |
|
||||
|--------|--------|--------|
|
||||
| Score | Gitea comment | X/10 |
|
||||
| Duration | Agent timing | milliseconds |
|
||||
| Success | Exit status | boolean |
|
||||
| Files | Gitea comment | count |
|
||||
| Issue | Context | number |
|
||||
|
||||
### Aggregated Metrics
|
||||
|
||||
| Metric | Calculation | Use |
|
||||
|--------|-------------|-----|
|
||||
| Average Score | `sum(scores) / count` | Agent effectiveness |
|
||||
| Success Rate | `successes / total * 100` | Reliability |
|
||||
| Average Duration | `sum(durations) / count` | Speed |
|
||||
| Files per Task | `sum(files) / count` | Scope |
|
||||
|
||||
## Recommendations Generation
|
||||
|
||||
### Priority Levels
|
||||
|
||||
| Priority | Criteria | Action |
|
||||
|----------|----------|--------|
|
||||
| Critical | Fit score < 70 | Immediate update |
|
||||
| High | Model unavailable | Switch to fallback |
|
||||
| Medium | Better model available | Consider upgrade |
|
||||
| Low | Optimization possible | Optional improvement |
|
||||
|
||||
### Example Recommendation
|
||||
|
||||
```json
|
||||
{
|
||||
"agent": "requirement-refiner",
|
||||
"recommendations": [{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "+22% quality, 1M context for specifications",
|
||||
"priority": "critical"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Evolution Rules
|
||||
|
||||
### When Model Change is Recorded
|
||||
|
||||
1. **Detect change**
|
||||
- Compare current.model with previous value
|
||||
- Extract reason from commit message
|
||||
|
||||
2. **Record in history**
|
||||
```json
|
||||
{
|
||||
"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 security analysis"
|
||||
}
|
||||
```
|
||||
|
||||
3. **Update current**
|
||||
- Set current.model to new value
|
||||
- Update provider if changed
|
||||
- Recalculate fit score
|
||||
|
||||
### When Performance Drops
|
||||
|
||||
1. **Detect pattern**
|
||||
- Last 5 scores average < 7
|
||||
- Success rate < 80%
|
||||
|
||||
2. **Generate recommendation**
|
||||
- Suggest model upgrade
|
||||
- Trigger prompt-optimizer
|
||||
|
||||
3. **Notify via Gitea comment**
|
||||
- Post to related issue
|
||||
- Include improvement suggestions
|
||||
|
||||
## Integration in Pipeline
|
||||
|
||||
Add to post-pipeline:
|
||||
|
||||
```yaml
|
||||
# .kilo/commands/pipeline.md
|
||||
post_steps:
|
||||
- name: sync_evolution
|
||||
run: bun run sync:evolution
|
||||
- name: check_recommendations
|
||||
run: bun run agent-evolution/scripts/check-recommendations.ts
|
||||
```
|
||||
|
||||
## Dashboard Access
|
||||
|
||||
```bash
|
||||
# Start local server
|
||||
bun run evolution:dashboard
|
||||
|
||||
# Open in browser
|
||||
bun run evolution:open
|
||||
# or visit http://localhost:3001
|
||||
```
|
||||
|
||||
## API Endpoints (Future)
|
||||
|
||||
```typescript
|
||||
// GET /api/evolution/agents
|
||||
// Returns all agents with current state
|
||||
|
||||
// GET /api/evolution/agents/:name/history
|
||||
// Returns agent history
|
||||
|
||||
// GET /api/evolution/recommendations
|
||||
// Returns pending recommendations
|
||||
|
||||
// POST /api/evolution/agents/:name/apply
|
||||
// Apply recommendation
|
||||
|
||||
// POST /api/evolution/sync
|
||||
// Trigger manual sync
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Sync after every pipeline run**
|
||||
- Captures model changes
|
||||
- Records performance
|
||||
|
||||
2. **Review dashboard weekly**
|
||||
- Check pending recommendations
|
||||
- Apply critical updates
|
||||
|
||||
3. **Track before/after metrics**
|
||||
- When applying changes
|
||||
- Compare performance
|
||||
|
||||
4. **Keep history clean**
|
||||
- Deduplicate entries
|
||||
- Merge related changes
|
||||
|
||||
5. **Use consistent naming**
|
||||
- Agent names match file names
|
||||
- Model IDs match capability-index.yaml
|
||||
275
.kilo/skills/evolution-sync/SKILL.md
Normal file
275
.kilo/skills/evolution-sync/SKILL.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Evolution Sync Skill
|
||||
|
||||
Synchronizes agent evolution data from multiple sources.
|
||||
|
||||
## Purpose
|
||||
|
||||
Keeps the agent evolution dashboard up-to-date by:
|
||||
1. Parsing git history for agent changes
|
||||
2. Extracting current models from kilo.jsonc and capability-index.yaml
|
||||
3. Recording performance metrics from Gitea issue comments
|
||||
4. Tracking model and prompt changes over time
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Sync from all sources
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts
|
||||
|
||||
# Sync specific source
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts --source git
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts --source gitea
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### 1. Git History
|
||||
|
||||
Parses commit messages for agent-related changes:
|
||||
|
||||
```bash
|
||||
git log --all --oneline -- ".kilo/agents/"
|
||||
```
|
||||
|
||||
Detects patterns like:
|
||||
- `feat: add flutter-developer agent`
|
||||
- `fix: update security-auditor model`
|
||||
- `docs: update lead-developer prompt`
|
||||
|
||||
### 2. Configuration Files
|
||||
|
||||
**kilo.jsonc** - Primary model assignments:
|
||||
```json
|
||||
{
|
||||
"agent": {
|
||||
"lead-developer": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**capability-index.yaml** - Capability mappings:
|
||||
```yaml
|
||||
agents:
|
||||
lead-developer:
|
||||
model: ollama-cloud/qwen3-coder:480b
|
||||
capabilities: [code_writing, refactoring]
|
||||
```
|
||||
|
||||
### 3. Gitea Integration
|
||||
|
||||
Extracts performance data from issue comments:
|
||||
|
||||
```typescript
|
||||
// Comment format
|
||||
// ## ✅ lead-developer completed
|
||||
// **Score**: 8/10
|
||||
// **Duration**: 1.2h
|
||||
// **Files**: src/auth.ts, src/user.ts
|
||||
```
|
||||
|
||||
## Function Reference
|
||||
|
||||
### syncEvolutionData()
|
||||
|
||||
Main sync function:
|
||||
|
||||
```typescript
|
||||
async function syncEvolutionData(): Promise<void> {
|
||||
// 1. Load agent files
|
||||
const agentFiles = loadAgentFiles();
|
||||
|
||||
// 2. Load capability index
|
||||
const capabilityIndex = loadCapabilityIndex();
|
||||
|
||||
// 3. Load kilo config
|
||||
const kiloConfig = loadKiloConfig();
|
||||
|
||||
// 4. Get git history
|
||||
const gitHistory = await getGitHistory();
|
||||
|
||||
// 5. Merge all sources
|
||||
const merged = mergeConfigs(agentFiles, capabilityIndex, kiloConfig);
|
||||
|
||||
// 6. Update evolution data
|
||||
updateEvolutionData(merged, gitHistory);
|
||||
}
|
||||
```
|
||||
|
||||
### recordAgentChange()
|
||||
|
||||
Records a model or prompt change:
|
||||
|
||||
```typescript
|
||||
interface AgentChange {
|
||||
agent: string;
|
||||
type: 'model_change' | 'prompt_change' | 'capability_change';
|
||||
from: string | null;
|
||||
to: string;
|
||||
reason: string;
|
||||
issue_number?: number;
|
||||
}
|
||||
|
||||
function recordAgentChange(change: AgentChange): void {
|
||||
const evolution = loadEvolutionData();
|
||||
|
||||
if (!evolution.agents[change.agent]) {
|
||||
evolution.agents[change.agent] = {
|
||||
current: { model: change.to, ... },
|
||||
history: [],
|
||||
performance_log: []
|
||||
};
|
||||
}
|
||||
|
||||
// Add to history
|
||||
evolution.agents[change.agent].history.push({
|
||||
date: new Date().toISOString(),
|
||||
commit: 'manual',
|
||||
type: change.type,
|
||||
from: change.from,
|
||||
to: change.to,
|
||||
reason: change.reason,
|
||||
source: 'gitea'
|
||||
});
|
||||
|
||||
saveEvolutionData(evolution);
|
||||
}
|
||||
```
|
||||
|
||||
### recordPerformance()
|
||||
|
||||
Records agent performance from issue:
|
||||
|
||||
```typescript
|
||||
interface AgentPerformance {
|
||||
agent: string;
|
||||
issue: number;
|
||||
score: number;
|
||||
duration_ms: number;
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
function recordPerformance(perf: AgentPerformance): void {
|
||||
const evolution = loadEvolutionData();
|
||||
|
||||
if (!evolution.agents[perf.agent]) return;
|
||||
|
||||
evolution.agents[perf.agent].performance_log.push({
|
||||
date: new Date().toISOString(),
|
||||
issue: perf.issue,
|
||||
score: perf.score,
|
||||
duration_ms: perf.duration_ms,
|
||||
success: perf.success
|
||||
});
|
||||
|
||||
saveEvolutionData(evolution);
|
||||
}
|
||||
```
|
||||
|
||||
## Pipeline Integration
|
||||
|
||||
Add to `.kilo/commands/pipeline.md`:
|
||||
|
||||
```yaml
|
||||
post_pipeline:
|
||||
- name: sync_evolution
|
||||
description: Sync agent evolution data after pipeline run
|
||||
command: bun run agent-evolution/scripts/sync-agent-history.ts
|
||||
```
|
||||
|
||||
## Gitea Webhook Handler
|
||||
|
||||
```typescript
|
||||
// Parse agent completion comment
|
||||
app.post('/api/evolution/webhook', async (req, res) => {
|
||||
const { issue, comment } = req.body;
|
||||
|
||||
// Check for agent completion marker
|
||||
const agentMatch = comment.match(/## ✅ (\w+-?\w*) completed/);
|
||||
const scoreMatch = comment.match(/\*\*Score\*\*: (\d+)\/10/);
|
||||
|
||||
if (agentMatch && scoreMatch) {
|
||||
await recordPerformance({
|
||||
agent: agentMatch[1],
|
||||
issue: issue.number,
|
||||
score: parseInt(scoreMatch[1]),
|
||||
duration_ms: 0, // Parse from duration
|
||||
success: true
|
||||
});
|
||||
}
|
||||
|
||||
// Check for model change
|
||||
const modelMatch = comment.match(/Model changed: (\S+) → (\S+)/);
|
||||
if (modelMatch) {
|
||||
await recordAgentChange({
|
||||
agent: agentMatch[1],
|
||||
type: 'model_change',
|
||||
from: modelMatch[1],
|
||||
to: modelMatch[2],
|
||||
reason: 'Manual update',
|
||||
issue_number: issue.number
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Files Structure
|
||||
|
||||
```
|
||||
agent-evolution/
|
||||
├── data/
|
||||
│ ├── agent-versions.json # Current state + history
|
||||
│ └── agent-versions.schema.json # JSON schema
|
||||
├── scripts/
|
||||
│ ├── sync-agent-history.ts # Main sync script
|
||||
│ ├── parse-git-history.ts # Git parser
|
||||
│ └── gitea-webhook.ts # Webhook handler
|
||||
└── index.html # Dashboard UI
|
||||
```
|
||||
|
||||
## Dashboard Features
|
||||
|
||||
1. **Overview Tab**
|
||||
- Total agents, with history, pending recommendations
|
||||
- Recent changes timeline
|
||||
- Critical recommendations
|
||||
|
||||
2. **All Agents Tab**
|
||||
- Filterable by category
|
||||
- Searchable
|
||||
- Shows model, fit score, capabilities
|
||||
|
||||
3. **Timeline Tab**
|
||||
- Full evolution history
|
||||
- Model changes
|
||||
- Prompt changes
|
||||
|
||||
4. **Recommendations Tab**
|
||||
- Export to JSON
|
||||
- Priority-based sorting
|
||||
- One-click apply
|
||||
|
||||
5. **Model Matrix Tab**
|
||||
- Agent × Model mapping
|
||||
- Fit scores
|
||||
- Provider distribution
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Run sync after each pipeline**
|
||||
- Ensures history is up-to-date
|
||||
- Captures model changes
|
||||
|
||||
2. **Record performance from every issue**
|
||||
- Track agent effectiveness
|
||||
- Identify improvement patterns
|
||||
|
||||
3. **Apply recommendations systematically**
|
||||
- Use priority: critical → high → medium
|
||||
- Track before/after performance
|
||||
|
||||
4. **Monitor evolution trends**
|
||||
- Which agents change most frequently
|
||||
- Which models perform best
|
||||
- Category-specific optimizations
|
||||
59
AGENTS.md
59
AGENTS.md
@@ -225,6 +225,65 @@ const runner = await createPipelineRunner({
|
||||
await runner.run({ issueNumber: 42 })
|
||||
```
|
||||
|
||||
## Agent Evolution Dashboard
|
||||
|
||||
Track agent model changes, performance, and recommendations in real-time.
|
||||
|
||||
### Access
|
||||
|
||||
```bash
|
||||
# Sync agent data
|
||||
bun run sync:evolution
|
||||
|
||||
# Open dashboard
|
||||
bun run evolution:dashboard
|
||||
bun run evolution:open
|
||||
# or visit http://localhost:3001
|
||||
```
|
||||
|
||||
### Dashboard Tabs
|
||||
|
||||
| Tab | Description |
|
||||
|-----|-------------|
|
||||
| **Overview** | Stats, recent changes, pending recommendations |
|
||||
| **All Agents** | Filterable agent cards with history |
|
||||
| **Timeline** | Full evolution history |
|
||||
| **Recommendations** | Priority-based model suggestions |
|
||||
| **Model Matrix** | Agent × Model mapping with fit scores |
|
||||
|
||||
### Data Sources
|
||||
|
||||
| Source | What it tracks |
|
||||
|--------|----------------|
|
||||
| `.kilo/agents/*.md` | Model, description, capabilities |
|
||||
| `.kilo/kilo.jsonc` | Model assignments |
|
||||
| `.kilo/capability-index.yaml` | Capability routing |
|
||||
| Git History | Model and prompt changes |
|
||||
| Gitea Comments | Performance scores |
|
||||
|
||||
### Evolution Data Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"lead-developer": {
|
||||
"current": { "model": "qwen3-coder:480b", "fit_score": 92 },
|
||||
"history": [{ "type": "model_change", "from": "deepseek", "to": "qwen3" }],
|
||||
"performance_log": [{ "issue": 42, "score": 8, "success": true }]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Recommendations Priority
|
||||
|
||||
| Priority | When | Example |
|
||||
|----------|------|---------|
|
||||
| **Critical** | Fit score < 70 | Immediate model change required |
|
||||
| **High** | Model unavailable | Switch to fallback |
|
||||
| **Medium** | Better model available | Consider upgrade |
|
||||
| **Low** | Optimization possible | Optional improvement |
|
||||
|
||||
## Code Style
|
||||
|
||||
- Use TypeScript for new files
|
||||
|
||||
30
agent-evolution/Dockerfile
Normal file
30
agent-evolution/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
# Agent Evolution Dashboard Dockerfile
|
||||
# Standalone version - works from file:// or HTTP
|
||||
|
||||
# Build stage - run sync to generate standalone HTML
|
||||
FROM oven/bun:1 AS builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy config files for sync
|
||||
COPY .kilo/agents/*.md ./.kilo/agents/
|
||||
COPY .kilo/capability-index.yaml ./.kilo/
|
||||
COPY .kilo/kilo.jsonc ./.kilo/
|
||||
COPY agent-evolution/ ./agent-evolution/
|
||||
|
||||
# Run sync to generate standalone HTML with embedded data
|
||||
RUN bun agent-evolution/scripts/sync-agent-history.ts || true
|
||||
|
||||
# Production stage - Python HTTP server
|
||||
FROM python:3.12-alpine AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy standalone HTML (embedded data)
|
||||
COPY --from=builder /build/agent-evolution/index.standalone.html ./index.html
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3001
|
||||
|
||||
# Simple HTTP server (no CORS issues)
|
||||
CMD ["python3", "-m", "http.server", "3001"]
|
||||
182
agent-evolution/MILESTONE_ISSUES.md
Normal file
182
agent-evolution/MILESTONE_ISSUES.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Agent Evolution Dashboard - Milestone & Issues
|
||||
|
||||
## Milestone: Agent Evolution Dashboard
|
||||
|
||||
**Title:** Agent Evolution Dashboard
|
||||
**Description:** Интерактивная панель для отслеживания эволюции агентной системы APAW с интеграцией Gitea
|
||||
**Due Date:** 2026-04-19 (2 недели)
|
||||
**State:** Open
|
||||
|
||||
---
|
||||
|
||||
## Issues
|
||||
|
||||
### Issue 1: Рефакторинг из архива в root-директорию
|
||||
|
||||
**Title:** Рефакторинг: перенести agent model research из archive в agent-evolution
|
||||
**Labels:** `refactor`, `high-priority`
|
||||
**Milestone:** Agent Evolution Dashboard
|
||||
|
||||
**Описание:**
|
||||
Файл `archive/apaw_agent_model_research_v3.html` содержит ценную информацию о моделях и рекомендациях. Необходимо:
|
||||
|
||||
1. ✅ Создать директорию `agent-evolution/` в корне проекта
|
||||
2. ✅ Создать `agent-evolution/index.standalone.html` с интегрированными данными
|
||||
3. ✅ Создать `agent-evolution/data/agent-versions.json` с актуальными данными
|
||||
4. ✅ Создать `agent-evolution/scripts/build-standalone.cjs` для генерации
|
||||
5. 🔄 Удалить `archive/apaw_agent_model_research_v3.html` после переноса данных
|
||||
|
||||
**Критерии приёмки:**
|
||||
- [ ] Все данные из архива интегрированы
|
||||
- [ ] Дашборд работает автономно (file://)
|
||||
- [ ] Данные актуальны на момент коммита
|
||||
|
||||
---
|
||||
|
||||
### Issue 2: Интеграция с Gitea для истории изменений
|
||||
|
||||
**Title:** Интеграция Agent Evolution с Gitea API
|
||||
**Labels:** `enhancement`, `integration`, `high-priority`
|
||||
**Milestone:** Agent Evolution Dashboard
|
||||
|
||||
**Описание:**
|
||||
Требуется интегрировать дашборд с Gitea для:
|
||||
|
||||
1. Получения истории изменений моделей из issue comments
|
||||
2. Парсинга комментариев агентов (формат `## ✅ agent-name completed`)
|
||||
3. Извлечения метрик производительности (Score, Duration, Files)
|
||||
4. Отображения реальной истории в дашборде
|
||||
|
||||
**Требования:**
|
||||
- API endpoint `/api/evolution/history` для получения истории
|
||||
- Webhook для автоматического обновления при новых комментариях
|
||||
- Кэширование данных локально
|
||||
- Fallback на локальные данные при недоступности Gitea
|
||||
|
||||
**Критерии приёмки:**
|
||||
- [ ] История загружается из Gitea при наличии API
|
||||
- [ ] Fallback на локальные данные
|
||||
- [ ] Webhook обрабатывает `issue_comment` события
|
||||
- [ ] Данные обновляются в реальном времени
|
||||
|
||||
---
|
||||
|
||||
### Issue 3: Синхронизация с capability-index.yaml и kilo.jsonc
|
||||
|
||||
**Title:** Автоматическая синхронизация эволюции агентов
|
||||
**Labels:** `automation`, `sync`, `medium-priority`
|
||||
**Milestone:** Agent Evolution Dashboard
|
||||
|
||||
**Описание:**
|
||||
Создать автоматическую синхронизацию данных эволюции из:
|
||||
|
||||
1. `.kilo/agents/*.md` - frontmatter с моделями
|
||||
2. `.kilo/capability-index.yaml` - capabilities и routing
|
||||
3. `.kilo/kilo.jsonc` - model assignments
|
||||
4. Git history - история изменений
|
||||
5. Gitea issue comments - performance metrics
|
||||
|
||||
**Скрипты:**
|
||||
- `agent-evolution/scripts/sync-agent-history.ts` - основная синхронизация
|
||||
- `agent-evolution/scripts/build-standalone.cjs` - генерация HTML
|
||||
|
||||
**NPM Scripts:**
|
||||
```json
|
||||
"sync:evolution": "bun run agent-evolution/scripts/sync-agent-history.ts && node agent-evolution/scripts/build-standalone.cjs",
|
||||
"evolution:dashboard": "bunx serve agent-evolution -l 3001",
|
||||
"evolution:open": "start agent-evolution/index.standalone.html"
|
||||
```
|
||||
|
||||
**Критерии приёмки:**
|
||||
- [ ] Синхронизация работает корректно
|
||||
- [ ] HTML генерируется автоматически
|
||||
- [ ] Данные консистентны
|
||||
|
||||
---
|
||||
|
||||
### Issue 4: Документация и README
|
||||
|
||||
**Title:** Документация Agent Evolution Dashboard
|
||||
**Labels:** `documentation`, `low-priority`
|
||||
**Milestone:** Agent Evolution Dashboard
|
||||
|
||||
**Описание:**
|
||||
Создать полную документацию:
|
||||
|
||||
1. ✅ `agent-evolution/README.md` - основная документация
|
||||
2. 🔄 `docs/agent-evolution.md` - техническая документация
|
||||
3. 🔄 Инструкция по запуску в `AGENTS.md`
|
||||
4. ✅ Schema: `agent-evolution/data/agent-versions.schema.json`
|
||||
5. ✅ Skills: `.kilo/skills/evolution-sync/SKILL.md`
|
||||
6. ✅ Rules: `.kilo/rules/evolutionary-sync.md`
|
||||
|
||||
**Критерии приёмки:**
|
||||
- [ ] README покрывает все сценарии использования
|
||||
- [ ] Техническая документация описывает API
|
||||
- [ ] Есть примеры кода
|
||||
|
||||
---
|
||||
|
||||
### Issue 5: Docker контейнер для дашборда
|
||||
|
||||
**Title:** Docker-изация Agent Evolution Dashboard
|
||||
**Labels:** `docker`, `deployment`, `low-priority`
|
||||
**Milestone:** Agent Evolution Dashboard
|
||||
|
||||
**Описание:**
|
||||
Упаковать дашборд в Docker для простого деплоя:
|
||||
|
||||
**Файлы:**
|
||||
- ✅ `agent-evolution/Dockerfile`
|
||||
- ✅ `docker-compose.evolution.yml`
|
||||
- ✅ `agent-evolution/docker-run.sh` (Linux/macOS)
|
||||
- ✅ `agent-evolution/docker-run.bat` (Windows)
|
||||
|
||||
**Команды:**
|
||||
```bash
|
||||
# Linux/macOS
|
||||
bash agent-evolution/docker-run.sh restart
|
||||
|
||||
# Windows
|
||||
agent-evolution\docker-run.bat restart
|
||||
|
||||
# Docker Compose
|
||||
docker-compose -f docker-compose.evolution.yml up -d
|
||||
```
|
||||
|
||||
**Критерии приёмки:**
|
||||
- [ ] Docker образ собирается
|
||||
- [ ] Контейнер запускается на порту 3001
|
||||
- [ ] Данные монтируются корректно
|
||||
|
||||
---
|
||||
|
||||
## Статус напраления
|
||||
|
||||
**Текущий статус:** `PAUSED` - приостановлено до следующего спринта
|
||||
|
||||
**Причина паузы:**
|
||||
Базовая инфраструктура создана:
|
||||
- ✅ Структура директорий `agent-evolution/`
|
||||
- ✅ Данные интегрированы в HTML
|
||||
- ✅ Скрипты синхронизации созданы
|
||||
- ✅ Docker контейнер настроен
|
||||
- ✅ Документация написана
|
||||
|
||||
**Что осталось:**
|
||||
- 🔄 Issue #2: Интеграция с Gitea API (требует backend)
|
||||
- 🔄 Issue #3: Полная синхронизация (требует тестирования)
|
||||
- 🔄 Issue #4: Расширенная документация
|
||||
|
||||
**Резюме работы:**
|
||||
Создана полноценная инфраструктура для отслеживания эволюции агентной системы. Дашборд работает автономно без сервера, включает данные о 28 агентах, 8 моделях, рекомендациях по оптимизации. Подготовлен foundation для будущей интеграции с Gitea.
|
||||
|
||||
---
|
||||
|
||||
## Quick Links
|
||||
|
||||
- Dashboard: `agent-evolution/index.standalone.html`
|
||||
- Data: `agent-evolution/data/agent-versions.json`
|
||||
- Build Script: `agent-evolution/scripts/build-standalone.cjs`
|
||||
- Docker: `docker-compose -f docker-compose.evolution.yml up -d`
|
||||
- NPM: `bun run sync:evolution`
|
||||
409
agent-evolution/README.md
Normal file
409
agent-evolution/README.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# Agent Evolution Dashboard
|
||||
|
||||
Интерактивная панель для отслеживания эволюции агентной системы APAW.
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### Синхронизация данных
|
||||
|
||||
```bash
|
||||
# Синхронизировать агентов + построить standalone HTML
|
||||
bun run sync:evolution
|
||||
|
||||
# Только построить HTML из существующих данных
|
||||
bun run evolution:build
|
||||
```
|
||||
|
||||
### Открыть в браузере
|
||||
|
||||
**Способ 1: Локальный файл (рекомендуется)**
|
||||
|
||||
```bash
|
||||
# Windows
|
||||
start agent-evolution\index.standalone.html
|
||||
|
||||
# macOS
|
||||
open agent-evolution/index.standalone.html
|
||||
|
||||
# Linux
|
||||
xdg-open agent-evolution/index.standalone.html
|
||||
|
||||
# Или через npm
|
||||
bun run evolution:open
|
||||
```
|
||||
|
||||
**Способ 2: HTTP сервер**
|
||||
|
||||
```bash
|
||||
cd agent-evolution
|
||||
python -m http.server 3001
|
||||
|
||||
# Открыть http://localhost:3001
|
||||
```
|
||||
|
||||
**Способ 3: Docker**
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
bash agent-evolution/docker-run.sh restart
|
||||
|
||||
# Windows
|
||||
agent-evolution\docker-run.bat restart
|
||||
|
||||
# Открыть http://localhost:3001
|
||||
```
|
||||
|
||||
## 📁 Структура файлов
|
||||
|
||||
### Быстрый запуск
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
bash agent-evolution/docker-run.sh restart
|
||||
|
||||
# Windows
|
||||
agent-evolution\docker-run.bat restart
|
||||
|
||||
# Открыть в браузере
|
||||
http://localhost:3001
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```bash
|
||||
# Стандартный запуск
|
||||
docker-compose -f docker-compose.evolution.yml up -d
|
||||
|
||||
# С nginx reverse proxy
|
||||
docker-compose -f docker-compose.evolution.yml --profile nginx up -d
|
||||
|
||||
# Остановка
|
||||
docker-compose -f docker-compose.evolution.yml down
|
||||
```
|
||||
|
||||
### Управление контейнером
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
bash agent-evolution/docker-run.sh build # Собрать образ
|
||||
bash agent-evolution/docker-run.sh run # Запустить контейнер
|
||||
bash agent-evolution/docker-run.sh stop # Остановить
|
||||
bash agent-evolution/docker-run.sh restart # Пересобрать и запустить
|
||||
bash agent-evolution/docker-run.sh logs # Логи
|
||||
bash agent-evolution/docker-run.sh open # Открыть в браузере
|
||||
bash agent-evolution/docker-run.sh sync # Синхронизировать данные
|
||||
bash agent-evolution/docker-run.sh status # Статус
|
||||
bash agent-evolution/docker-run.sh clean # Удалить всё
|
||||
bash agent-evolution/docker-run.sh dev # Dev режим с hot reload
|
||||
|
||||
# Windows
|
||||
agent-evolution\docker-run.bat build
|
||||
agent-evolution\docker-run.bat run
|
||||
agent-evolution\docker-run.bat stop
|
||||
agent-evolution\docker-run.bat restart
|
||||
agent-evolution\docker-run.bat logs
|
||||
agent-evolution\docker-run.bat open
|
||||
agent-evolution\docker-run.bat sync
|
||||
agent-evolution\docker-run.bat status
|
||||
agent-evolution\docker-run.bat clean
|
||||
agent-evolution\docker-run.bat dev
|
||||
```
|
||||
|
||||
### NPM Scripts
|
||||
|
||||
```bash
|
||||
bun run evolution:build # Собрать Docker образ
|
||||
bun run evolution:run # Запустить контейнер
|
||||
bun run evolution:stop # Остановить
|
||||
bun run evolution:dev # Docker Compose
|
||||
bun run evolution:logs # Логи
|
||||
```
|
||||
|
||||
## Структура
|
||||
|
||||
```
|
||||
agent-evolution/
|
||||
├── data/
|
||||
│ ├── agent-versions.json # Текущее состояние + история
|
||||
│ └── agent-versions.schema.json # JSON Schema
|
||||
├── scripts/
|
||||
│ └── sync-agent-history.ts # Скрипт синхронизации
|
||||
├── index.html # Дашборд UI
|
||||
└── README.md # Этот файл
|
||||
```
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```bash
|
||||
# Синхронизировать данные агентов
|
||||
bun run sync:evolution
|
||||
|
||||
# Запустить дашборд
|
||||
bun run evolution:dashboard
|
||||
|
||||
# Открыть в браузере
|
||||
bun run evolution:open
|
||||
# или http://localhost:3001
|
||||
```
|
||||
|
||||
## Возможности дашборда
|
||||
|
||||
### 1. Overview — Обзор
|
||||
|
||||
- **Статистика**: общее количество агентов, с историей, рекомендации
|
||||
- **Recent Changes**: последние изменения моделей и промптов
|
||||
- **Pending Recommendations**: критические рекомендации по обновлению
|
||||
|
||||
### 2. All Agents — Все агенты
|
||||
|
||||
- Поиск и фильтрация по категориям
|
||||
- Карточки агентов с:
|
||||
- Текущей моделью
|
||||
- Fit Score
|
||||
- Количеством capability
|
||||
- Историей изменений
|
||||
|
||||
### 3. Timeline — История
|
||||
|
||||
- Полная хронология изменений
|
||||
- Типы событий: model_change, prompt_change, agent_created
|
||||
- Фильтрация по дате
|
||||
|
||||
### 4. Recommendations — Рекомендации
|
||||
|
||||
- Агенты с pending recommendations
|
||||
- Приоритеты: critical, high, medium, low
|
||||
- Экспорт в JSON
|
||||
|
||||
### 5. Model Matrix — Матрица моделей
|
||||
|
||||
- Таблица Agent × Model
|
||||
- Fit Score для каждой пары
|
||||
- Визуализация provider distribution
|
||||
|
||||
## Источники данных
|
||||
|
||||
### 1. Agent Files (`.kilo/agents/*.md`)
|
||||
|
||||
```yaml
|
||||
---
|
||||
model: ollama-cloud/qwen3-coder:480b
|
||||
description: Primary code writer
|
||||
mode: subagent
|
||||
color: "#DC2626"
|
||||
---
|
||||
```
|
||||
|
||||
### 2. Capability Index (`.kilo/capability-index.yaml`)
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
lead-developer:
|
||||
model: ollama-cloud/qwen3-coder:480b
|
||||
capabilities: [code_writing, refactoring]
|
||||
```
|
||||
|
||||
### 3. Kilo Config (`.kilo/kilo.jsonc`)
|
||||
|
||||
```json
|
||||
{
|
||||
"agent": {
|
||||
"lead-developer": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Git History
|
||||
|
||||
```bash
|
||||
git log --all --oneline -- ".kilo/agents/"
|
||||
```
|
||||
|
||||
### 5. Gitea Issue Comments
|
||||
|
||||
```markdown
|
||||
## ✅ lead-developer completed
|
||||
|
||||
**Score**: 8/10
|
||||
**Duration**: 1.2h
|
||||
**Files**: src/auth.ts, src/user.ts
|
||||
```
|
||||
|
||||
## JSON Schema
|
||||
|
||||
Формат `agent-versions.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"lastUpdated": "2026-04-05T17:27:00Z",
|
||||
"agents": {
|
||||
"lead-developer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"fit_score": 92
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"date": "2026-04-05T05:21:00Z",
|
||||
"commit": "caf77f53c8",
|
||||
"type": "model_change",
|
||||
"from": null,
|
||||
"to": "ollama-cloud/qwen3-coder:480b",
|
||||
"reason": "Initial configuration"
|
||||
}
|
||||
],
|
||||
"performance_log": [
|
||||
{
|
||||
"date": "2026-04-05T10:30:00Z",
|
||||
"issue": 42,
|
||||
"score": 8,
|
||||
"duration_ms": 120000,
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Интеграция
|
||||
|
||||
### В Pipeline
|
||||
|
||||
Добавьте в `.kilo/commands/pipeline.md`:
|
||||
|
||||
```yaml
|
||||
post_steps:
|
||||
- name: sync_evolution
|
||||
run: bun run sync:evolution
|
||||
```
|
||||
|
||||
### В Gitea Webhooks
|
||||
|
||||
```typescript
|
||||
// Добавить webhook в Gitea
|
||||
{
|
||||
"url": "http://localhost:3000/api/evolution/webhook",
|
||||
"events": ["issue_comment", "issues"]
|
||||
}
|
||||
```
|
||||
|
||||
### Чтение из кода
|
||||
|
||||
```typescript
|
||||
import { agentEvolution } from './agent-evolution/scripts/sync-agent-history';
|
||||
|
||||
// Получить все агенты
|
||||
const agents = await agentEvolution.getAllAgents();
|
||||
|
||||
// Получить историю конкретного агента
|
||||
const history = await agentEvolution.getAgentHistory('lead-developer');
|
||||
|
||||
// Записать изменение модели
|
||||
await agentEvolution.recordChange({
|
||||
agent: 'security-auditor',
|
||||
type: 'model_change',
|
||||
from: 'gpt-oss:120b',
|
||||
to: 'nemotron-3-super',
|
||||
reason: 'Better reasoning for security analysis',
|
||||
source: 'manual'
|
||||
});
|
||||
```
|
||||
|
||||
## Рекомендации
|
||||
|
||||
### Приоритеты
|
||||
|
||||
| Priority | Criteria | Action |
|
||||
|----------|----------|--------|
|
||||
| Critical | Fit score < 70 | Немедленное обновление |
|
||||
| High | Модель недоступна | Переключение на fallback |
|
||||
| Medium | Доступна лучшая модель | Рассмотреть обновление |
|
||||
| Low | Возможна оптимизация | Опционально |
|
||||
|
||||
### Примеры рекомендаций
|
||||
|
||||
```json
|
||||
{
|
||||
"agent": "requirement-refiner",
|
||||
"recommendations": [{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "+22% quality, 1M context for specifications",
|
||||
"priority": "critical"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Мониторинг
|
||||
|
||||
### Метрики агента
|
||||
|
||||
- **Average Score**: Средний балл за последние 10 выполнений
|
||||
- **Success Rate**: Процент успешных выполнений
|
||||
- **Average Duration**: Среднее время выполнения
|
||||
- **Files per Task**: Среднее количество файлов на задачу
|
||||
|
||||
### Метрики системы
|
||||
|
||||
- **Total Agents**: Количество активных агентов
|
||||
- **Agents with History**: Агентов с историей изменений
|
||||
- **Pending Recommendations**: Количество рекомендаций
|
||||
- **Provider Distribution**: Распределение по провайдерам
|
||||
|
||||
## Обслуживание
|
||||
|
||||
### Очистка истории
|
||||
|
||||
```bash
|
||||
# Удалить дубликаты
|
||||
bun run agent-evolution/scripts/cleanup.ts --dedupe
|
||||
|
||||
# Слить связанные изменения
|
||||
bun run agent-evolution/scripts/cleanup.ts --merge
|
||||
```
|
||||
|
||||
### Экспорт данных
|
||||
|
||||
```bash
|
||||
# Экспортировать в CSV
|
||||
bun run agent-evolution/scripts/export.ts --format csv
|
||||
|
||||
# Экспортировать в Markdown
|
||||
bun run agent-evolution/scripts/export.ts --format md
|
||||
```
|
||||
|
||||
### Резервное копирование
|
||||
|
||||
```bash
|
||||
# Создать бэкап
|
||||
cp agent-evolution/data/agent-versions.json agent-evolution/data/backup/agent-versions-$(date +%Y%m%d).json
|
||||
|
||||
# Восстановить из бэкапа
|
||||
cp agent-evolution/data/backup/agent-versions-20260405.json agent-evolution/data/agent-versions.json
|
||||
```
|
||||
|
||||
## Будущие улучшения
|
||||
|
||||
1. **API Endpoints**:
|
||||
- `GET /api/evolution/agents` — список агентов
|
||||
- `GET /api/evolution/agents/:name/history` — история агента
|
||||
- `POST /api/evolution/sync` — запустить синхронизацию
|
||||
|
||||
2. **Real-time Updates**:
|
||||
- WebSocket для обновления дашборда
|
||||
- Автоматическое обновление при изменениях
|
||||
|
||||
3. **Analytics**:
|
||||
- Графики производительности во времени
|
||||
- Сравнение моделей
|
||||
- Прогнозирование производительности
|
||||
|
||||
4. **Integration**:
|
||||
- Slack/Telegram уведомления
|
||||
- Автоматическое применение рекомендаций
|
||||
- A/B testing моделей
|
||||
711
agent-evolution/data/agent-versions.json
Normal file
711
agent-evolution/data/agent-versions.json
Normal file
@@ -0,0 +1,711 @@
|
||||
{
|
||||
"$schema": "./agent-versions.schema.json",
|
||||
"version": "1.0.0",
|
||||
"lastUpdated": "2026-04-05T17:27:00Z",
|
||||
"agents": {
|
||||
"lead-developer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"mode": "subagent",
|
||||
"color": "#DC2626",
|
||||
"description": "Primary code writer for backend and core logic. Writes implementation to pass tests",
|
||||
"benchmark": {
|
||||
"swe_bench": 66.5,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 92
|
||||
},
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"performance_log": []
|
||||
},
|
||||
"frontend-developer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"mode": "subagent",
|
||||
"color": "#3B82F6",
|
||||
"description": "UI implementation specialist with multimodal capabilities",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 90
|
||||
},
|
||||
"capabilities": ["ui_implementation", "component_creation", "styling", "responsive_design"]
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"mode": "subagent",
|
||||
"color": "#10B981",
|
||||
"description": "Node.js, Express, APIs, database specialist",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 91
|
||||
},
|
||||
"capabilities": ["api_development", "database_design", "server_logic", "authentication"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"go-developer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"mode": "subagent",
|
||||
"color": "#00ADD8",
|
||||
"description": "Go backend services specialist",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 85
|
||||
},
|
||||
"capabilities": ["go_api_development", "go_database_design", "go_concurrent_programming", "go_authentication"]
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "QA",
|
||||
"mode": "subagent",
|
||||
"color": "#8B5CF6",
|
||||
"description": "Writes tests following TDD methodology. Tests MUST fail initially",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 88
|
||||
},
|
||||
"capabilities": ["unit_tests", "integration_tests", "e2e_tests", "test_planning", "visual_regression"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"code-skeptic": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/minimax-m2.5",
|
||||
"provider": "Ollama",
|
||||
"category": "QA",
|
||||
"mode": "subagent",
|
||||
"color": "#EF4444",
|
||||
"description": "Adversarial code reviewer. Finds problems and issues. Does NOT suggest implementations",
|
||||
"benchmark": {
|
||||
"swe_bench": 80.2,
|
||||
"ruler_1m": null,
|
||||
"terminal_bench": null,
|
||||
"fit_score": 85
|
||||
},
|
||||
"capabilities": ["code_review", "security_review", "style_check", "issue_identification"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"security-auditor": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Security",
|
||||
"mode": "subagent",
|
||||
"color": "#DC2626",
|
||||
"description": "Scans for security vulnerabilities, OWASP Top 10, dependency CVEs",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"ruler_1m": 91.75,
|
||||
"pinch_bench": 85.6,
|
||||
"fit_score": 80
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Performance",
|
||||
"mode": "subagent",
|
||||
"color": "#F59E0B",
|
||||
"description": "Reviews code for performance issues: N+1 queries, memory leaks, algorithmic complexity",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"ruler_1m": 91.75,
|
||||
"pinch_bench": 85.6,
|
||||
"fit_score": 82
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Testing",
|
||||
"mode": "subagent",
|
||||
"color": "#0EA5E9",
|
||||
"description": "Browser automation agent using Playwright MCP for E2E testing",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 87
|
||||
},
|
||||
"capabilities": ["e2e_browser_tests", "form_filling", "navigation_testing", "screenshot_capture"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"visual-tester": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Testing",
|
||||
"mode": "subagent",
|
||||
"color": "#EC4899",
|
||||
"description": "Visual regression testing agent that compares screenshots",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 82
|
||||
},
|
||||
"capabilities": ["visual_regression", "pixel_comparison", "screenshot_diff", "ui_validation"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"system-analyst": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/glm-5",
|
||||
"provider": "Ollama",
|
||||
"category": "Analysis",
|
||||
"mode": "subagent",
|
||||
"color": "#6366F1",
|
||||
"description": "Designs technical specifications, data schemas, and API contracts",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 82
|
||||
},
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"performance_log": []
|
||||
},
|
||||
"requirement-refiner": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/gpt-oss:120b",
|
||||
"provider": "Ollama",
|
||||
"category": "Analysis",
|
||||
"mode": "subagent",
|
||||
"color": "#8B5CF6",
|
||||
"description": "Converts vague ideas into strict User Stories with acceptance criteria",
|
||||
"benchmark": {
|
||||
"swe_bench": 62.4,
|
||||
"fit_score": 62
|
||||
},
|
||||
"capabilities": ["requirement_analysis", "user_story_creation", "acceptance_criteria", "clarification"],
|
||||
"recommendations": [
|
||||
{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "+22% quality, 1M context for specifications",
|
||||
"priority": "critical"
|
||||
}
|
||||
]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"history-miner": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/glm-5",
|
||||
"provider": "Ollama",
|
||||
"category": "Analysis",
|
||||
"mode": "subagent",
|
||||
"color": "#A855F7",
|
||||
"description": "Analyzes git history for duplicates and past solutions",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 78
|
||||
},
|
||||
"capabilities": ["git_search", "duplicate_detection", "past_solution_finder", "pattern_identification"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"capability-analyst": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/gpt-oss:120b",
|
||||
"provider": "Ollama",
|
||||
"category": "Analysis",
|
||||
"mode": "subagent",
|
||||
"color": "#14B8A6",
|
||||
"description": "Analyzes task coverage and identifies gaps",
|
||||
"benchmark": {
|
||||
"swe_bench": 62.4,
|
||||
"fit_score": 66
|
||||
},
|
||||
"capabilities": ["gap_analysis", "capability_mapping", "recommendation_generation", "coverage_analysis"],
|
||||
"recommendations": [
|
||||
{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "+21% quality for gap analysis and recommendations",
|
||||
"priority": "critical"
|
||||
}
|
||||
]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"orchestrator": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/glm-5",
|
||||
"provider": "Ollama",
|
||||
"category": "Process",
|
||||
"mode": "primary",
|
||||
"color": "#0EA5E9",
|
||||
"description": "Process manager. Distributes tasks between agents",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 80
|
||||
},
|
||||
"capabilities": ["task_routing", "state_management", "agent_coordination", "workflow_execution"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"release-manager": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/devstral-2:123b",
|
||||
"provider": "Ollama",
|
||||
"category": "Process",
|
||||
"mode": "subagent",
|
||||
"color": "#22C55E",
|
||||
"description": "Manages git operations, semantic versioning, deployments",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 75
|
||||
},
|
||||
"capabilities": ["git_operations", "version_management", "changelog_creation", "deployment"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"evaluator": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Process",
|
||||
"mode": "subagent",
|
||||
"color": "#F97316",
|
||||
"description": "Scores agent effectiveness after task completion",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"fit_score": 82
|
||||
},
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"performance_log": []
|
||||
},
|
||||
"prompt-optimizer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Process",
|
||||
"mode": "subagent",
|
||||
"color": "#EC4899",
|
||||
"description": "Improves agent system prompts based on performance failures",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"fit_score": 80
|
||||
},
|
||||
"capabilities": ["prompt_analysis", "prompt_improvement", "failure_pattern_detection"],
|
||||
"recommendations": [
|
||||
{
|
||||
"target": "openrouter/qwen3.6-plus:free",
|
||||
"reason": "Terminal-Bench 61.6% > Nemotron, always-on CoT",
|
||||
"priority": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"date": "2026-04-05T05:21:00Z",
|
||||
"commit": "caf77f53c8",
|
||||
"type": "model_change",
|
||||
"from": "openrouter/qwen3.6-plus:free",
|
||||
"to": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "Research recommendation applied",
|
||||
"source": "git"
|
||||
}
|
||||
],
|
||||
"performance_log": []
|
||||
},
|
||||
"the-fixer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/minimax-m2.5",
|
||||
"provider": "Ollama",
|
||||
"category": "Fixes",
|
||||
"mode": "subagent",
|
||||
"color": "#EF4444",
|
||||
"description": "Iteratively fixes bugs based on specific error reports",
|
||||
"benchmark": {
|
||||
"swe_bench": 80.2,
|
||||
"fit_score": 88
|
||||
},
|
||||
"capabilities": ["bug_fixing", "issue_resolution", "code_correction"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"product-owner": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/glm-5",
|
||||
"provider": "Ollama",
|
||||
"category": "Management",
|
||||
"mode": "subagent",
|
||||
"color": "#10B981",
|
||||
"description": "Manages issue checklists, status labels, progress tracking",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 76
|
||||
},
|
||||
"capabilities": ["issue_management", "prioritization", "backlog_management", "workflow_completion"]
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"date": "2026-04-05T05:21:00Z",
|
||||
"commit": "caf77f53c8",
|
||||
"type": "model_change",
|
||||
"from": "openrouter/qwen3.6-plus:free",
|
||||
"to": "ollama-cloud/glm-5",
|
||||
"reason": "GLM-5 good for management tasks",
|
||||
"source": "git"
|
||||
}
|
||||
],
|
||||
"performance_log": []
|
||||
},
|
||||
"workflow-architect": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/glm-5",
|
||||
"provider": "Ollama",
|
||||
"category": "Workflow",
|
||||
"mode": "subagent",
|
||||
"color": "#6366F1",
|
||||
"description": "Creates workflow definitions",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 74
|
||||
},
|
||||
"capabilities": ["workflow_design", "process_definition", "automation_setup"]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"markdown-validator": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/nemotron-3-nano:30b",
|
||||
"provider": "Ollama",
|
||||
"category": "Validation",
|
||||
"mode": "subagent",
|
||||
"color": "#84CC16",
|
||||
"description": "Validates Markdown formatting",
|
||||
"benchmark": {
|
||||
"swe_bench": null,
|
||||
"fit_score": 72
|
||||
},
|
||||
"capabilities": ["markdown_validation", "formatting_check", "link_validation"]
|
||||
},
|
||||
"history": [
|
||||
{
|
||||
"date": "2026-04-05T05:21:00Z",
|
||||
"commit": "caf77f53c8",
|
||||
"type": "model_change",
|
||||
"from": "openrouter/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": {
|
||||
"model": "ollama-cloud/gpt-oss:120b",
|
||||
"provider": "Ollama",
|
||||
"category": "Meta",
|
||||
"mode": "subagent",
|
||||
"color": "#A855F7",
|
||||
"description": "Creates new agents when gaps identified",
|
||||
"benchmark": {
|
||||
"swe_bench": 62.4,
|
||||
"fit_score": 69
|
||||
},
|
||||
"capabilities": ["agent_design", "prompt_engineering", "capability_definition"],
|
||||
"recommendations": [
|
||||
{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "+19% quality for agent design",
|
||||
"priority": "high"
|
||||
}
|
||||
]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"planner": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Cognitive",
|
||||
"mode": "subagent",
|
||||
"color": "#3B82F6",
|
||||
"description": "Task decomposition, CoT, ToT planning",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"fit_score": 84
|
||||
},
|
||||
"capabilities": ["task_decomposition", "chain_of_thought", "tree_of_thoughts", "plan_execute_reflect"]
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Cognitive",
|
||||
"mode": "subagent",
|
||||
"color": "#14B8A6",
|
||||
"description": "Self-reflection agent using Reflexion pattern",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"fit_score": 82
|
||||
},
|
||||
"capabilities": ["self_reflection", "mistake_analysis", "lesson_extraction"]
|
||||
},
|
||||
"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": {
|
||||
"model": "ollama-cloud/nemotron-3-super",
|
||||
"provider": "Ollama",
|
||||
"category": "Cognitive",
|
||||
"mode": "subagent",
|
||||
"color": "#F59E0B",
|
||||
"description": "Manages agent memory systems",
|
||||
"benchmark": {
|
||||
"swe_bench": 60.5,
|
||||
"ruler_1m": 91.75,
|
||||
"fit_score": 90
|
||||
},
|
||||
"capabilities": ["memory_retrieval", "memory_storage", "memory_consolidation", "relevance_scoring"]
|
||||
},
|
||||
"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": {
|
||||
"model": null,
|
||||
"provider": null,
|
||||
"category": "DevOps",
|
||||
"mode": "subagent",
|
||||
"color": "#2563EB",
|
||||
"description": "Docker, Kubernetes, CI/CD pipeline automation",
|
||||
"benchmark": {
|
||||
"fit_score": 0
|
||||
},
|
||||
"capabilities": ["docker", "kubernetes", "ci_cd", "infrastructure"],
|
||||
"status": "new",
|
||||
"recommendations": [
|
||||
{
|
||||
"target": "ollama-cloud/nemotron-3-super",
|
||||
"reason": "DevOps requires strong reasoning",
|
||||
"priority": "critical"
|
||||
}
|
||||
]
|
||||
},
|
||||
"history": [],
|
||||
"performance_log": []
|
||||
},
|
||||
"flutter-developer": {
|
||||
"current": {
|
||||
"model": "ollama-cloud/qwen3-coder:480b",
|
||||
"provider": "Ollama",
|
||||
"category": "Core Dev",
|
||||
"mode": "subagent",
|
||||
"color": "#0EA5E9",
|
||||
"description": "Flutter mobile specialist",
|
||||
"benchmark": {
|
||||
"fit_score": 86
|
||||
},
|
||||
"capabilities": ["flutter_development", "state_management", "ui_components", "cross_platform"]
|
||||
},
|
||||
"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": []
|
||||
}
|
||||
},
|
||||
"providers": {
|
||||
"Ollama": {
|
||||
"models": [
|
||||
{"id": "qwen3-coder:480b", "swe_bench": 66.5, "context": "256K", "active_params": "35B"},
|
||||
{"id": "minimax-m2.5", "swe_bench": 80.2, "context": "128K"},
|
||||
{"id": "nemotron-3-super", "swe_bench": 60.5, "ruler_1m": 91.75, "context": "1M"},
|
||||
{"id": "nemotron-3-nano:30b", "swe_bench": null, "context": "128K"},
|
||||
{"id": "glm-5", "swe_bench": null, "context": "128K"},
|
||||
{"id": "gpt-oss:120b", "swe_bench": 62.4, "context": "130K"},
|
||||
{"id": "gpt-oss:20b", "swe_bench": null, "context": "128K"},
|
||||
{"id": "devstral-2:123b", "swe_bench": null, "context": "128K"},
|
||||
{"id": "deepseek-v3.2", "swe_bench": null, "context": "128K"}
|
||||
]
|
||||
},
|
||||
"OpenRouter": {
|
||||
"models": [
|
||||
{"id": "qwen3.6-plus:free", "swe_bench": null, "terminal_bench": 61.6, "context": "1M", "free": true},
|
||||
{"id": "gemma4:31b", "intelligence_index": 39, "context": "256K", "free": true}
|
||||
]
|
||||
},
|
||||
"Groq": {
|
||||
"models": [
|
||||
{"id": "gpt-oss-120b", "speed_tps": 500, "rpd": 1000, "tpd": "200K"},
|
||||
{"id": "gpt-oss-20b", "speed_tps": 1200, "rpd": 1000},
|
||||
{"id": "kimi-k2-instruct", "speed_tps": 300, "rpm": 60},
|
||||
{"id": "qwen3-32b", "speed_tps": 400, "rpd": 1000, "tpd": "500K"},
|
||||
{"id": "llama-4-scout", "speed_tps": 350, "tpm": "30K"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"evolution_metrics": {
|
||||
"total_agents": 32,
|
||||
"agents_with_history": 12,
|
||||
"pending_recommendations": 6,
|
||||
"last_sync": "2026-04-05T17:27:00Z",
|
||||
"sync_sources": ["git", "capability-index.yaml", "kilo.jsonc"]
|
||||
}
|
||||
}
|
||||
183
agent-evolution/data/agent-versions.schema.json
Normal file
183
agent-evolution/data/agent-versions.schema.json
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Agent Versions Schema",
|
||||
"description": "Schema for tracking agent evolution in APAW",
|
||||
"type": "object",
|
||||
"required": ["version", "lastUpdated", "agents", "providers", "evolution_metrics"],
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
"description": "Reference to this schema"
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
||||
"description": "Schema version (semver)"
|
||||
},
|
||||
"lastUpdated": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 timestamp of last update"
|
||||
},
|
||||
"agents": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"required": ["current", "history", "performance_log"],
|
||||
"properties": {
|
||||
"current": {
|
||||
"type": "object",
|
||||
"required": ["model", "provider", "category", "mode", "description"],
|
||||
"properties": {
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Current model ID (e.g., ollama-cloud/qwen3-coder:480b)"
|
||||
},
|
||||
"provider": {
|
||||
"type": "string",
|
||||
"enum": ["Ollama", "OpenRouter", "Groq", "Unknown"],
|
||||
"description": "Model provider"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "Agent category (Core Dev, QA, Security, etc.)"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["primary", "subagent", "all"],
|
||||
"description": "Agent invocation mode"
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"pattern": "^#[0-9A-Fa-f]{6}$",
|
||||
"description": "UI color in hex format"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Agent purpose description"
|
||||
},
|
||||
"benchmark": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"swe_bench": { "type": "number", "minimum": 0, "maximum": 100 },
|
||||
"ruler_1m": { "type": "number", "minimum": 0, "maximum": 100 },
|
||||
"terminal_bench": { "type": "number", "minimum": 0, "maximum": 100 },
|
||||
"pinch_bench": { "type": "number", "minimum": 0, "maximum": 100 },
|
||||
"fit_score": { "type": "number", "minimum": 0, "maximum": 100 }
|
||||
}
|
||||
},
|
||||
"capabilities": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "List of agent capabilities"
|
||||
},
|
||||
"recommendations": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["target", "reason", "priority"],
|
||||
"properties": {
|
||||
"target": { "type": "string" },
|
||||
"reason": { "type": "string" },
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": ["critical", "high", "medium", "low"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["active", "new", "deprecated", "testing"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"history": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["date", "commit", "type", "to", "reason", "source"],
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"commit": { "type": "string" },
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["model_change", "prompt_change", "agent_created", "agent_removed", "capability_change"]
|
||||
},
|
||||
"from": { "type": ["string", "null"] },
|
||||
"to": { "type": "string" },
|
||||
"reason": { "type": "string" },
|
||||
"source": {
|
||||
"type": "string",
|
||||
"enum": ["git", "gitea", "manual"]
|
||||
},
|
||||
"issue_number": { "type": "integer" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"performance_log": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["date", "issue", "score", "success"],
|
||||
"properties": {
|
||||
"date": { "type": "string", "format": "date-time" },
|
||||
"issue": { "type": "integer" },
|
||||
"score": { "type": "number", "minimum": 0, "maximum": 10 },
|
||||
"duration_ms": { "type": "integer" },
|
||||
"success": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"providers": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"required": ["models"],
|
||||
"properties": {
|
||||
"models": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"swe_bench": { "type": "number" },
|
||||
"terminal_bench": { "type": "number" },
|
||||
"ruler_1m": { "type": "number" },
|
||||
"pinch_bench": { "type": "number" },
|
||||
"context": { "type": "string" },
|
||||
"active_params": { "type": "string" },
|
||||
"speed_tps": { "type": "number" },
|
||||
"rpm": { "type": "number" },
|
||||
"rpd": { "type": "number" },
|
||||
"tpm": { "type": "string" },
|
||||
"tpd": { "type": "string" },
|
||||
"free": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"evolution_metrics": {
|
||||
"type": "object",
|
||||
"required": ["total_agents", "agents_with_history", "pending_recommendations", "last_sync", "sync_sources"],
|
||||
"properties": {
|
||||
"total_agents": { "type": "integer", "minimum": 0 },
|
||||
"agents_with_history": { "type": "integer", "minimum": 0 },
|
||||
"pending_recommendations": { "type": "integer", "minimum": 0 },
|
||||
"last_sync": { "type": "string", "format": "date-time" },
|
||||
"sync_sources": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
197
agent-evolution/docker-run.bat
Normal file
197
agent-evolution/docker-run.bat
Normal file
@@ -0,0 +1,197 @@
|
||||
@echo off
|
||||
REM Agent Evolution Dashboard - Docker Management Script (Windows)
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set IMAGE_NAME=apaw-evolution
|
||||
set CONTAINER_NAME=apaw-evolution-dashboard
|
||||
set PORT=3001
|
||||
set DATA_DIR=.\agent-evolution\data
|
||||
|
||||
REM Colors (limited in Windows CMD)
|
||||
set RED=[91m
|
||||
set GREEN=[92m
|
||||
set YELLOW=[93m
|
||||
set NC=[0m
|
||||
|
||||
REM Main logic
|
||||
if "%1"=="" goto help
|
||||
if "%1"=="build" goto build
|
||||
if "%1"=="run" goto run
|
||||
if "%1"=="stop" goto stop
|
||||
if "%1"=="restart" goto restart
|
||||
if "%1"=="logs" goto logs
|
||||
if "%1"=="open" goto open
|
||||
if "%1"=="sync" goto sync
|
||||
if "%1"=="status" goto status
|
||||
if "%1"=="clean" goto clean
|
||||
if "%1"=="dev" goto dev
|
||||
if "%1"=="help" goto help
|
||||
goto unknown
|
||||
|
||||
:log_info
|
||||
echo %GREEN%[INFO]%NC% %*
|
||||
goto :eof
|
||||
|
||||
:log_warn
|
||||
echo %YELLOW%[WARN]%NC% %*
|
||||
goto :eof
|
||||
|
||||
:log_error
|
||||
echo %RED%[ERROR]%NC% %*
|
||||
goto :eof
|
||||
|
||||
:build
|
||||
call :log_info Building Docker image...
|
||||
docker build -t %IMAGE_NAME%:latest -f agent-evolution/Dockerfile --target production .
|
||||
if errorlevel 1 (
|
||||
call :log_error Build failed
|
||||
exit /b 1
|
||||
)
|
||||
call :log_info Build complete: %IMAGE_NAME%:latest
|
||||
goto :eof
|
||||
|
||||
:run
|
||||
REM Check if already running
|
||||
docker ps -q --filter "name=%CONTAINER_NAME%" 2>nul | findstr /r . >nul
|
||||
if not errorlevel 1 (
|
||||
call :log_warn Container %CONTAINER_NAME% is already running
|
||||
call :log_info Use 'docker-run.bat restart' to restart it
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
REM Remove stopped container
|
||||
docker ps -aq --filter "name=%CONTAINER_NAME%" 2>nul | findstr /r . >nul
|
||||
if not errorlevel 1 (
|
||||
call :log_info Removing stopped container...
|
||||
docker rm %CONTAINER_NAME% >nul 2>nul
|
||||
)
|
||||
|
||||
call :log_info Starting container...
|
||||
docker run -d ^
|
||||
--name %CONTAINER_NAME% ^
|
||||
-p %PORT%:3001 ^
|
||||
-v %cd%/%DATA_DIR%:/app/data:ro ^
|
||||
-v %cd%/.kilo/agents:/app/kilo/agents:ro ^
|
||||
-v %cd%/.kilo/capability-index.yaml:/app/kilo/capability-index.yaml:ro ^
|
||||
-v %cd%/.kilo/kilo.jsonc:/app/kilo/kilo.jsonc:ro ^
|
||||
--restart unless-stopped ^
|
||||
%IMAGE_NAME%:latest
|
||||
|
||||
if errorlevel 1 (
|
||||
call :log_error Failed to start container
|
||||
exit /b 1
|
||||
)
|
||||
call :log_info Container started: %CONTAINER_NAME%
|
||||
call :log_info Dashboard available at: http://localhost:%PORT%
|
||||
goto :eof
|
||||
|
||||
:stop
|
||||
call :log_info Stopping container...
|
||||
docker stop %CONTAINER_NAME% >nul 2>nul
|
||||
docker rm %CONTAINER_NAME% >nul 2>nul
|
||||
call :log_info Container stopped
|
||||
goto :eof
|
||||
|
||||
:restart
|
||||
call :stop
|
||||
call :build
|
||||
call :run
|
||||
goto :eof
|
||||
|
||||
:logs
|
||||
docker logs -f %CONTAINER_NAME%
|
||||
goto :eof
|
||||
|
||||
:open
|
||||
set URL=http://localhost:%PORT%
|
||||
call :log_info Opening dashboard: %URL%
|
||||
start %URL%
|
||||
goto :eof
|
||||
|
||||
:sync
|
||||
call :log_info Syncing evolution data...
|
||||
where bun >nul 2>nul
|
||||
if not errorlevel 1 (
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts
|
||||
) else (
|
||||
where npx >nul 2>nul
|
||||
if not errorlevel 1 (
|
||||
npx tsx agent-evolution/scripts/sync-agent-history.ts
|
||||
) else (
|
||||
call :log_error Node.js or Bun required for sync
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
call :log_info Sync complete
|
||||
goto :eof
|
||||
|
||||
:status
|
||||
docker ps -q --filter "name=%CONTAINER_NAME%" 2>nul | findstr /r . >nul
|
||||
if not errorlevel 1 (
|
||||
call :log_info Container status: %GREEN%RUNNING%NC%
|
||||
call :log_info URL: http://localhost:%PORT%
|
||||
|
||||
REM Health check
|
||||
for /f "tokens=*" %%i in ('docker inspect --format="{{.State.Health.Status}}" %CONTAINER_NAME% 2^>nul') do set HEALTH=%%i
|
||||
call :log_info Health: !HEALTH!
|
||||
|
||||
REM Started time
|
||||
for /f "tokens=*" %%i in ('docker inspect --format="{{.State.StartedAt}}" %CONTAINER_NAME% 2^>nul') do set STARTED=%%i
|
||||
if defined STARTED call :log_info Started: !STARTED!
|
||||
) else (
|
||||
docker ps -aq --filter "name=%CONTAINER_NAME%" 2>nul | findstr /r . >nul
|
||||
if not errorlevel 1 (
|
||||
call :log_info Container status: %YELLOW%STOPPED%NC%
|
||||
) else (
|
||||
call :log_info Container status: %RED%NOT CREATED%NC%
|
||||
)
|
||||
)
|
||||
goto :eof
|
||||
|
||||
:clean
|
||||
call :log_info Cleaning up...
|
||||
call :stop >nul 2>nul
|
||||
docker rmi %IMAGE_NAME%:latest >nul 2>nul
|
||||
call :log_info Cleanup complete
|
||||
goto :eof
|
||||
|
||||
:dev
|
||||
call :log_info Starting development mode...
|
||||
docker build -t %IMAGE_NAME%:dev -f agent-evolution/Dockerfile --target development .
|
||||
if errorlevel 1 (
|
||||
call :log_error Build failed
|
||||
exit /b 1
|
||||
)
|
||||
docker run --rm ^
|
||||
--name %CONTAINER_NAME%-dev ^
|
||||
-p %PORT%:3001 ^
|
||||
-v %cd%/%DATA_DIR%:/app/data ^
|
||||
-v %cd%/agent-evolution/index.html:/app/index.html ^
|
||||
%IMAGE_NAME%:dev
|
||||
goto :eof
|
||||
|
||||
:help
|
||||
echo Agent Evolution Dashboard - Docker Management (Windows)
|
||||
echo.
|
||||
echo Usage: %~nx0 ^<command^>
|
||||
echo.
|
||||
echo Commands:
|
||||
echo build Build Docker image
|
||||
echo run Run container
|
||||
echo stop Stop container
|
||||
echo restart Restart container (build + run)
|
||||
echo logs View container logs
|
||||
echo open Open dashboard in browser
|
||||
echo sync Sync evolution data
|
||||
echo status Show container status
|
||||
echo clean Remove container and image
|
||||
echo dev Run in development mode (with hot reload)
|
||||
echo help Show this help message
|
||||
goto :eof
|
||||
|
||||
:unknown
|
||||
call :log_error Unknown command: %1
|
||||
goto help
|
||||
|
||||
endlocal
|
||||
203
agent-evolution/docker-run.sh
Normal file
203
agent-evolution/docker-run.sh
Normal file
@@ -0,0 +1,203 @@
|
||||
#!/bin/bash
|
||||
# Agent Evolution Dashboard - Docker Management Script
|
||||
|
||||
set -e
|
||||
|
||||
IMAGE_NAME="apaw-evolution"
|
||||
CONTAINER_NAME="apaw-evolution-dashboard"
|
||||
PORT=3001
|
||||
DATA_DIR="./agent-evolution/data"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Build Docker image
|
||||
build() {
|
||||
log_info "Building Docker image..."
|
||||
docker build \
|
||||
-t "$IMAGE_NAME:latest" \
|
||||
-f agent-evolution/Dockerfile \
|
||||
--target production \
|
||||
.
|
||||
log_info "Build complete: $IMAGE_NAME:latest"
|
||||
}
|
||||
|
||||
# Run container
|
||||
run() {
|
||||
# Check if container already running
|
||||
if docker ps -q --filter "name=$CONTAINER_NAME" | grep -q .; then
|
||||
log_warn "Container $CONTAINER_NAME is already running"
|
||||
log_info "Use '$0 restart' to restart it"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove stopped container if exists
|
||||
if docker ps -aq --filter "name=$CONTAINER_NAME" | grep -q .; then
|
||||
log_info "Removing stopped container..."
|
||||
docker rm "$CONTAINER_NAME" >/dev/null || true
|
||||
fi
|
||||
|
||||
log_info "Starting container..."
|
||||
docker run -d \
|
||||
--name "$CONTAINER_NAME" \
|
||||
-p "$PORT:3001" \
|
||||
-v "$(pwd)/$DATA_DIR:/app/data:ro" \
|
||||
-v "$(pwd)/.kilo/agents:/app/kilo/agents:ro" \
|
||||
-v "$(pwd)/.kilo/capability-index.yaml:/app/kilo/capability-index.yaml:ro" \
|
||||
-v "$(pwd)/.kilo/kilo.jsonc:/app/kilo/kilo.jsonc:ro" \
|
||||
--restart unless-stopped \
|
||||
--health-cmd "wget --no-verbose --tries=1 --spider http://localhost:3001/ || exit 1" \
|
||||
--health-interval "30s" \
|
||||
--health-timeout "10s" \
|
||||
--health-retries "3" \
|
||||
"$IMAGE_NAME:latest"
|
||||
|
||||
log_info "Container started: $CONTAINER_NAME"
|
||||
log_info "Dashboard available at: http://localhost:$PORT"
|
||||
}
|
||||
|
||||
# Stop container
|
||||
stop() {
|
||||
log_info "Stopping container..."
|
||||
docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||
docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
|
||||
log_info "Container stopped"
|
||||
}
|
||||
|
||||
# Restart container
|
||||
restart() {
|
||||
stop
|
||||
build
|
||||
run
|
||||
}
|
||||
|
||||
# View logs
|
||||
logs() {
|
||||
docker logs -f "$CONTAINER_NAME"
|
||||
}
|
||||
|
||||
# Open dashboard in browser
|
||||
open() {
|
||||
URL="http://localhost:$PORT"
|
||||
log_info "Opening dashboard: $URL"
|
||||
|
||||
if command -v xdg-open &> /dev/null; then
|
||||
xdg-open "$URL"
|
||||
elif command -v open &> /dev/null; then
|
||||
open "$URL"
|
||||
elif command -v start &> /dev/null; then
|
||||
start "$URL"
|
||||
else
|
||||
log_warn "Could not open browser. Navigate to: $URL"
|
||||
fi
|
||||
}
|
||||
|
||||
# Sync evolution data
|
||||
sync() {
|
||||
log_info "Syncing evolution data..."
|
||||
if command -v bun &> /dev/null; then
|
||||
bun run agent-evolution/scripts/sync-agent-history.ts
|
||||
elif command -v node &> /dev/null; then
|
||||
npx tsx agent-evolution/scripts/sync-agent-history.ts
|
||||
else
|
||||
log_error "Node.js or Bun required for sync"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Sync complete"
|
||||
}
|
||||
|
||||
# Status check
|
||||
status() {
|
||||
if docker ps -q --filter "name=$CONTAINER_NAME" | grep -q .; then
|
||||
log_info "Container status: ${GREEN}RUNNING${NC}"
|
||||
log_info "URL: http://localhost:$PORT"
|
||||
|
||||
# Health check
|
||||
HEALTH=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "unknown")
|
||||
log_info "Health: $HEALTH"
|
||||
|
||||
# Uptime
|
||||
STARTED=$(docker inspect --format='{{.State.StartedAt}}' "$CONTAINER_NAME" 2>/dev/null)
|
||||
if [ -n "$STARTED" ] && [ "$STARTED" != "" ]; then
|
||||
log_info "Started: $STARTED"
|
||||
fi
|
||||
else
|
||||
if docker ps -aq --filter "name=$CONTAINER_NAME" | grep -q .; then
|
||||
log_info "Container status: ${YELLOW}STOPPED${NC}"
|
||||
else
|
||||
log_info "Container status: ${RED}NOT CREATED${NC}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Clean up
|
||||
clean() {
|
||||
log_info "Cleaning up..."
|
||||
stop
|
||||
docker rmi "$IMAGE_NAME:latest" >/dev/null 2>&1 || true
|
||||
log_info "Cleanup complete"
|
||||
}
|
||||
|
||||
# Development mode with hot reload
|
||||
dev() {
|
||||
log_info "Starting development mode..."
|
||||
docker build \
|
||||
-t "$IMAGE_NAME:dev" \
|
||||
-f agent-evolution/Dockerfile \
|
||||
--target development \
|
||||
.
|
||||
|
||||
docker run --rm \
|
||||
--name "${CONTAINER_NAME}-dev" \
|
||||
-p "$PORT:3001" \
|
||||
-v "$(pwd)/$DATA_DIR:/app/data" \
|
||||
-v "$(pwd)/agent-evolution/index.html:/app/index.html" \
|
||||
"$IMAGE_NAME:dev"
|
||||
}
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
echo "Agent Evolution Dashboard - Docker Management"
|
||||
echo ""
|
||||
echo "Usage: $0 <command>"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " build Build Docker image"
|
||||
echo " run Run container"
|
||||
echo " stop Stop container"
|
||||
echo " restart Restart container (build + run)"
|
||||
echo " logs View container logs"
|
||||
echo " open Open dashboard in browser"
|
||||
echo " sync Sync evolution data"
|
||||
echo " status Show container status"
|
||||
echo " clean Remove container and image"
|
||||
echo " dev Run in development mode (with hot reload)"
|
||||
echo " help Show this help message"
|
||||
}
|
||||
|
||||
# Main
|
||||
case "${1:-help}" in
|
||||
build) build ;;
|
||||
run) run ;;
|
||||
stop) stop ;;
|
||||
restart) restart ;;
|
||||
logs) logs ;;
|
||||
open) open ;;
|
||||
sync) sync ;;
|
||||
status) status ;;
|
||||
clean) clean ;;
|
||||
dev) dev ;;
|
||||
help) show_help ;;
|
||||
*)
|
||||
log_error "Unknown command: $1"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
1062
agent-evolution/index.html
Normal file
1062
agent-evolution/index.html
Normal file
File diff suppressed because it is too large
Load Diff
654
agent-evolution/index.standalone.html
Normal file
654
agent-evolution/index.standalone.html
Normal file
@@ -0,0 +1,654 @@
|
||||
<!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: #080b12;
|
||||
--bg-panel: #0e1219;
|
||||
--bg-card: #141922;
|
||||
--bg-card-hover: #1a2130;
|
||||
--border: #1e2736;
|
||||
--border-bright: #2a3650;
|
||||
--text-primary: #e8edf5;
|
||||
--text-secondary: #8896aa;
|
||||
--text-muted: #5a6880;
|
||||
--accent-cyan: #00d4ff;
|
||||
--accent-green: #00ff94;
|
||||
--accent-orange: #ff9f43;
|
||||
--accent-red: #ff4757;
|
||||
--accent-purple: #a855f7;
|
||||
--glow-cyan: rgba(0,212,255,0.15);
|
||||
--glow-green: rgba(0,255,148,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;
|
||||
overflow-x:hidden;
|
||||
}
|
||||
body::before {
|
||||
content:'';
|
||||
position:fixed; inset:0;
|
||||
background:linear-gradient(90deg,rgba(0,212,255,0.02) 1px,transparent 1px),
|
||||
linear-gradient(rgba(0,212,255,0.02) 1px,transparent 1px);
|
||||
background-size:60px 60px;
|
||||
pointer-events:none; z-index:0;
|
||||
}
|
||||
.container { max-width:1540px; margin:0 auto; padding:24px 16px; position:relative; z-index:1; }
|
||||
|
||||
.header { text-align:center; margin-bottom:32px; }
|
||||
.header h1 {
|
||||
font-size:2.4em; font-weight:900;
|
||||
background:linear-gradient(135deg,var(--accent-cyan),var(--accent-green));
|
||||
-webkit-background-clip:text; -webkit-text-fill-color:transparent;
|
||||
}
|
||||
.header .sub { font-family:'JetBrains Mono',monospace; color:var(--text-muted); font-size:.8em; margin-top:6px; }
|
||||
|
||||
.tabs { display:flex; gap:3px; 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 12px; background:none; border:none; color:var(--text-secondary);
|
||||
font-family:'Inter',sans-serif; font-size:.85em; font-weight:600; border-radius:9px; cursor:pointer; transition:all .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)); }
|
||||
.tab-panel { display:none; }
|
||||
.tab-panel.active { display:block; }
|
||||
|
||||
.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;
|
||||
transition:all .3s;
|
||||
}
|
||||
.stat-card:hover { border-color:var(--accent-cyan); transform:translateY(-2px); }
|
||||
.stat-label { font-family:'JetBrains Mono',monospace; font-size:.65em; color:var(--text-muted); text-transform:uppercase; letter-spacing:1px; }
|
||||
.stat-value { font-size:2em; font-weight:800; margin:4px 0; }
|
||||
.stat-sub { font-size:.75em; color:var(--text-secondary); }
|
||||
.grad-cyan { background:linear-gradient(135deg,var(--accent-cyan),var(--accent-green)); -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-orange { background:linear-gradient(135deg,var(--accent-orange),#facc15); -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; }
|
||||
|
||||
.sec-hdr { display:flex; align-items:center; gap:10px; margin-bottom:16px; padding-bottom:8px; border-bottom:1px solid var(--border); }
|
||||
.sec-hdr h2 { font-size:1.1em; font-weight:700; }
|
||||
.badge { font-family:'JetBrains Mono',monospace; font-size:.65em; padding:3px 9px; border-radius:16px; }
|
||||
.badge-cyan { background:var(--glow-cyan); color:var(--accent-cyan); border:1px solid rgba(0,212,255,.2); }
|
||||
.badge-green { background:var(--glow-green); color:var(--accent-green); border:1px solid rgba(0,255,148,.2); }
|
||||
.badge-orange { background:rgba(255,159,67,.1); color:var(--accent-orange); border:1px solid rgba(255,159,67,.2); }
|
||||
|
||||
.tbl-wrap { overflow-x:auto; border-radius:10px; border:1px solid var(--border); background:var(--bg-card); margin-bottom:24px; }
|
||||
table.dt { width:100%; border-collapse:collapse; font-size:.84em; }
|
||||
table.dt th { font-family:'JetBrains Mono',monospace; font-size:.7em; color:var(--text-muted); text-transform:uppercase; padding:12px 14px; background:var(--bg-panel); border-bottom:2px solid var(--border); text-align:left; }
|
||||
table.dt td { padding:10px 14px; border-bottom:1px solid var(--border); }
|
||||
table.dt tr:hover td { background:var(--bg-card-hover); }
|
||||
table.dt tr { cursor:pointer; transition:background .15s; }
|
||||
|
||||
.mbadge { display:inline-block; padding:3px 8px; border-radius:5px; font-family:'JetBrains Mono',monospace; font-size:.78em; font-weight:500; cursor:pointer; transition:all .2s; }
|
||||
.mbadge:hover { transform:scale(1.05); }
|
||||
.mbadge.qwen { background:rgba(59,130,246,.12); color:#60a5fa; border:1px solid rgba(59,130,246,.25); }
|
||||
.mbadge.minimax { background:rgba(255,159,67,.12); color:#ff9f43; border:1px solid rgba(255,159,67,.25); }
|
||||
.mbadge.nemotron { background:rgba(34,197,94,.12); color:#4ade80; border:1px solid rgba(34,197,94,.25); }
|
||||
.mbadge.glm { background:rgba(0,255,148,.08); color:#00ff94; border:1px solid rgba(0,255,148,.2); }
|
||||
.mbadge.gptoss { background:rgba(168,85,247,.12); color:#c084fc; border:1px solid rgba(168,85,247,.25); }
|
||||
.mbadge.devstral { background:rgba(0,212,255,.12); color:#00d4ff; border:1px solid rgba(0,212,255,.25); }
|
||||
|
||||
.prov-tag { display:inline-block; padding:1px 6px; border-radius:3px; font-size:.62em; font-family:'JetBrains Mono',monospace; }
|
||||
.prov-tag.ollama { background:rgba(0,212,255,.1); color:var(--accent-cyan); }
|
||||
.prov-tag.groq { background:rgba(255,71,87,.1); color:#ff6b81; }
|
||||
.prov-tag.openrouter { background:rgba(168,85,247,.1); color:#c084fc; }
|
||||
|
||||
.sbar { display:flex; align-items:center; gap:6px; }
|
||||
.sbar-bg { width:60px; height:5px; background:var(--border); border-radius:3px; overflow:hidden; }
|
||||
.sbar-fill { height:100%; border-radius:3px; }
|
||||
.sbar-fill.h { background:linear-gradient(90deg,var(--accent-green),#00ff94); }
|
||||
.sbar-fill.m { background:linear-gradient(90deg,var(--accent-orange),#ffc048); }
|
||||
.sbar-fill.l { background:linear-gradient(90deg,var(--accent-red),#ff6b81); }
|
||||
.snum { font-family:'JetBrains Mono',monospace; font-weight:600; font-size:.85em; min-width:28px; }
|
||||
|
||||
.rec-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(380px,1fr)); gap:14px; margin-bottom:24px; }
|
||||
.rec-card {
|
||||
background:var(--bg-card); border:1px solid var(--border); border-radius:10px; padding:16px;
|
||||
transition:all .3s; border-left:3px solid var(--border);
|
||||
}
|
||||
.rec-card:hover { border-color:var(--accent-green); transform:translateY(-2px); }
|
||||
.rec-card.critical { border-left-color:var(--accent-red); }
|
||||
.rec-card.high { border-left-color:var(--accent-orange); }
|
||||
.rec-card.medium { border-left-color:var(--accent-orange); }
|
||||
.rec-card.optimal { border-left-color:var(--accent-green); }
|
||||
.rec-hdr { display:flex; justify-content:space-between; align-items:center; margin-bottom:10px; }
|
||||
.rec-agent { font-weight:700; font-size:1em; color:var(--accent-cyan); }
|
||||
.imp-badge { padding:2px 8px; border-radius:16px; font-family:'JetBrains Mono',monospace; font-size:.68em; font-weight:600; }
|
||||
.imp-badge.critical { background:rgba(255,71,87,.18); color:var(--accent-red); }
|
||||
.imp-badge.high { background:rgba(255,159,67,.18); color:var(--accent-orange); }
|
||||
.imp-badge.medium { background:rgba(250,204,21,.18); color:var(--accent-yellow); }
|
||||
.imp-badge.optimal { background:rgba(0,255,148,.18); color:var(--accent-green); }
|
||||
.swap-vis { display:flex; align-items:center; gap:8px; margin:10px 0; padding:10px; background:var(--bg-panel); border-radius:6px; }
|
||||
.swap-from { font-family:'JetBrains Mono',monospace; font-size:.75em; padding:3px 8px; border-radius:4px; background:rgba(255,71,87,.08); color:#ff6b81; border:1px solid rgba(255,71,87,.15); text-decoration:line-through; opacity:.65; }
|
||||
.swap-to { font-family:'JetBrains Mono',monospace; font-size:.75em; padding:3px 8px; border-radius:4px; background:rgba(0,255,148,.08); color:#00ff94; border:1px solid rgba(0,255,148,.2); font-weight:600; }
|
||||
.swap-arrow { color:var(--accent-green); font-size:1.2em; }
|
||||
.rec-reason { font-size:.82em; color:var(--text-secondary); line-height:1.5; margin-top:10px; padding-top:10px; border-top:1px solid var(--border); }
|
||||
|
||||
.hm-wrap { overflow-x:auto; border-radius:10px; border:1px solid var(--border); background:var(--bg-card); padding:16px; margin-bottom:24px; }
|
||||
.hm-title { font-weight:700; font-size:1.05em; margin-bottom:6px; }
|
||||
.hm-sub { font-size:.76em; color:var(--text-muted); margin-bottom:12px; }
|
||||
.hm-table { border-collapse:collapse; width:100%; }
|
||||
.hm-table th { font-family:'JetBrains Mono',monospace; font-size:.62em; color:var(--text-muted); padding:8px 6px; text-align:center; white-space:nowrap; }
|
||||
.hm-table th.hm-role { text-align:left; min-width:140px; font-size:.68em; }
|
||||
.hm-table td { text-align:center; padding:6px 4px; font-family:'JetBrains Mono',monospace; font-size:.74em; font-weight:600; border-radius:3px; cursor:pointer; transition:all .12s; min-width:36px; }
|
||||
.hm-table td:hover { transform:scale(1.1); z-index:2; }
|
||||
.hm-table td.hm-r { text-align:left; font-family:'Inter',sans-serif; font-size:.78em; font-weight:500; color:var(--text-secondary); cursor:default; }
|
||||
.hm-table td.hm-r:hover { transform:none; }
|
||||
.hm-cur { outline:2px solid var(--accent-cyan); outline-offset:-2px; }
|
||||
|
||||
.modal { display:none; position:fixed; inset:0; background:rgba(0,0,0,.85); 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:800px; width:100%; max-height:85vh; overflow-y:auto; }
|
||||
.modal-header { display:flex; justify-content:space-between; align-items:center; padding:20px; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--bg-panel); z-index:1; }
|
||||
.modal-title { font-weight:700; font-size:1.2em; display:flex; align-items:center; gap:10px; }
|
||||
.modal-close { background:none; border:none; color:var(--text-muted); font-size:1.5em; cursor:pointer; }
|
||||
.modal-close:hover { color:var(--accent-red); }
|
||||
.modal-body { padding:20px; }
|
||||
.model-info { display:grid; grid-template-columns:repeat(2,1fr); gap:12px; margin-bottom:16px; }
|
||||
.model-info-item { background:var(--bg-card); padding:12px; border-radius:6px; }
|
||||
.model-info-label { font-size:.7em; color:var(--text-muted); text-transform:uppercase; }
|
||||
.model-info-value { font-size:1.1em; font-weight:600; margin-top:2px; }
|
||||
.model-tags { display:flex; flex-wrap:wrap; gap:6px; margin-top:12px; }
|
||||
.model-tag { padding:4px 10px; background:rgba(0,212,255,.1); border:1px solid rgba(0,212,255,.2); border-radius:16px; font-size:.75em; color:var(--accent-cyan); }
|
||||
|
||||
.gitea-timeline { position:relative; padding-left:24px; }
|
||||
.gitea-timeline::before { content:''; position:absolute; left:8px; top:0; bottom:0; width:2px; background:var(--border); }
|
||||
.gitea-item { position:relative; padding:12px 0 12px 24px; border-bottom:1px solid var(--border); }
|
||||
.gitea-item:last-child { border-bottom:none; }
|
||||
.gitea-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); }
|
||||
.gitea-date { font-family:'JetBrains Mono',monospace; font-size:.75em; color:var(--text-muted); }
|
||||
.gitea-content { font-size:.9em; margin-top:4px; }
|
||||
.gitea-agent { font-weight:600; color:var(--accent-cyan); }
|
||||
.gitea-change { color:var(--text-secondary); }
|
||||
|
||||
.frow { display:flex; gap:6px; margin-bottom:16px; flex-wrap:wrap; }
|
||||
.fbtn { padding:6px 14px; background:var(--bg-card); border:1px solid var(--border); color:var(--text-secondary); border-radius:20px; font-size:.8em; cursor:pointer; transition:all .2s; }
|
||||
.fbtn:hover,.fbtn.active { border-color:var(--accent-cyan); color:var(--accent-cyan); background:rgba(0,212,255,.06); }
|
||||
|
||||
.models-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:12px; }
|
||||
.mc { background:var(--bg-card); border:1px solid var(--border); border-radius:10px; padding:16px; cursor:pointer; transition:all .25s; }
|
||||
.mc:hover { border-color:var(--accent-cyan); transform:translateY(-2px); box-shadow:0 6px 20px var(--glow-cyan); }
|
||||
|
||||
@media(max-width:768px) {
|
||||
.header h1 { font-size:1.5em; }
|
||||
.tabs { flex-wrap:wrap; }
|
||||
.rec-grid { grid-template-columns:1fr; }
|
||||
.stats-row { grid-template-columns:repeat(2,1fr); }
|
||||
.model-info { grid-template-columns:1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>.Agent Evolution</h1>
|
||||
<div class="sub">Эволюция агентной системы APAW • Модели и рекомендации</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" onclick="switchTab('overview')">Обзор</button>
|
||||
<button class="tab-btn" onclick="switchTab('matrix')">Матрица</button>
|
||||
<button class="tab-btn" onclick="switchTab('recs')">Рекомендации</button>
|
||||
<button class="tab-btn" onclick="switchTab('history')">История</button>
|
||||
<button class="tab-btn" onclick="switchTab('models')">Модели</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-overview" class="tab-panel active">
|
||||
<div class="stats-row" id="statsRow"></div>
|
||||
|
||||
<div class="sec-hdr">
|
||||
<h2>Конфигурация агентов</h2>
|
||||
<span class="badge badge-cyan" id="agentsCount">0 агентов</span>
|
||||
</div>
|
||||
<div class="tbl-wrap">
|
||||
<table class="dt">
|
||||
<thead><tr>
|
||||
<th>Агент</th>
|
||||
<th>Модель</th>
|
||||
<th>Провайдер</th>
|
||||
<th>Fit</th>
|
||||
<th>Статус</th>
|
||||
</tr></thead>
|
||||
<tbody id="agentsTable"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-matrix" class="tab-panel">
|
||||
<div class="hm-wrap">
|
||||
<div class="hm-title">Матрица «Агент × Модель»</div>
|
||||
<div class="hm-sub">Кликните на ячейку для подробностей • ★ = текущая модель</div>
|
||||
<table class="hm-table" id="heatmapTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-recs" class="tab-panel">
|
||||
<div class="sec-hdr">
|
||||
<h2>Рекомендации по оптимизации</h2>
|
||||
<span class="badge badge-orange" id="recsCount">0 рекомен-й</span>
|
||||
</div>
|
||||
<div class="frow">
|
||||
<button class="fbtn active" onclick="filterRecs('all',this)">Все</button>
|
||||
<button class="fbtn" onclick="filterRecs('critical',this)">Критичные</button>
|
||||
<button class="fbtn" onclick="filterRecs('high',this)">Высокие</button>
|
||||
<button class="fbtn" onclick="filterRecs('medium',this)">Средние</button>
|
||||
<button class="fbtn" onclick="filterRecs('optimal',this)">Оптимальные</button>
|
||||
</div>
|
||||
<div class="rec-grid" id="recsGrid"></div>
|
||||
</div>
|
||||
|
||||
<div id="tab-history" class="tab-panel">
|
||||
<div class="sec-hdr">
|
||||
<h2>История изменений</h2>
|
||||
<span class="badge badge-green" id="historyCount">0 изменений</span>
|
||||
</div>
|
||||
<div class="gitea-timeline" id="historyTimeline"></div>
|
||||
</div>
|
||||
|
||||
<div id="tab-models" class="tab-panel">
|
||||
<div class="sec-hdr">
|
||||
<h2>Доступные модели</h2>
|
||||
<span class="badge badge-cyan">Ollama + Groq + OpenRouter</span>
|
||||
</div>
|
||||
<div class="models-grid" id="modelsGrid"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal" id="modelModal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">
|
||||
<span id="modalTitle">Модель</span>
|
||||
<span class="prov-tag" id="modalProvider">Ollama</span>
|
||||
</div>
|
||||
<button class="modal-close" onclick="closeModal()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="model-info" id="modalInfo"></div>
|
||||
<div class="model-tags" id="modalTags"></div>
|
||||
<div style="margin-top:16px">
|
||||
<h3 style="font-size:.95em;margin-bottom:10px">Агенты на этой модели</h3>
|
||||
<div id="modalAgents" style="display:flex;flex-wrap:wrap;gap:8px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ======================= EMBEDDED DATA =======================
|
||||
const EMBEDDED_DATA = {
|
||||
agents: {
|
||||
"lead-developer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"Core Dev",fit:92,desc:"Primary code writer",status:"optimal"}},
|
||||
"frontend-developer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"Core Dev",fit:90,desc:"UI implementation",status:"optimal"}},
|
||||
"backend-developer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"Core Dev",fit:91,desc:"Node.js/APIs",status:"optimal"}},
|
||||
"go-developer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"Core Dev",fit:85,desc:"Go backend",status:"optimal"}},
|
||||
"sdet-engineer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"QA",fit:88,desc:"TDD tests",status:"optimal"}},
|
||||
"code-skeptic": {current:{model:"ollama-cloud/minimax-m2.5",provider:"Ollama",category:"QA",fit:85,desc:"Adversarial review",status:"good"}},
|
||||
"security-auditor": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Security",fit:80,desc:"OWASP scanner",status:"good"}},
|
||||
"performance-engineer": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Performance",fit:82,desc:"N+1 detection",status:"good"}},
|
||||
"system-analyst": {current:{model:"ollama-cloud/glm-5",provider:"Ollama",category:"Analysis",fit:82,desc:"Architecture design",status:"good"}},
|
||||
"requirement-refiner": {current:{model:"ollama-cloud/gpt-oss:120b",provider:"Ollama",category:"Analysis",fit:62,desc:"User Stories",status:"needs-update"}},
|
||||
"history-miner": {current:{model:"ollama-cloud/glm-5",provider:"Ollama",category:"Analysis",fit:78,desc:"Git search",status:"good"}},
|
||||
"capability-analyst": {current:{model:"ollama-cloud/gpt-oss:120b",provider:"Ollama",category:"Analysis",fit:66,desc:"Gap analysis",status:"needs-update"}},
|
||||
"orchestrator": {current:{model:"ollama-cloud/glm-5",provider:"Ollama",category:"Process",fit:80,desc:"Task routing",status:"good"}},
|
||||
"release-manager": {current:{model:"ollama-cloud/devstral-2:123b",provider:"Ollama",category:"Process",fit:75,desc:"Git ops",status:"good"}},
|
||||
"evaluator": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Process",fit:82,desc:"Scoring",status:"good"}},
|
||||
"prompt-optimizer": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Process",fit:80,desc:"Prompt improvement",status:"good"}},
|
||||
"the-fixer": {current:{model:"ollama-cloud/minimax-m2.5",provider:"Ollama",category:"Fixes",fit:88,desc:"Bug fixing",status:"optimal"}},
|
||||
"product-owner": {current:{model:"ollama-cloud/glm-5",provider:"Ollama",category:"Management",fit:76,desc:"Backlog",status:"good"}},
|
||||
"workflow-architect": {current:{model:"ollama-cloud/glm-5",provider:"Ollama",category:"Process",fit:74,desc:"Workflow design",status:"good"}},
|
||||
"markdown-validator": {current:{model:"ollama-cloud/nemotron-3-nano:30b",provider:"Ollama",category:"Validation",fit:72,desc:"Markdown check",status:"good"}},
|
||||
"agent-architect": {current:{model:"ollama-cloud/gpt-oss:120b",provider:"Ollama",category:"Meta",fit:69,desc:"Agent design",status:"needs-update"}},
|
||||
"planner": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Cognitive",fit:84,desc:"Task planning",status:"good"}},
|
||||
"reflector": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Cognitive",fit:82,desc:"Self-reflection",status:"good"}},
|
||||
"memory-manager": {current:{model:"ollama-cloud/nemotron-3-super",provider:"Ollama",category:"Cognitive",fit:90,desc:"Memory systems",status:"optimal"}},
|
||||
"devops-engineer": {current:{model:null,provider:null,category:"DevOps",fit:0,desc:"Docker/K8s/CI",status:"new"}},
|
||||
"flutter-developer": {current:{model:"ollama-cloud/qwen3-coder:480b",provider:"Ollama",category:"Core Dev",fit:86,desc:"Flutter mobile",status:"optimal"}}
|
||||
},
|
||||
models: {
|
||||
"qwen3-coder:480b":{name:"Qwen3-Coder 480B",org:"Qwen",swe:66.5,ctx:"256K→1M",desc:"SOTA кодинг. Сравним с Claude Sonnet 4.",tags:["coding","agent","tools"]},
|
||||
"minimax-m2.5":{name:"MiniMax M2.5",org:"MiniMax",swe:80.2,ctx:"128K",desc:"Лидер SWE-bench 80.2%",tags:["coding","agent"]},
|
||||
"nemotron-3-super":{name:"Nemotron 3 Super",org:"NVIDIA",swe:60.5,ctx:"1M",ruler:91.75,desc:"RULER@1M 91.75%! PinchBench 85.6%",tags:["agent","reasoning","1M-ctx"]},
|
||||
"nemotron-3-nano:30b":{name:"Nemotron 3 Nano",org:"NVIDIA",ctx:"128K",desc:"Ультра-компактная. Thinking mode.",tags:["efficient","thinking"]},
|
||||
"glm-5":{name:"GLM-5",org:"Z.ai",ctx:"128K",desc:"Мощный reasoning",tags:["reasoning","agent"]},
|
||||
"gpt-oss:120b":{name:"GPT-OSS 120B",org:"OpenAI",swe:62.4,ctx:"130K",desc:"O4-mini уровень. Apache 2.0.",tags:["reasoning","tools"]},
|
||||
"devstral-2:123b":{name:"Devstral 2",org:"Mistral",ctx:"128K",desc:"Multi-file editing. Vision.",tags:["coding","vision"]}
|
||||
},
|
||||
recommendations: [
|
||||
{agent:"requirement-refiner",from:"gpt-oss:120b",to:"nemotron-3-super",priority:"critical",quality:"+22%",context:"130K→1M",reason:"Nemotron с RULER@1M 91.75% значительно лучше для спецификаций."},
|
||||
{agent:"capability-analyst",from:"gpt-oss:120b",to:"nemotron-3-super",priority:"critical",quality:"+21%",context:"130K→1M",reason:"Gap analysis требует агентских способностей. Nemotron (80 vs 66)."},
|
||||
{agent:"agent-architect",from:"gpt-oss:120b",to:"nemotron-3-super",priority:"high",quality:"+19%",context:"130K→1M",reason:"Agent design с длинным контекстом. Nemotron (82 vs 69)."},
|
||||
{agent:"history-miner",from:"glm-5",to:"nemotron-3-super",priority:"high",quality:"+13%",context:"128K→1M",reason:"Git history требует 1M контекст. Nemotron (88 vs 78)."},
|
||||
{agent:"devops-engineer",from:"(не назначена)",to:"nemotron-3-super",priority:"critical",reason:"Новый агент. Nemotron 1M для docker-compose + k8s manifests."},
|
||||
{agent:"prompt-optimizer",from:"nemotron-3-super",to:"qwen3.6-plus:free",priority:"high",quality:"+2%",reason:"FREE на OpenRouter. Terminal-Bench 61.6%"},
|
||||
{agent:"memory-manager",from:"gpt-oss:120b",to:"nemotron-3-super",priority:"applied",quality:"+30%",context:"130K→1M",reason:"Уже применено. RULER@1M критичен для памяти."},
|
||||
{agent:"evaluator",from:"gpt-oss:120b",to:"nemotron-3-super",priority:"applied",quality:"+15%",reason:"Уже применено. Nemotron оптимален для оценки."},
|
||||
{agent:"the-fixer",from:"minimax-m2.5",to:"minimax-m2.5",priority:"optimal",reason:"MiniMax M2.5 (SWE 80.2%) уже оптимален для фиксов."},
|
||||
{agent:"lead-developer",from:"qwen3-coder:480b",to:"qwen3-coder:480b",priority:"optimal",reason:"Qwen3-Coder (SWE 66.5%) оптимален для кодинга."}
|
||||
],
|
||||
history: [
|
||||
{date:"2026-04-05T05:21:00Z",agent:"security-auditor",from:"deepseek-v3.2",to:"nemotron-3-super",reason:"RULER@1M для security"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"performance-engineer",from:"gpt-oss:120b",to:"nemotron-3-super",reason:"Лучший reasoning"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"memory-manager",from:"gpt-oss:120b",to:"nemotron-3-super",reason:"1M контекст критичен"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"evaluator",from:"gpt-oss:120b",to:"nemotron-3-super",reason:"Оценка качества"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"planner",from:"gpt-oss:120b",to:"nemotron-3-super",reason:"CoT/ToT планирование"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"reflector",from:"gpt-oss:120b",to:"nemotron-3-super",reason:"Рефлексия"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"system-analyst",from:"gpt-oss:120b",to:"glm-5",reason:"GLM-5 для архитектуры"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"go-developer",from:"deepseek-v3.2",to:"qwen3-coder:480b",reason:"Qwen оптимален для Go"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"markdown-validator",from:"qwen3.6-plus:free",to:"nemotron-3-nano:30b",reason:"Nano для лёгких задач"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"prompt-optimizer",from:"qwen3.6-plus:free",to:"nemotron-3-super",reason:"Анализ промптов"},
|
||||
{date:"2026-04-05T05:21:00Z",agent:"product-owner",from:"qwen3.6-plus:free",to:"glm-5",reason:"Управление backlog"}
|
||||
],
|
||||
lastUpdated:"2026-04-05T18:00:00Z"
|
||||
};
|
||||
|
||||
// ======================= INITIALIZATION =======================
|
||||
const agentData = EMBEDDED_DATA;
|
||||
const modelData = EMBEDDED_DATA.models;
|
||||
const recommendations = EMBEDDED_DATA.recommendations;
|
||||
const historyData = EMBEDDED_DATA.history;
|
||||
|
||||
function init() {
|
||||
renderStats();
|
||||
renderAgentsTable();
|
||||
renderHeatmap();
|
||||
renderRecommendations();
|
||||
renderHistory();
|
||||
renderModels();
|
||||
}
|
||||
|
||||
// ======================= RENDER FUNCTIONS =======================
|
||||
function renderStats() {
|
||||
const agents = Object.values(agentData.agents);
|
||||
const total = agents.length;
|
||||
const optimal = agents.filter(a => a.current.status === 'optimal').length;
|
||||
const needsUpdate = agents.filter(a => a.current.status === 'needs-update').length;
|
||||
const critical = recommendations.filter(r => r.priority === 'critical').length;
|
||||
|
||||
document.getElementById('statsRow').innerHTML = `
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Всего агентов</div>
|
||||
<div class="stat-value grad-cyan">${total}</div>
|
||||
<div class="stat-sub">${Object.keys(agentData.agents).filter(a => agentData.agents[a].current.status === 'optimal').length} оптимально</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Требуют внимания</div>
|
||||
<div class="stat-value grad-orange">${needsUpdate + critical}</div>
|
||||
<div class="stat-sub">${critical} критичных</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Провайдеров</div>
|
||||
<div class="stat-value grad-green">3</div>
|
||||
<div class="stat-sub">Ollama, Groq, OR</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">История</div>
|
||||
<div class="stat-value grad-purple">${historyData.length}</div>
|
||||
<div class="stat-sub">изменений записано</div>
|
||||
</div>
|
||||
`;
|
||||
document.getElementById('agentsCount').textContent = total + ' агентов';
|
||||
}
|
||||
|
||||
function renderAgentsTable() {
|
||||
const rows = Object.entries(agentData.agents).map(([name, data]) => {
|
||||
const model = data.current.model || 'не назначена';
|
||||
const provider = data.current.provider || '—';
|
||||
const fit = data.current.fit || 0;
|
||||
const status = data.current.status || 'good';
|
||||
|
||||
const statusIcon = status === 'new' ? '🆕' :
|
||||
status === 'needs-update' ? '⚠️' :
|
||||
status === 'optimal' ? '✅' : '🟡';
|
||||
const statusText = status === 'new' ? 'Новый' :
|
||||
status === 'needs-update' ? 'Улучшить' :
|
||||
status === 'optimal' ? 'Оптимально' : 'Хорошо';
|
||||
|
||||
const modelClass = model.includes('qwen') ? 'qwen' :
|
||||
model.includes('minimax') ? 'minimax' :
|
||||
model.includes('nemotron') ? 'nemotron' :
|
||||
model.includes('glm') ? 'glm' :
|
||||
model.includes('gpt-oss') ? 'gptoss' :
|
||||
model.includes('devstral') ? 'devstral' : '';
|
||||
|
||||
return `
|
||||
<tr onclick="showAgentModal('${name}')" style="cursor:pointer" onmouseover="this.style.background='var(--bg-card-hover)'" onmouseout="this.style.background=''">
|
||||
<td style="font-weight:600">${name}</td>
|
||||
<td><span class="mbadge ${modelClass}">${model}</span></td>
|
||||
<td><span class="prov-tag ${provider?.toLowerCase()||''}">${provider}</span></td>
|
||||
<td><div class="sbar"><div class="sbar-bg"><div class="sbar-fill ${getScoreClass(fit)}" style="width:${fit}%"></div></div><span class="snum">${fit}</span></div></td>
|
||||
<td>${statusIcon} ${statusText}</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
document.getElementById('agentsTable').innerHTML = rows;
|
||||
}
|
||||
|
||||
function renderHeatmap() {
|
||||
const agents = ['Core Dev', 'QA', 'Security', 'Analysis', 'Process', 'Cognitive', 'DevOps'];
|
||||
const models = ['Qwen3-Coder', 'MiniMax M2.5', 'Nemotron', 'GLM-5', 'GPT-OSS'];
|
||||
|
||||
// Score matrix
|
||||
const scores = [
|
||||
[92, 82, 72, 68, 65], // Core Dev
|
||||
[88, 85, 76, 72, 70], // QA
|
||||
[75, 72, 90, 68, 65], // Security
|
||||
[72, 68, 88, 82, 62], // Analysis
|
||||
[78, 72, 85, 80, 65], // Process
|
||||
[75, 70, 92, 78, 66], // Cognitive
|
||||
[82, 68, 85, 75, 70], // DevOps
|
||||
];
|
||||
|
||||
let html = '<thead><tr><th class="hm-role">Категория</th>';
|
||||
models.forEach(m => html += `<th>${m}</th>`);
|
||||
html += '</tr></thead><tbody>';
|
||||
|
||||
agents.forEach((cat, i) => {
|
||||
html += `<tr><td class="hm-r">${cat}</td>`;
|
||||
models.forEach((m, j) => {
|
||||
const score = scores[i][j];
|
||||
const isCurrent = (i === 0 && j === 0) || (i === 2 && j === 2) || (i === 3 && j === 3) || (i === 4 && j === 3) || (i === 5 && j === 2);
|
||||
const style = `background:${getScoreColor(score)}15;color:${getScoreColor(score)}${isCurrent ? ';outline:2px solid var(--accent-cyan);outline-offset:-2px' : ''}`;
|
||||
html += `<td style="${style}" onclick="showModelFromHeatmap('${m}')">${score}${isCurrent ? '<span style="color:#FFD700;font-size:.75em">★</span>' : ''}</td>`;
|
||||
});
|
||||
html += '</tr>';
|
||||
});
|
||||
html += '</tbody>';
|
||||
document.getElementById('heatmapTable').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderRecommendations() {
|
||||
document.getElementById('recsCount').textContent = recommendations.length + ' рекомендаций';
|
||||
|
||||
const html = recommendations.map(r => {
|
||||
const priorityClass = r.priority === 'critical' ? 'critical' : r.priority === 'high' ? 'high' : r.priority === 'medium' ? 'medium' : 'optimal';
|
||||
const priorityText = r.priority === 'critical' ? '🔴 Критично' :
|
||||
r.priority === 'high' ? '🟠 Высокий' :
|
||||
r.priority === 'medium' ? '🟡 Средний' : '✅ Оптимально';
|
||||
|
||||
return `
|
||||
<div class="rec-card ${priorityClass}" data-priority="${r.priority}">
|
||||
<div class="rec-hdr">
|
||||
<span class="rec-agent">${r.agent}</span>
|
||||
<span class="imp-badge ${priorityClass}">${priorityText}</span>
|
||||
</div>
|
||||
<div class="swap-vis">
|
||||
<span class="swap-from">${r.from}</span>
|
||||
<span class="swap-arrow">→</span>
|
||||
<span class="swap-to">${r.to}</span>
|
||||
</div>
|
||||
<div class="rec-reason">${r.reason}</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
document.getElementById('recsGrid').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderHistory() {
|
||||
document.getElementById('historyCount').textContent = historyData.length + ' изменений';
|
||||
|
||||
const html = historyData.map(h => `
|
||||
<div class="gitea-item">
|
||||
<div class="gitea-date">${formatDate(h.date)}</div>
|
||||
<div class="gitea-content">
|
||||
<span class="gitea-agent">${h.agent}</span>
|
||||
<span class="gitea-change">: ${h.from} → ${h.to}</span>
|
||||
</div>
|
||||
<div style="font-size:.8em;color:var(--text-muted)">${h.reason}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
document.getElementById('historyTimeline').innerHTML = html;
|
||||
}
|
||||
|
||||
function renderModels() {
|
||||
const models = Object.values(modelData);
|
||||
const html = models.map(m => `
|
||||
<div class="mc" onclick="showModelModal('${m.name}')">
|
||||
<div style="font-weight:700;font-size:1.05em">${m.name}</div>
|
||||
<div style="font-size:.75em;color:var(--text-muted);margin:4px 0">${m.org} • Контекст: ${m.ctx}</div>
|
||||
${m.swe ? `<div style="font-size:.8em"><span style="color:var(--text-muted)">SWE-bench:</span> <span style="color:var(--accent-green);font-weight:600">${m.swe}%</span></div>` : ''}
|
||||
${m.ruler ? `<div style="font-size:.8em"><span style="color:var(--text-muted)">RULER@1M:</span> <span style="color:var(--accent-cyan);font-weight:600">${m.ruler}%</span></div>` : ''}
|
||||
<div style="font-size:.78em;color:var(--text-secondary);margin-top:8px;line-height:1.4">${m.desc}</div>
|
||||
<div style="margin-top:8px">${m.tags.map(t => `<span style="font-size:.68em;padding:2px 6px;background:rgba(0,212,255,.1);border-radius:12px;color:var(--accent-cyan);margin-right:4px">${t}</span>`).join('')}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
document.getElementById('modelsGrid').innerHTML = html;
|
||||
}
|
||||
|
||||
// ======================= MODAL FUNCTIONS =======================
|
||||
function showModelModal(modelName) {
|
||||
const m = Object.values(modelData).find(m => m.name === modelName);
|
||||
if (!m) return;
|
||||
|
||||
document.getElementById('modalTitle').textContent = m.name;
|
||||
document.getElementById('modalProvider').textContent = m.org;
|
||||
|
||||
document.getElementById('modalInfo').innerHTML = `
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Организация</div>
|
||||
<div class="model-info-value">${m.org}</div>
|
||||
</div>
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Контекст</div>
|
||||
<div class="model-info-value">${m.ctx}</div>
|
||||
</div>
|
||||
${m.swe ? `<div class="model-info-item">
|
||||
<div class="model-info-label">SWE-bench</div>
|
||||
<div class="model-info-value" style="color:var(--accent-green)">${m.swe}%</div>
|
||||
</div>` : ''}
|
||||
${m.ruler ? `<div class="model-info-item">
|
||||
<div class="model-info-label">RULER@1M</div>
|
||||
<div class="model-info-value" style="color:var(--accent-cyan)">${m.ruler}%</div>
|
||||
</div>` : ''}
|
||||
`;
|
||||
|
||||
document.getElementById('modalTags').innerHTML = m.tags.map(t => `<span class="model-tag">${t}</span>`).join('');
|
||||
|
||||
// Find agents using this model
|
||||
const agentsUsing = Object.entries(agentData.agents)
|
||||
.filter(([_, d]) => d.current.model?.includes(m.name.toLowerCase().split(' ')[0].toLowerCase()))
|
||||
.map(([name, _]) => name);
|
||||
|
||||
document.getElementById('modalAgents').innerHTML = agentsUsing.length > 0
|
||||
? agentsUsing.map(a => `<span class="mbadge">${a}</span>`).join('')
|
||||
: '<span style="color:var(--text-muted)">Нет агентов на этой модели</span>';
|
||||
|
||||
document.getElementById('modelModal').classList.add('show');
|
||||
}
|
||||
|
||||
function showAgentModal(agentName) {
|
||||
const a = agentData.agents[agentName];
|
||||
if (!a) return;
|
||||
|
||||
document.getElementById('modalTitle').textContent = agentName;
|
||||
document.getElementById('modalProvider').textContent = a.current.provider || '—';
|
||||
|
||||
document.getElementById('modalInfo').innerHTML = `
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Модель</div>
|
||||
<div class="model-info-value">${a.current.model || 'не назначена'}</div>
|
||||
</div>
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Категория</div>
|
||||
<div class="model-info-value">${a.current.category}</div>
|
||||
</div>
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Fit Score</div>
|
||||
<div class="model-info-value" style="color:${getScoreColor(a.current.fit)}">${a.current.fit || '—'}</div>
|
||||
</div>
|
||||
<div class="model-info-item">
|
||||
<div class="model-info-label">Статус</div>
|
||||
<div class="model-info-value">${a.current.status || '—'}</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('modalTags').innerHTML = '';
|
||||
document.getElementById('modalAgents').innerHTML = `<div style="color:var(--text-secondary);font-size:.9em">${a.current.desc}</div>`;
|
||||
|
||||
document.getElementById('modelModal').classList.add('show');
|
||||
}
|
||||
|
||||
function showModelFromHeatmap(modelName) {
|
||||
showModelModal(modelName);
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('modelModal').classList.remove('show');
|
||||
}
|
||||
|
||||
function filterRecs(filter, btn) {
|
||||
document.querySelectorAll('.frow .fbtn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
|
||||
if (filter === 'all') {
|
||||
document.querySelectorAll('.rec-card').forEach(c => c.style.display = '');
|
||||
} else {
|
||||
document.querySelectorAll('.rec-card').forEach(c => {
|
||||
c.style.display = c.dataset.priority === filter ? '' : 'none';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ======================= UTILITIES =======================
|
||||
function getScoreColor(score) {
|
||||
if (score >= 85) return '#00ff94';
|
||||
if (score >= 70) return '#ffc048';
|
||||
return '#ff6b81';
|
||||
}
|
||||
|
||||
function getScoreClass(score) {
|
||||
if (score >= 85) return 'h';
|
||||
if (score >= 70) return 'm';
|
||||
return 'l';
|
||||
}
|
||||
|
||||
function formatDate(dateStr) {
|
||||
const date = new Date(dateStr);
|
||||
return date.toLocaleDateString('ru-RU', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
function switchTab(tabId) {
|
||||
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('tab-' + tabId).classList.add('active');
|
||||
event.target.classList.add('active');
|
||||
}
|
||||
|
||||
document.getElementById('modelModal').addEventListener('click', (e) => {
|
||||
if (e.target.id === 'modelModal') closeModal();
|
||||
});
|
||||
|
||||
// Initialize
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
117
agent-evolution/scripts/build-standalone.cjs
Normal file
117
agent-evolution/scripts/build-standalone.cjs
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build standalone HTML with embedded data
|
||||
* Run: node agent-evolution/scripts/build-standalone.cjs
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DATA_FILE = path.join(__dirname, '../data/agent-versions.json');
|
||||
const HTML_FILE = path.join(__dirname, '../index.html');
|
||||
const OUTPUT_FILE = path.join(__dirname, '../index.standalone.html');
|
||||
|
||||
try {
|
||||
// Read data
|
||||
console.log('📖 Reading data from:', DATA_FILE);
|
||||
const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf-8'));
|
||||
console.log(' Found', Object.keys(data.agents).length, 'agents');
|
||||
|
||||
// Read HTML
|
||||
console.log('📖 Reading HTML from:', HTML_FILE);
|
||||
let html = fs.readFileSync(HTML_FILE, 'utf-8');
|
||||
|
||||
// Step 1: Replace EMBEDDED_DATA
|
||||
const startMarker = '// Default embedded data (minimal - updated by sync script)';
|
||||
const endPattern = /"sync_sources":\s*\[[^\]]*\]\s*\}\s*\};/;
|
||||
|
||||
const startIdx = html.indexOf(startMarker);
|
||||
const endMatch = html.match(endPattern);
|
||||
|
||||
if (startIdx === -1) {
|
||||
throw new Error('Start marker not found in HTML');
|
||||
}
|
||||
if (!endMatch) {
|
||||
throw new Error('End pattern not found in HTML');
|
||||
}
|
||||
|
||||
const endIdx = endMatch.index + endMatch[0].length + 1;
|
||||
|
||||
// Create embedded data
|
||||
const embeddedData = `// Embedded data (generated ${new Date().toISOString()})
|
||||
const EMBEDDED_DATA = ${JSON.stringify(data, null, 2)};`;
|
||||
|
||||
// Replace the section
|
||||
html = html.substring(0, startIdx) + embeddedData + html.substring(endIdx);
|
||||
|
||||
// Step 2: Replace entire init function
|
||||
// Find the init function start and end
|
||||
const initStartPattern = /\/\/ Initialize\s*\n\s*async function init\(\) \{/;
|
||||
const initStartMatch = html.match(initStartPattern);
|
||||
|
||||
if (initStartMatch) {
|
||||
const initStartIdx = initStartMatch.index;
|
||||
|
||||
// Find matching closing brace (count opening and closing)
|
||||
let braceCount = 0;
|
||||
let inFunction = false;
|
||||
let initEndIdx = initStartIdx;
|
||||
|
||||
for (let i = initStartIdx; i < html.length; i++) {
|
||||
if (html[i] === '{') {
|
||||
braceCount++;
|
||||
inFunction = true;
|
||||
} else if (html[i] === '}') {
|
||||
braceCount--;
|
||||
if (inFunction && braceCount === 0) {
|
||||
initEndIdx = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New init function
|
||||
const newInit = `// 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';
|
||||
}
|
||||
}`;
|
||||
|
||||
html = html.substring(0, initStartIdx) + newInit + html.substring(initEndIdx);
|
||||
}
|
||||
|
||||
// Write output
|
||||
fs.writeFileSync(OUTPUT_FILE, html);
|
||||
|
||||
console.log('\n✅ Built standalone dashboard');
|
||||
console.log(' Output:', OUTPUT_FILE);
|
||||
console.log(' Agents:', Object.keys(data.agents).length);
|
||||
console.log(' Size:', (fs.statSync(OUTPUT_FILE).size / 1024).toFixed(1), 'KB');
|
||||
console.log('\n📊 Open in browser:');
|
||||
console.log(' Windows: start agent-evolution\\index.standalone.html');
|
||||
console.log(' macOS: open agent-evolution/index.standalone.html');
|
||||
console.log(' Linux: xdg-open agent-evolution/index.standalone.html');
|
||||
} catch (error) {
|
||||
console.error('❌ Error:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
501
agent-evolution/scripts/sync-agent-history.ts
Normal file
501
agent-evolution/scripts/sync-agent-history.ts
Normal file
@@ -0,0 +1,501 @@
|
||||
#!/usr/bin/env bun
|
||||
/**
|
||||
* Agent Evolution Synchronization Script
|
||||
* Parses git history and syncs agent definitions
|
||||
*
|
||||
* Usage: bun run agent-evolution/scripts/sync-agent-history.ts
|
||||
*
|
||||
* Generates:
|
||||
* - data/agent-versions.json - JSON data
|
||||
* - index.standalone.html - Dashboard with embedded data
|
||||
*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
// Try to load yaml parser (optional)
|
||||
let yaml: any;
|
||||
try {
|
||||
yaml = require("yaml");
|
||||
} catch {
|
||||
yaml = null;
|
||||
}
|
||||
|
||||
// Types
|
||||
interface AgentVersion {
|
||||
date: string;
|
||||
commit: string;
|
||||
type: "model_change" | "prompt_change" | "agent_created" | "agent_removed" | "capability_change";
|
||||
from: string | null;
|
||||
to: string;
|
||||
reason: string;
|
||||
source: "git" | "gitea" | "manual";
|
||||
}
|
||||
|
||||
interface AgentConfig {
|
||||
model: string;
|
||||
provider: string;
|
||||
category: string;
|
||||
mode: string;
|
||||
color: string;
|
||||
description: string;
|
||||
benchmark?: {
|
||||
swe_bench?: number;
|
||||
ruler_1m?: number;
|
||||
terminal_bench?: number;
|
||||
pinch_bench?: number;
|
||||
fit_score?: number;
|
||||
};
|
||||
capabilities: string[];
|
||||
recommendations?: Array<{
|
||||
target: string;
|
||||
reason: string;
|
||||
priority: string;
|
||||
}>;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
interface AgentData {
|
||||
current: AgentConfig;
|
||||
history: AgentVersion[];
|
||||
performance_log: Array<{
|
||||
date: string;
|
||||
issue: number;
|
||||
score: number;
|
||||
duration_ms: number;
|
||||
success: boolean;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface EvolutionData {
|
||||
version: string;
|
||||
lastUpdated: string;
|
||||
agents: Record<string, AgentData>;
|
||||
providers: Record<string, { models: unknown[] }>;
|
||||
evolution_metrics: {
|
||||
total_agents: number;
|
||||
agents_with_history: number;
|
||||
pending_recommendations: number;
|
||||
last_sync: string;
|
||||
sync_sources: string[];
|
||||
};
|
||||
}
|
||||
|
||||
// Constants
|
||||
const AGENTS_DIR = ".kilo/agents";
|
||||
const CAPABILITY_INDEX = ".kilo/capability-index.yaml";
|
||||
const KILO_CONFIG = ".kilo/kilo.jsonc";
|
||||
const OUTPUT_FILE = "agent-evolution/data/agent-versions.json";
|
||||
const GIT_DIR = ".git";
|
||||
|
||||
// Provider detection
|
||||
function detectProvider(model: string): string {
|
||||
if (model.startsWith("ollama-cloud/") || model.startsWith("ollama/")) return "Ollama";
|
||||
if (model.startsWith("openrouter/") || model.includes("openrouter")) return "OpenRouter";
|
||||
if (model.startsWith("groq/")) return "Groq";
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// Parse agent file frontmatter
|
||||
function parseAgentFrontmatter(content: string): AgentConfig | null {
|
||||
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
||||
if (!frontmatterMatch) return null;
|
||||
|
||||
try {
|
||||
const frontmatter = frontmatterMatch[1];
|
||||
const lines = frontmatter.split("\n");
|
||||
const config: Record<string, unknown> = {};
|
||||
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^(\w+):\s*(.+)$/);
|
||||
if (match) {
|
||||
const [, key, value] = match;
|
||||
if (value === "allow" || value === "deny") {
|
||||
if (!config.permission) config.permission = {};
|
||||
(config.permission as Record<string, unknown>)[key] = value;
|
||||
} else if (key === "model") {
|
||||
config[key] = value;
|
||||
config.provider = detectProvider(value);
|
||||
} else {
|
||||
config[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config as unknown as AgentConfig;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get git history for agent changes
|
||||
function getGitHistory(): Map<string, AgentVersion[]> {
|
||||
const history = new Map<string, AgentVersion[]>();
|
||||
|
||||
try {
|
||||
// Get commits that modified agent files
|
||||
const result = spawnSync('git', ['log', '--all', '--oneline', '--follow', '--format=%H|%ai|%s', '--', '.kilo/agents/'], {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf-8',
|
||||
maxBuffer: 10 * 1024 * 1024
|
||||
});
|
||||
|
||||
if (result.status !== 0 || !result.stdout) {
|
||||
console.warn('Git log failed, skipping history');
|
||||
return history;
|
||||
}
|
||||
|
||||
const logOutput = result.stdout.trim();
|
||||
const commits = logOutput.split('\n').filter(Boolean);
|
||||
|
||||
for (const line of commits) {
|
||||
const [hash, date, ...msgParts] = line.split('|');
|
||||
if (!hash || !date) continue;
|
||||
|
||||
const message = msgParts.join('|').trim();
|
||||
|
||||
// Detect change type from commit message
|
||||
const agentMatch = message.match(/(?:add|update|fix|feat|change|set)\s+(\w+-?\w*)/i);
|
||||
|
||||
if (agentMatch) {
|
||||
const agentName = agentMatch[1].toLowerCase();
|
||||
const type = message.toLowerCase().includes("add") || message.toLowerCase().includes("feat")
|
||||
? "agent_created"
|
||||
: message.toLowerCase().includes("model")
|
||||
? "model_change"
|
||||
: "prompt_change";
|
||||
|
||||
if (!history.has(agentName)) {
|
||||
history.set(agentName, []);
|
||||
}
|
||||
|
||||
history.get(agentName)!.push({
|
||||
date: date.replace(" ", "T") + "Z",
|
||||
commit: hash.substring(0, 8),
|
||||
type: type as AgentVersion["type"],
|
||||
from: null, // Will be filled later
|
||||
to: "", // Will be filled later
|
||||
reason: message,
|
||||
source: "git"
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Git history extraction failed:", error);
|
||||
}
|
||||
|
||||
return history;
|
||||
}
|
||||
|
||||
// Load capability index (simple parsing without yaml dependency)
|
||||
function loadCapabilityIndex(): Record<string, AgentConfig> {
|
||||
const configs: Record<string, AgentConfig> = {};
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(CAPABILITY_INDEX, "utf-8");
|
||||
|
||||
// Simple YAML-ish parsing for our specific format
|
||||
// Extract agent blocks
|
||||
const agentRegex = /^ (\w[\w-]+):\n((?: .+\n?)+)/gm;
|
||||
let match;
|
||||
|
||||
while ((match = agentRegex.exec(content)) !== null) {
|
||||
const name = match[1];
|
||||
if (name === 'capability_routing' || name === 'parallel_groups' ||
|
||||
name === 'iteration_loops' || name === 'quality_gates' ||
|
||||
name === 'workflow_states') continue;
|
||||
|
||||
const block = match[2];
|
||||
|
||||
// Extract model
|
||||
const modelMatch = block.match(/model:\s*(.+)/);
|
||||
if (!modelMatch) continue;
|
||||
|
||||
const model = modelMatch[1].trim();
|
||||
|
||||
// Extract capabilities
|
||||
const capsMatch = block.match(/capabilities:\n((?: - .+\n?)+)/);
|
||||
const capabilities = capsMatch
|
||||
? capsMatch[1].split('\n').filter(l => l.trim()).map(l => l.replace(/^\s*-?\s*/, '').trim())
|
||||
: [];
|
||||
|
||||
// Extract mode
|
||||
const modeMatch = block.match(/mode:\s*(\w+)/);
|
||||
const mode = modeMatch ? modeMatch[1] : 'subagent';
|
||||
|
||||
configs[name] = {
|
||||
model,
|
||||
provider: detectProvider(model),
|
||||
category: capabilities[0]?.replace(/_/g, ' ') || 'General',
|
||||
mode,
|
||||
color: '#6B7280',
|
||||
description: '',
|
||||
capabilities,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Capability index loading failed:", error);
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
// Load kilo.jsonc configuration
|
||||
function loadKiloConfig(): Record<string, AgentConfig> {
|
||||
const configs: Record<string, AgentConfig> = {};
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(KILO_CONFIG, "utf-8");
|
||||
// Remove comments for JSON parsing
|
||||
const cleaned = content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, "");
|
||||
const parsed = JSON.parse(cleaned);
|
||||
|
||||
if (parsed.agent) {
|
||||
for (const [name, config] of Object.entries(parsed.agent)) {
|
||||
const agentConfig = config as Record<string, unknown>;
|
||||
if (agentConfig.model) {
|
||||
configs[name] = {
|
||||
model: agentConfig.model as string,
|
||||
provider: detectProvider(agentConfig.model as string),
|
||||
category: "Built-in",
|
||||
mode: (agentConfig.mode as string) || "primary",
|
||||
color: "#3B82F6",
|
||||
description: (agentConfig.description as string) || "",
|
||||
capabilities: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Kilo config loading failed:", error);
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
// Load all agent files
|
||||
function loadAgentFiles(): Record<string, AgentConfig> {
|
||||
const configs: Record<string, AgentConfig> = {};
|
||||
|
||||
try {
|
||||
const files = fs.readdirSync(AGENTS_DIR);
|
||||
|
||||
for (const file of files) {
|
||||
if (!file.endsWith(".md")) continue;
|
||||
|
||||
const filepath = path.join(AGENTS_DIR, file);
|
||||
const content = fs.readFileSync(filepath, "utf-8");
|
||||
const frontmatter = parseAgentFrontmatter(content);
|
||||
|
||||
if (frontmatter && frontmatter.model) {
|
||||
const name = file.replace(".md", "");
|
||||
configs[name] = {
|
||||
...frontmatter,
|
||||
category: getCategoryFromCapabilities(frontmatter.capabilities),
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Agent files loading failed:", error);
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
// Get category from capabilities
|
||||
function getCategoryFromCapabilities(capabilities?: string[]): string {
|
||||
if (!capabilities) return "General";
|
||||
|
||||
const categoryMap: Record<string, string> = {
|
||||
code: "Core Dev",
|
||||
ui: "Frontend",
|
||||
test: "QA",
|
||||
security: "Security",
|
||||
performance: "Performance",
|
||||
devops: "DevOps",
|
||||
go_: "Go Development",
|
||||
flutter: "Mobile",
|
||||
memory: "Cognitive",
|
||||
plan: "Cognitive",
|
||||
workflow: "Process",
|
||||
markdown: "Validation",
|
||||
};
|
||||
|
||||
for (const cap of capabilities) {
|
||||
const key = Object.keys(categoryMap).find((k) => cap.toLowerCase().includes(k.toLowerCase()));
|
||||
if (key) return categoryMap[key];
|
||||
}
|
||||
|
||||
return "General";
|
||||
}
|
||||
|
||||
// Merge all sources
|
||||
function mergeConfigs(
|
||||
agentFiles: Record<string, AgentConfig>,
|
||||
capabilityIndex: Record<string, AgentConfig>,
|
||||
kiloConfig: Record<string, AgentConfig>
|
||||
): Record<string, AgentConfig> {
|
||||
const merged: Record<string, AgentConfig> = {};
|
||||
|
||||
// Start with agent files (highest priority)
|
||||
for (const [name, config] of Object.entries(agentFiles)) {
|
||||
merged[name] = { ...config };
|
||||
}
|
||||
|
||||
// Overlay capability index data
|
||||
for (const [name, config] of Object.entries(capabilityIndex)) {
|
||||
if (merged[name]) {
|
||||
merged[name] = {
|
||||
...merged[name],
|
||||
capabilities: config.capabilities,
|
||||
};
|
||||
} else {
|
||||
merged[name] = config;
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay kilo.jsonc data
|
||||
for (const [name, config] of Object.entries(kiloConfig)) {
|
||||
if (merged[name]) {
|
||||
merged[name] = {
|
||||
...merged[name],
|
||||
model: config.model,
|
||||
provider: config.provider,
|
||||
};
|
||||
} else {
|
||||
merged[name] = config;
|
||||
}
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
// Main sync function
|
||||
async function sync() {
|
||||
console.log("🔄 Syncing agent evolution data...\n");
|
||||
|
||||
// Load all sources
|
||||
console.log("📂 Loading agent files...");
|
||||
const agentFiles = loadAgentFiles();
|
||||
console.log(` Found ${Object.keys(agentFiles).length} agent files`);
|
||||
|
||||
console.log("📄 Loading capability index...");
|
||||
const capabilityIndex = loadCapabilityIndex();
|
||||
console.log(` Found ${Object.keys(capabilityIndex).length} agents`);
|
||||
|
||||
console.log("⚙️ Loading kilo config...");
|
||||
const kiloConfig = loadKiloConfig();
|
||||
console.log(` Found ${Object.keys(kiloConfig).length} agents`);
|
||||
|
||||
// Get git history
|
||||
console.log("\n📜 Parsing git history...");
|
||||
const gitHistory = await getGitHistory();
|
||||
console.log(` Found history for ${gitHistory.size} agents`);
|
||||
|
||||
// Merge configs
|
||||
const merged = mergeConfigs(agentFiles, capabilityIndex, kiloConfig);
|
||||
|
||||
// Load existing evolution data
|
||||
let existingData: EvolutionData = {
|
||||
version: "1.0.0",
|
||||
lastUpdated: new Date().toISOString(),
|
||||
agents: {},
|
||||
providers: {
|
||||
Ollama: { models: [] },
|
||||
OpenRouter: { models: [] },
|
||||
Groq: { models: [] },
|
||||
},
|
||||
evolution_metrics: {
|
||||
total_agents: 0,
|
||||
agents_with_history: 0,
|
||||
pending_recommendations: 0,
|
||||
last_sync: new Date().toISOString(),
|
||||
sync_sources: ["git", "capability-index.yaml", "kilo.jsonc"],
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(OUTPUT_FILE)) {
|
||||
const existing = JSON.parse(fs.readFileSync(OUTPUT_FILE, "utf-8"));
|
||||
existingData.agents = existing.agents || {};
|
||||
}
|
||||
} catch {
|
||||
// Use defaults
|
||||
}
|
||||
|
||||
// Update agents
|
||||
for (const [name, config] of Object.entries(merged)) {
|
||||
const existingAgent = existingData.agents[name];
|
||||
|
||||
// Check if model changed
|
||||
if (existingAgent?.current?.model && existingAgent.current.model !== config.model) {
|
||||
// Add to history
|
||||
existingAgent.history.push({
|
||||
date: new Date().toISOString(),
|
||||
commit: "sync",
|
||||
type: "model_change",
|
||||
from: existingAgent.current.model,
|
||||
to: config.model,
|
||||
reason: "Model update from sync",
|
||||
source: "git",
|
||||
});
|
||||
existingAgent.current = { ...config };
|
||||
} else {
|
||||
existingData.agents[name] = {
|
||||
current: config,
|
||||
history: existingAgent?.history || gitHistory.get(name) || [],
|
||||
performance_log: existingAgent?.performance_log || [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Update metrics
|
||||
existingData.evolution_metrics.total_agents = Object.keys(existingData.agents).length;
|
||||
existingData.evolution_metrics.agents_with_history = Object.values(existingData.agents).filter(
|
||||
(a) => a.history.length > 0
|
||||
).length;
|
||||
existingData.evolution_metrics.pending_recommendations = Object.values(existingData.agents).filter(
|
||||
(a) => a.current.recommendations && a.current.recommendations.length > 0
|
||||
).length;
|
||||
existingData.evolution_metrics.last_sync = new Date().toISOString();
|
||||
|
||||
// Save JSON
|
||||
fs.writeFileSync(OUTPUT_FILE, JSON.stringify(existingData, null, 2));
|
||||
console.log(`\n✅ Synced ${existingData.evolution_metrics.total_agents} agents to ${OUTPUT_FILE}`);
|
||||
|
||||
// Generate standalone HTML
|
||||
generateStandalone(existingData);
|
||||
|
||||
// Print summary
|
||||
console.log("\n📊 Summary:");
|
||||
console.log(` Total agents: ${existingData.evolution_metrics.total_agents}`);
|
||||
console.log(` Agents with history: ${existingData.evolution_metrics.agents_with_history}`);
|
||||
console.log(` Pending recommendations: ${existingData.evolution_metrics.pending_recommendations}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate standalone HTML with embedded data
|
||||
*/
|
||||
function generateStandalone(data: EvolutionData): void {
|
||||
const templatePath = path.join(__dirname, '../index.html');
|
||||
const outputPath = path.join(__dirname, '../index.standalone.html');
|
||||
|
||||
let html = fs.readFileSync(templatePath, 'utf-8');
|
||||
|
||||
// Replace EMBEDDED_DATA with actual data
|
||||
const embeddedDataStr = `const EMBEDDED_DATA = ${JSON.stringify(data, null, 2)};`;
|
||||
|
||||
// Find and replace the EMBEDDED_DATA declaration
|
||||
html = html.replace(
|
||||
/const EMBEDDED_DATA = \{[\s\S]*?\};?\s*\/\/ Initialize/,
|
||||
embeddedDataStr + '\n\n// Initialize'
|
||||
);
|
||||
|
||||
fs.writeFileSync(outputPath, html);
|
||||
console.log(`📄 Generated standalone: ${outputPath}`);
|
||||
console.log(` File size: ${(fs.statSync(outputPath).size / 1024).toFixed(1)} KB`);
|
||||
}
|
||||
|
||||
// Run
|
||||
sync().catch(console.error);
|
||||
57
docker-compose.evolution.yml
Normal file
57
docker-compose.evolution.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
# Docker Compose for Agent Evolution Dashboard
|
||||
# Usage: docker-compose -f docker-compose.evolution.yml up -d
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
evolution-dashboard:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: agent-evolution/Dockerfile
|
||||
target: production
|
||||
container_name: apaw-evolution
|
||||
ports:
|
||||
- "3001:3001"
|
||||
volumes:
|
||||
# Mount data directory for live updates
|
||||
- ./agent-evolution/data:/app/data:ro
|
||||
# Mount for reading source files (optional, for sync)
|
||||
- ./.kilo/agents:/app/kilo/agents:ro
|
||||
- ./.kilo/capability-index.yaml:/app/kilo/capability-index.yaml:ro
|
||||
- ./.kilo/kilo.jsonc:/app/kilo/kilo.jsonc:ro
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- TZ=UTC
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
networks:
|
||||
- evolution-network
|
||||
labels:
|
||||
- "com.apaw.service=evolution-dashboard"
|
||||
- "com.apaw.description=Agent Evolution Dashboard"
|
||||
|
||||
# Optional: Nginx reverse proxy with SSL
|
||||
evolution-nginx:
|
||||
image: nginx:alpine
|
||||
container_name: apaw-evolution-nginx
|
||||
profiles:
|
||||
- nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./agent-evolution/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./agent-evolution/ssl:/etc/nginx/ssl:ro
|
||||
depends_on:
|
||||
- evolution-dashboard
|
||||
networks:
|
||||
- evolution-network
|
||||
|
||||
networks:
|
||||
evolution-network:
|
||||
driver: bridge
|
||||
11
package.json
11
package.json
@@ -20,7 +20,16 @@
|
||||
"dev": "tsc --watch",
|
||||
"clean": "rm -rf dist",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "bun test"
|
||||
"test": "bun test",
|
||||
"sync:evolution": "bun run agent-evolution/scripts/sync-agent-history.ts && node agent-evolution/scripts/build-standalone.cjs",
|
||||
"evolution:build": "node agent-evolution/scripts/build-standalone.cjs",
|
||||
"evolution:open": "start agent-evolution/index.standalone.html",
|
||||
"evolution:dashboard": "bunx serve agent-evolution -l 3001",
|
||||
"evolution:run": "docker run -d --name apaw-evolution-dashboard -p 3001:3001 -v \"$(pwd)/agent-evolution/data:/app/data:ro\" apaw-evolution:latest",
|
||||
"evolution:stop": "docker stop apaw-evolution-dashboard && docker rm apaw-evolution-dashboard",
|
||||
"evolution:start": "bash agent-evolution/docker-run.sh run",
|
||||
"evolution:dev": "docker-compose -f docker-compose.evolution.yml up -d",
|
||||
"evolution:logs": "docker logs -f apaw-evolution-dashboard"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.24.1"
|
||||
|
||||
Reference in New Issue
Block a user