feat: Node Self-Healing, DAGI Audit, Agent Prompts, Infra Invariants
### Backend (city-service) - Node Registry + Self-Healing API (migration 039) - Improved get_all_nodes() with robust fallback for node_registry/node_cache - Agent Prompts Runtime API for DAGI Router integration - DAGI Router Audit endpoints (phantom/stale detection) - Node Agents API (Guardian/Steward) - Node metrics extended (CPU/GPU/RAM/Disk) ### Frontend (apps/web) - Node Directory with improved error handling - Node Cabinet with metrics cards - DAGI Router Card component - Node Metrics Card component - useDAGIAudit hook ### Scripts - check-invariants.py - deploy verification - node-bootstrap.sh - node self-registration - node-guardian-loop.py - continuous self-healing - dagi_agent_audit.py - DAGI audit utility ### Migrations - 034: Agent prompts seed - 035: Agent DAGI audit - 036: Node metrics extended - 037: Node agents complete - 038: Agent prompts full coverage - 039: Node registry self-healing ### Tests - test_infra_smoke.py - test_agent_prompts_runtime.py - test_dagi_router_api.py ### Documentation - DEPLOY_CHECKLIST_2024_11_30.md - Multiple TASK_PHASE docs
This commit is contained in:
244
docs/DEPLOY_CHECKLIST_2024_11_30.md
Normal file
244
docs/DEPLOY_CHECKLIST_2024_11_30.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# 🚀 DEPLOY CHECKLIST — daarion.space
|
||||
|
||||
**Дата:** 2024-11-30
|
||||
**Версія:** MVP Node Self-Healing + DAGI Audit + Agent Prompts
|
||||
|
||||
---
|
||||
|
||||
## 📋 Що деплоїмо
|
||||
|
||||
### Backend (city-service)
|
||||
- ✅ Node Registry + Self-Healing API
|
||||
- ✅ Improved `get_all_nodes()` з fallback
|
||||
- ✅ Agent Prompts Runtime API
|
||||
- ✅ DAGI Router Audit API
|
||||
- ✅ Node Agents API (Guardian/Steward)
|
||||
|
||||
### Frontend (apps/web)
|
||||
- ✅ Node Directory з покращеним error handling
|
||||
- ✅ Node Cabinet з метриками
|
||||
- ✅ DAGI Router Card
|
||||
- ✅ Node Metrics Card
|
||||
|
||||
### Scripts
|
||||
- ✅ `check-invariants.py` — перевірка інваріантів
|
||||
- ✅ `node-bootstrap.sh` — самореєстрація ноди
|
||||
- ✅ `node-guardian-loop.py` — self-healing loop
|
||||
|
||||
### Міграції (НОВІ)
|
||||
- `034_agent_prompts_seed.sql`
|
||||
- `035_agent_dagi_audit.sql`
|
||||
- `036_node_metrics_extended.sql`
|
||||
- `037_node_agents_complete.sql`
|
||||
- `038_agent_prompts_full_coverage.sql`
|
||||
- `039_node_registry_self_healing.sql`
|
||||
|
||||
---
|
||||
|
||||
## 🔧 КРОК 1: Локально — Закомітити та запушити
|
||||
|
||||
```bash
|
||||
cd /Users/apple/github-projects/microdao-daarion
|
||||
|
||||
# Додати всі зміни
|
||||
git add .
|
||||
|
||||
# Закомітити
|
||||
git commit -m "feat: Node Self-Healing, DAGI Audit, Agent Prompts, Infra Invariants
|
||||
|
||||
- Node Registry for self-healing (migration 039)
|
||||
- Improved get_all_nodes() with robust fallback
|
||||
- Agent Prompts Runtime API for DAGI Router
|
||||
- DAGI Router Audit endpoints
|
||||
- Node metrics and Guardian/Steward APIs
|
||||
- check-invariants.py for deploy verification
|
||||
- node-bootstrap.sh for node self-registration
|
||||
- node-guardian-loop.py for continuous self-healing
|
||||
- Updated Node Directory UI with better error handling
|
||||
- Node Cabinet with metrics cards and DAGI Router card"
|
||||
|
||||
# Запушити
|
||||
git push origin main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ КРОК 2: На сервері NODE1 (Hetzner)
|
||||
|
||||
### 2.1. SSH на сервер
|
||||
```bash
|
||||
ssh root@<NODE1_IP>
|
||||
# або через ваш алиас
|
||||
ssh node1
|
||||
```
|
||||
|
||||
### 2.2. Перейти в директорію проєкту
|
||||
```bash
|
||||
cd /opt/daarion
|
||||
# або ваш шлях до проєкту
|
||||
```
|
||||
|
||||
### 2.3. Оновити код
|
||||
```bash
|
||||
git pull origin main
|
||||
```
|
||||
|
||||
### 2.4. Застосувати міграції
|
||||
```bash
|
||||
# Підключитися до PostgreSQL
|
||||
docker exec -it daarion-postgres psql -U daarion_user -d daarion
|
||||
|
||||
# Або напряму через psql
|
||||
PGPASSWORD=<password> psql -h localhost -U daarion_user -d daarion
|
||||
|
||||
# Виконати міграції послідовно:
|
||||
\i migrations/034_agent_prompts_seed.sql
|
||||
\i migrations/035_agent_dagi_audit.sql
|
||||
\i migrations/036_node_metrics_extended.sql
|
||||
\i migrations/037_node_agents_complete.sql
|
||||
\i migrations/038_agent_prompts_full_coverage.sql
|
||||
\i migrations/039_node_registry_self_healing.sql
|
||||
|
||||
# Вийти
|
||||
\q
|
||||
```
|
||||
|
||||
### 2.5. Перебілдити і перезапустити сервіси
|
||||
```bash
|
||||
# Зупинити сервіси
|
||||
docker compose -f docker-compose.all.yml down
|
||||
|
||||
# Перебілдити
|
||||
docker compose -f docker-compose.all.yml build
|
||||
|
||||
# Запустити
|
||||
docker compose -f docker-compose.all.yml up -d
|
||||
```
|
||||
|
||||
### 2.6. Перевірити здоров'я
|
||||
```bash
|
||||
# Перевірити статус контейнерів
|
||||
docker ps | grep daarion
|
||||
|
||||
# Перевірити логи city-service
|
||||
docker logs -f daarion-city-service --tail 100
|
||||
|
||||
# Перевірити /healthz
|
||||
curl http://localhost:7001/healthz
|
||||
|
||||
# Перевірити /public/nodes
|
||||
curl http://localhost:7001/public/nodes | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 КРОК 3: Перевірка інваріантів
|
||||
|
||||
```bash
|
||||
# На сервері (або локально якщо є доступ)
|
||||
python3 scripts/check-invariants.py --base-url http://localhost:7001
|
||||
|
||||
# Очікуваний результат:
|
||||
# ✅ ALL INVARIANTS PASSED
|
||||
# або
|
||||
# ⚠️ WARNINGS (деякі можуть бути нормальними)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 КРОК 4: Smoke-тести
|
||||
|
||||
```bash
|
||||
# Якщо встановлено pytest
|
||||
pytest tests/test_infra_smoke.py -v --base-url http://localhost:7001
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 КРОК 5: Перевірка в браузері
|
||||
|
||||
1. **Node Directory:** https://daarion.space/nodes
|
||||
- Повинні відображатися NODE1 і NODE2
|
||||
- Без "Помилка завантаження нод"
|
||||
|
||||
2. **Node Cabinet:** https://daarion.space/nodes/node-1-hetzner-gex44
|
||||
- Метрики CPU/GPU/RAM/Disk
|
||||
- DAGI Router Card
|
||||
- Guardian/Steward агенти
|
||||
|
||||
3. **Agents:** https://daarion.space/agents
|
||||
- System Prompts для агентів
|
||||
|
||||
---
|
||||
|
||||
## 🔄 КРОК 6 (опційно): Node Bootstrap
|
||||
|
||||
Якщо ноди не з'являються після міграції:
|
||||
|
||||
```bash
|
||||
# На NODE1
|
||||
NODE_ID=node-1-hetzner-gex44 \
|
||||
NODE_NAME="NODE1 — Hetzner GEX44" \
|
||||
NODE_ENVIRONMENT=production \
|
||||
NODE_ROLES=production,gpu,ai_runtime,storage,matrix \
|
||||
./scripts/node-bootstrap.sh
|
||||
|
||||
# На NODE2 (якщо потрібно)
|
||||
NODE_ID=node-2-macbook-m4max \
|
||||
NODE_NAME="NODE2 — MacBook Pro M4 Max" \
|
||||
NODE_ENVIRONMENT=development \
|
||||
NODE_ROLES=development,gpu,ai_runtime,testing \
|
||||
./scripts/node-bootstrap.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ❌ Rollback (якщо щось пішло не так)
|
||||
|
||||
```bash
|
||||
# Відкотити код
|
||||
git reset --hard HEAD~1
|
||||
git push -f origin main
|
||||
|
||||
# На сервері
|
||||
git pull origin main
|
||||
docker compose -f docker-compose.all.yml down
|
||||
docker compose -f docker-compose.all.yml up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Очікуваний результат
|
||||
|
||||
Після успішного деплою:
|
||||
|
||||
| Компонент | URL | Очікуваний статус |
|
||||
|-----------|-----|-------------------|
|
||||
| Health | /healthz | `{"status": "ok"}` |
|
||||
| Nodes | /public/nodes | `{"items": [...], "total": 2}` |
|
||||
| Node Cabinet | /nodes/{id} | Метрики + DAGI + Agents |
|
||||
| Invariants | check-invariants.py | ✅ PASSED |
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
### "Failed to fetch nodes"
|
||||
1. Перевірити логи: `docker logs daarion-city-service`
|
||||
2. Перевірити чи є записи в node_cache: `SELECT * FROM node_cache;`
|
||||
3. Застосувати міграцію 039
|
||||
|
||||
### "node_registry does not exist"
|
||||
```sql
|
||||
\i migrations/039_node_registry_self_healing.sql
|
||||
```
|
||||
|
||||
### "Ноди не відображаються"
|
||||
```bash
|
||||
# Перевірити node_cache
|
||||
docker exec -it daarion-postgres psql -U daarion_user -d daarion -c "SELECT node_id, node_name FROM node_cache;"
|
||||
|
||||
# Якщо порожньо — запустити bootstrap
|
||||
./scripts/node-bootstrap.sh
|
||||
```
|
||||
|
||||
214
docs/tasks/TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v1.md
Normal file
214
docs/tasks/TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v1.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v1
|
||||
|
||||
## Проєкт
|
||||
|
||||
microdao-daarion (MVP DAARION.city)
|
||||
|
||||
## Статус
|
||||
|
||||
✅ **COMPLETED** — 2025-11-30
|
||||
|
||||
## Мета
|
||||
|
||||
Зробити так, щоб системні промти агентів:
|
||||
- зберігались у реальній БД (`agent_prompts` таблиця)
|
||||
- завантажувались через API
|
||||
- редагувалися через UI на сторінці `/agents/:slug` (вкладка System Prompts)
|
||||
|
||||
Після виконання цієї фази вкладка System Prompts перестає бути "плейсхолдером" і працює як повноцінний редактор системних промтів для ключових агентів DAARION.city.
|
||||
|
||||
---
|
||||
|
||||
## Виконані роботи
|
||||
|
||||
### 1. Аналіз проблеми
|
||||
|
||||
**Причина порожніх промтів:**
|
||||
- Backend routes (`routes_city.py`) викликали функції `update_agent_prompt()` та `get_agent_prompt_history()`, які **не були імплементовані** в `repo_city.py`
|
||||
- Функція `get_agent_prompts()` вже існувала і правильно повертала дані
|
||||
|
||||
**Структура, яка вже працювала:**
|
||||
- ✅ Міграція `016_agent_prompts.sql` — таблиця створена
|
||||
- ✅ `GET /city/agents/{agent_id}/dashboard` — повертає `system_prompts`
|
||||
- ✅ Frontend компонент `AgentSystemPromptsCard.tsx`
|
||||
- ✅ Next.js API routes proxy
|
||||
|
||||
### 2. Backend: Додані функції в `repo_city.py`
|
||||
|
||||
#### `update_agent_prompt(agent_id, kind, content, created_by, note)`
|
||||
- Деактивує попередню версію промта
|
||||
- Створює нову версію з інкрементованим номером
|
||||
- Повертає оновлений запис
|
||||
|
||||
#### `get_agent_prompt_history(agent_id, kind, limit)`
|
||||
- Повертає історію всіх версій промту
|
||||
- Впорядковано по версії (DESC)
|
||||
|
||||
**Файл:** `services/city-service/repo_city.py` (рядки ~628-705)
|
||||
|
||||
### 3. Seed Data: Міграція `034_agent_prompts_seed.sql`
|
||||
|
||||
Створено детальні системні промти для ключових агентів:
|
||||
|
||||
| Агент | Промти | Роль |
|
||||
|-------|--------|------|
|
||||
| DAARWIZZ | core, safety, governance | City Mayor / Orchestrator |
|
||||
| DARIA | core, safety | Technical Support |
|
||||
| DARIO | core | Community Manager |
|
||||
| SOUL | core, safety | District Lead (Wellness) |
|
||||
| Spirit | core | Guidance Agent |
|
||||
| Logic | core | Information Agent |
|
||||
| Helion | core, safety, tools | District Lead (Energy) |
|
||||
| GREENFOOD | core, safety | District Lead (Supply-Chain) |
|
||||
|
||||
---
|
||||
|
||||
## API Reference
|
||||
|
||||
### Отримати всі промти агента
|
||||
```
|
||||
GET /city/agents/{agent_id}/dashboard
|
||||
```
|
||||
Повертає `system_prompts` об'єкт з 4 типами: core, safety, governance, tools
|
||||
|
||||
### Оновити промт
|
||||
```
|
||||
PUT /city/agents/{agent_id}/prompts/{kind}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"content": "New prompt content...",
|
||||
"note": "Optional change note"
|
||||
}
|
||||
```
|
||||
|
||||
### Отримати історію промту
|
||||
```
|
||||
GET /city/agents/{agent_id}/prompts/{kind}/history?limit=10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Схема БД: `agent_prompts`
|
||||
|
||||
```sql
|
||||
CREATE TABLE agent_prompts (
|
||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
agent_id text NOT NULL,
|
||||
kind text NOT NULL CHECK (kind IN ('core', 'safety', 'governance', 'tools')),
|
||||
content text NOT NULL,
|
||||
version integer NOT NULL DEFAULT 1,
|
||||
created_at timestamptz NOT NULL DEFAULT now(),
|
||||
created_by text,
|
||||
note text,
|
||||
is_active boolean NOT NULL DEFAULT true
|
||||
);
|
||||
```
|
||||
|
||||
**Індекси:**
|
||||
- `idx_agent_prompts_agent_kind` — пошук активних промтів
|
||||
- `idx_agent_prompts_agent_created_at` — сортування по часу
|
||||
- `idx_agent_prompts_active` — фільтр активних
|
||||
|
||||
---
|
||||
|
||||
## Frontend
|
||||
|
||||
### Сторінка агента
|
||||
`/agents/[agentId]` → вкладка "System Prompts"
|
||||
|
||||
### Компоненти
|
||||
- `apps/web/src/app/agents/[agentId]/page.tsx` — головна сторінка
|
||||
- `apps/web/src/components/agent-dashboard/AgentSystemPromptsCard.tsx` — редактор промтів
|
||||
- `apps/web/src/lib/agent-dashboard.ts` — API клієнт
|
||||
|
||||
### Можливості
|
||||
- Перемикання між типами промтів (core/safety/governance/tools)
|
||||
- Редагування тексту промта
|
||||
- Збереження змін з індикацією статусу
|
||||
- Перегляд версії та часу останнього оновлення
|
||||
|
||||
---
|
||||
|
||||
## Застосування міграції
|
||||
|
||||
```bash
|
||||
# На сервері
|
||||
cd /opt/microdao-daarion
|
||||
psql -U postgres -d daarion < migrations/034_agent_prompts_seed.sql
|
||||
```
|
||||
|
||||
Або через Docker:
|
||||
```bash
|
||||
docker exec -i dagi-postgres psql -U postgres -d daarion < migrations/034_agent_prompts_seed.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- ✅ Для будь-якого агента з seed-промтами: `/agents/:id` → вкладка System Prompts показує реальний текст з БД
|
||||
- ✅ Редагування промта з UI: змінює запис у БД, після перезавантаження новий текст відображається
|
||||
- ✅ API GET/PUT працюють коректно
|
||||
- ✅ Версіонування: кожне збереження створює нову версію
|
||||
- ✅ Seed-дані для 8 ключових агентів
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope (на потім)
|
||||
|
||||
- [ ] UI для перегляду історії версій
|
||||
- [ ] Перемикання на попередню версію (rollback)
|
||||
- [ ] RBAC перевірки (хто може редагувати)
|
||||
- [ ] Інтеграція з DAGI Router runtime
|
||||
|
||||
---
|
||||
|
||||
## Файли змінені/створені
|
||||
|
||||
### Змінені
|
||||
- `services/city-service/repo_city.py` — додані функції update_agent_prompt, get_agent_prompt_history
|
||||
|
||||
### Створені
|
||||
- `migrations/034_agent_prompts_seed.sql` — детальні промти для ключових агентів
|
||||
- `docs/tasks/TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v1.md` — цей документ
|
||||
|
||||
### Вже існували (без змін)
|
||||
- `migrations/016_agent_prompts.sql` — схема таблиці
|
||||
- `services/city-service/routes_city.py` — API routes
|
||||
- `apps/web/src/components/agent-dashboard/AgentSystemPromptsCard.tsx` — UI компонент
|
||||
- `apps/web/src/lib/agent-dashboard.ts` — API клієнт
|
||||
- `apps/web/src/app/api/agents/[agentId]/prompts/[kind]/route.ts` — Next.js proxy
|
||||
|
||||
---
|
||||
|
||||
## Тестування
|
||||
|
||||
### Backend (curl)
|
||||
```bash
|
||||
# Отримати dashboard з промтами
|
||||
curl http://localhost:7001/city/agents/AGENT_ID/dashboard | jq '.system_prompts'
|
||||
|
||||
# Оновити промт
|
||||
curl -X PUT http://localhost:7001/city/agents/AGENT_ID/prompts/core \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"content": "Test prompt", "note": "Test update"}'
|
||||
|
||||
# Отримати історію
|
||||
curl http://localhost:7001/city/agents/AGENT_ID/prompts/core/history
|
||||
```
|
||||
|
||||
### Frontend
|
||||
1. Відкрити http://localhost:8899/agents
|
||||
2. Вибрати агента (DAARWIZZ, DARIA, тощо)
|
||||
3. Перейти на вкладку "System Prompts"
|
||||
4. Перевірити що відображаються seed-промти
|
||||
5. Змінити текст та натиснути "Save"
|
||||
6. Перезавантажити сторінку — зміни збережені
|
||||
|
||||
---
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Дата:** 2025-11-30
|
||||
**Автор:** DAARION AI Team
|
||||
|
||||
157
docs/tasks/TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v2.md
Normal file
157
docs/tasks/TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v2.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# TASK_PHASE_AGENT_SYSTEM_PROMPTS_MVP_v2
|
||||
|
||||
## Проєкт
|
||||
microdao-daarion (MVP DAARION.city)
|
||||
|
||||
## Фаза
|
||||
Agent System Prompts — Coverage + Runtime Integration
|
||||
|
||||
## Статус
|
||||
✅ **COMPLETED**
|
||||
|
||||
---
|
||||
|
||||
## Мета
|
||||
|
||||
1. Заповнити системні промти для всіх ключових агентів міста (City / District / Node)
|
||||
2. Підключити зберігання промтів у БД до реального DAGI Router runtime
|
||||
|
||||
---
|
||||
|
||||
## Результат
|
||||
|
||||
### 1. Повне покриття агентів (16 агентів)
|
||||
|
||||
#### City / Core
|
||||
- ✅ **DAARWIZZ** — core, safety, governance, tools
|
||||
- ✅ **MicroDAO Orchestrator** — core, safety
|
||||
- ✅ **DevTools Agent** — core, safety, tools
|
||||
|
||||
#### District / MicroDAO
|
||||
- ✅ **GREENFOOD** — core, safety, tools
|
||||
- ✅ **Helion** — core, safety, tools
|
||||
- ✅ **SOUL** — core, safety
|
||||
- ✅ **DRUID** — core, safety, tools
|
||||
- ✅ **NUTRA** — core, safety
|
||||
- ✅ **EONARCH** — core, safety
|
||||
- ✅ **CLAN** — core
|
||||
- ✅ **Yaromir** — core
|
||||
- ✅ **Monitor** — core, safety
|
||||
|
||||
#### Node Agents
|
||||
- ✅ **monitor-node1** (Node Guardian NODE1) — core, safety, governance
|
||||
- ✅ **monitor-node2** (Node Guardian NODE2) — core, safety
|
||||
- ✅ **node-steward-node1** — core
|
||||
- ✅ **node-steward-node2** — core
|
||||
|
||||
### 2. Runtime Integration
|
||||
|
||||
#### Нові API Endpoints
|
||||
|
||||
```
|
||||
GET /internal/agents/{agent_id}/prompts/runtime
|
||||
```
|
||||
Повертає промти для агента (тільки content, без метаданих).
|
||||
|
||||
```
|
||||
GET /internal/agents/{agent_id}/system-prompt
|
||||
```
|
||||
Повертає зібраний system prompt для LLM виклику.
|
||||
|
||||
```
|
||||
POST /internal/agents/prompts/status
|
||||
Body: { "agent_ids": ["agent-1", "agent-2"] }
|
||||
```
|
||||
Перевіряє наявність промтів для списку агентів.
|
||||
|
||||
#### DAGI Router Integration
|
||||
|
||||
Створено `services/router/prompt_builder.py`:
|
||||
- `PromptBuilder` клас для побудови system prompts
|
||||
- Пріоритети: БД → router-config → fallback
|
||||
- Автоматичне завантаження контексту (node, district)
|
||||
- `get_agent_system_prompt()` convenience function
|
||||
|
||||
Оновлено `/v1/agents/{agent_id}/infer`:
|
||||
- Автоматично завантажує system prompt з БД
|
||||
- Fallback на router-config.yml
|
||||
- Логування джерела промту
|
||||
|
||||
### 3. UI Індикатори
|
||||
|
||||
#### DAGIRouterCard
|
||||
- 🧠 іконка біля імені агента якщо `has_prompts = true`
|
||||
- Напівпрозора іконка якщо агент active але без промтів
|
||||
- Tooltip з інформацією про статус
|
||||
|
||||
### 4. Файли
|
||||
|
||||
#### Міграції
|
||||
- `migrations/038_agent_prompts_full_coverage.sql` — повний seed
|
||||
|
||||
#### Backend
|
||||
- `services/city-service/repo_city.py`:
|
||||
- `get_runtime_prompts(agent_id)`
|
||||
- `build_system_prompt(agent, prompts, context)`
|
||||
- `get_agent_with_runtime_prompt(agent_id)`
|
||||
- `check_agents_prompts_status(agent_ids)`
|
||||
|
||||
- `services/city-service/routes_city.py`:
|
||||
- Нові endpoints для runtime prompts
|
||||
- `DAGIRouterAgentItem.has_prompts` поле
|
||||
|
||||
#### Router
|
||||
- `services/router/prompt_builder.py` — новий модуль
|
||||
- `services/router/main.py` — інтеграція з prompt_builder
|
||||
|
||||
#### Frontend
|
||||
- `apps/web/src/hooks/useDAGIAudit.ts` — `has_prompts` в типах
|
||||
- `apps/web/src/components/node-dashboard/DAGIRouterCard.tsx` — UI індикатор
|
||||
|
||||
#### Тести
|
||||
- `tests/test_agent_prompts_runtime.py`
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
| Критерій | Статус |
|
||||
|----------|--------|
|
||||
| Всі агенти з Target Coverage мають core prompt | ✅ |
|
||||
| DAGI Router завантажує промти з БД | ✅ |
|
||||
| Fallback на config якщо БД порожня | ✅ |
|
||||
| UI показує індикатор has_prompts | ✅ |
|
||||
| API для batch перевірки статусу | ✅ |
|
||||
| Unit тести | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Як застосувати
|
||||
|
||||
```bash
|
||||
# 1. Застосувати міграцію
|
||||
docker exec -i dagi-postgres psql -U postgres -d daarion < migrations/038_agent_prompts_full_coverage.sql
|
||||
|
||||
# 2. Перезапустити city-service
|
||||
docker-compose restart daarion-city-service
|
||||
|
||||
# 3. Перезапустити router (опційно)
|
||||
docker-compose restart daarion-router
|
||||
|
||||
# 4. Зібрати frontend
|
||||
cd apps/web && npm run build
|
||||
|
||||
# 5. Запустити тести
|
||||
pytest tests/test_agent_prompts_runtime.py -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Наступні кроки (v3)
|
||||
|
||||
1. **Версіонування промтів** — історія змін з rollback
|
||||
2. **A/B testing** — різні версії промтів для тестування
|
||||
3. **Template system** — шаблони з variables
|
||||
4. **Metrics** — трекінг ефективності промтів
|
||||
5. **UI Editor** — advanced editor з preview
|
||||
|
||||
296
docs/tasks/TASK_PHASE_DAGI_AGENT_AUDIT_MVP_v1.md
Normal file
296
docs/tasks/TASK_PHASE_DAGI_AGENT_AUDIT_MVP_v1.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# TASK_PHASE_DAGI_AGENT_AUDIT_MVP_v1
|
||||
|
||||
Проєкт: DAARION.city — DAGI Router / Node Cabinet
|
||||
Фаза: DAGI Agent Audit & Activity Monitor
|
||||
Мета: гарантувати, що всі агенти, оголошені DAGI Router на кожній Ноді (NODA1, NODA2), коректно синхронізовані з системою microdao та відображаються у Кабінеті Ноди з правильним індикатором активності.
|
||||
|
||||
---
|
||||
|
||||
# 0. Problem Statement
|
||||
|
||||
У процесі розробки та деплою деякі агенти на НОДА з'являлись/зникали.
|
||||
Не було механізму перевірки їх присутності та активності у DAGI Router та їх відповідності записам у системі (microdao → agents).
|
||||
|
||||
Потрібно створити:
|
||||
- одноразовий аудит DAGI-агентів на кожній ноді;
|
||||
- постійний автоматизований моніторинг активності агентів;
|
||||
- індикатор «підключено/активний» замість терміну «зареєстрований у MVP»;
|
||||
- UI-відображення в Кабінеті Ноди;
|
||||
- метрики й сигналізація (NATS + Prometheus).
|
||||
|
||||
---
|
||||
|
||||
# 1. Scope
|
||||
|
||||
## Включено
|
||||
|
||||
- Аудит DAGI Router агентів на NODA1 та NODA2.
|
||||
- Зіставлення: `router_agents` ↔ `system_agents` (таблиця microdao.agents).
|
||||
- Додавання індикатора активності агента.
|
||||
- Одноразовий звіт diff у JSON.
|
||||
- Автоматичний воркер для періодичної перевірки.
|
||||
- Метрики Prometheus.
|
||||
- Події NATS.
|
||||
- UI (Node Cabinet → вкладка "DAGI Router").
|
||||
|
||||
## Виключено
|
||||
|
||||
- Вплив на логіку DAGI Router.
|
||||
- Автоматичне видалення агентів.
|
||||
- Версіонування агентів.
|
||||
|
||||
---
|
||||
|
||||
# 2. Definitions
|
||||
|
||||
- **Router Agents** — агенти, які DAGI Router бачить на конкретній ноді (`GET /api/agents` або NATS `dagi.router.agent.list`).
|
||||
- **System Agents** — агенти, зареєстровані в системі (таблиця `agents` у microdao).
|
||||
- **Node Agent Auditor** — спеціальний агент Ноди, який періодично перевіряє відповідність.
|
||||
- **Active** — агент з'являється в DAGI Router і відповідає на healthcheck.
|
||||
- **Stale** — агент є в системі, але його немає в DAGI Router.
|
||||
- **Phantom** — агент є в DAGI Router, але його немає в системі.
|
||||
|
||||
---
|
||||
|
||||
# 3. One-time Audit (Node1 + Node2)
|
||||
|
||||
## 3.1. Команда
|
||||
|
||||
Створити CLI/скрипт:
|
||||
|
||||
```bash
|
||||
scripts/dagi_agent_audit.py --node node1
|
||||
scripts/dagi_agent_audit.py --node node2
|
||||
```
|
||||
|
||||
## 3.2. Дії
|
||||
|
||||
1. Отримати список агентів з DAGI Router:
|
||||
```
|
||||
GET {ROUTER_URL}/api/agents
|
||||
```
|
||||
|
||||
2. Отримати список агентів з microdao:
|
||||
```sql
|
||||
SELECT id, name, role, node_id FROM agents WHERE node_id = :node
|
||||
```
|
||||
|
||||
3. Обчислити:
|
||||
```python
|
||||
missing_in_system = router_ids - system_ids
|
||||
stale_in_router = system_ids - router_ids
|
||||
active = intersection(router_ids, system_ids)
|
||||
```
|
||||
|
||||
4. Згенерувати звіт:
|
||||
```
|
||||
logs/dagi-audit-node{1,2}.json
|
||||
```
|
||||
|
||||
## 3.3. Структура JSON-звіту
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "node1",
|
||||
"router_total": 15,
|
||||
"system_total": 14,
|
||||
"active": ["agent_x", "agent_y"],
|
||||
"missing_in_system": ["agent_z"],
|
||||
"stale_in_router": ["agent_a"],
|
||||
"timestamp": "..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# 4. DB / System Changes
|
||||
|
||||
## 4.1. Таблиця agents (розширення)
|
||||
|
||||
Додати поля:
|
||||
- `node_id text` — ідентифікатор ноди.
|
||||
- `status text check(status in ('active','stale','missing','error'))` — стан.
|
||||
- `last_seen_at timestamptz` — останній час успішного контакту.
|
||||
|
||||
Міграція:
|
||||
```sql
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS node_id text;
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS status text DEFAULT 'stale';
|
||||
ALTER TABLE agents ADD COLUMN IF NOT EXISTS last_seen_at timestamptz;
|
||||
```
|
||||
|
||||
## 4.2. Repo-методи
|
||||
|
||||
- `repo_agents.update_status(agent_id, status, last_seen_at)`
|
||||
- `repo_agents.list_by_node(node_id)`
|
||||
- `repo_agents.sync_router_list(node_id, router_agents)` — optional
|
||||
|
||||
---
|
||||
|
||||
# 5. Automated Worker: Node Agent Auditor
|
||||
|
||||
Створити сервіс:
|
||||
`services/node-agent-auditor/worker.py`
|
||||
|
||||
## 5.1. Частота
|
||||
|
||||
- кожні 60 секунд (конфігуровано).
|
||||
|
||||
## 5.2. Алгоритм
|
||||
|
||||
```python
|
||||
router_agents = get_router_list(node)
|
||||
system_agents = get_system_list(node)
|
||||
|
||||
active = intersection(router_agents, system_agents)
|
||||
missing = router_agents - system_agents
|
||||
stale = system_agents - router_agents
|
||||
|
||||
update agents.status
|
||||
update agents.last_seen_at
|
||||
publish NATS events
|
||||
expose Prometheus metrics
|
||||
```
|
||||
|
||||
## 5.3. NATS події
|
||||
|
||||
- `node.agent.audit.active`
|
||||
- `node.agent.audit.missing`
|
||||
- `node.agent.audit.stale`
|
||||
- `node.agent.audit.error`
|
||||
|
||||
Payload:
|
||||
```json
|
||||
{
|
||||
"node_id": "node1",
|
||||
"agent_id": "daria",
|
||||
"status": "missing",
|
||||
"timestamp": "..."
|
||||
}
|
||||
```
|
||||
|
||||
## 5.4. Prometheus метрики
|
||||
|
||||
- `dagi_agents_active{node="node1"}`
|
||||
- `dagi_agents_missing{node="node1"}`
|
||||
- `dagi_agents_stale{node="node1"}`
|
||||
- `dagi_agent_last_seen_timestamp{agent="daria",node="node1"}`
|
||||
|
||||
---
|
||||
|
||||
# 6. Node Cabinet UI
|
||||
|
||||
## 6.1. Нова вкладка
|
||||
|
||||
```
|
||||
/node/{nodeId}/dagi-router
|
||||
```
|
||||
|
||||
## 6.2. Таблиця
|
||||
|
||||
Колонки:
|
||||
- Agent ID
|
||||
- Name
|
||||
- Role
|
||||
- Status (`active`, `missing`, `stale`, `error`)
|
||||
- Last Seen (`timestamp`)
|
||||
- Node
|
||||
|
||||
## 6.3. Індикатор статусу
|
||||
|
||||
- 🟢 Зелене коло — active
|
||||
- 🟡 Жовте — stale
|
||||
- 🔴 Червоне — missing
|
||||
- ⚫ Сіре — error
|
||||
|
||||
## 6.4. Елементи управління
|
||||
|
||||
- `Resync` → тригерить ручний аудит (POST `/internal/node/{id}/audit`).
|
||||
|
||||
---
|
||||
|
||||
# 7. API
|
||||
|
||||
## 7.1. GET
|
||||
|
||||
- `GET /internal/node/{node_id}/agents/router` → список DAGI Router агентів
|
||||
- `GET /internal/node/{node_id}/agents/system` → список system agent records
|
||||
- `GET /internal/node/{node_id}/audit` → останній аудит
|
||||
|
||||
## 7.2. POST
|
||||
|
||||
- `POST /internal/node/{node_id}/audit` → виконати аудит вручну
|
||||
- `POST /internal/node/{node_id}/sync` → синхронізувати статуси (опційно)
|
||||
|
||||
---
|
||||
|
||||
# 8. Tests
|
||||
|
||||
## 8.1. Unit
|
||||
|
||||
- зіставлення router/system списків
|
||||
- статуси: active/missing/stale/error
|
||||
|
||||
## 8.2. Integration
|
||||
|
||||
- worker → DB update
|
||||
- worker → NATS event
|
||||
- worker → Prometheus export
|
||||
|
||||
## 8.3. E2E
|
||||
|
||||
- запуск аудиту
|
||||
- відображення у Node Cabinet UI
|
||||
- Resync працює
|
||||
|
||||
---
|
||||
|
||||
# 9. Acceptance Criteria
|
||||
|
||||
- На NODA1 і NODA2 виконано успішний одноразовий аудит.
|
||||
- JSON-звіти створені.
|
||||
- Worker працює і оновлює статуси агентів у БД.
|
||||
- Статуси в UI відповідають реальному стану Router.
|
||||
- NATS і Prometheus показують коректні дані.
|
||||
- Resync викликає миттєве оновлення.
|
||||
|
||||
---
|
||||
|
||||
# 10. Deliverables
|
||||
|
||||
- `scripts/dagi_agent_audit.py`
|
||||
- `services/node-agent-auditor/worker.py`
|
||||
- Міграція agents.status/last_seen_at/node_id
|
||||
- API (internal)
|
||||
- Node Cabinet UI вкладка
|
||||
- Документація цього таску
|
||||
|
||||
---
|
||||
|
||||
# 11. Implementation Plan
|
||||
|
||||
## M0 — Одноразовий аудит (Day 1)
|
||||
1. Створити `scripts/dagi_agent_audit.py`
|
||||
2. Тест на NODA1 та NODA2
|
||||
3. Звіти в `logs/`
|
||||
|
||||
## M1 — DB + Repo (Day 1-2)
|
||||
1. Міграція для нових полів
|
||||
2. Repo-методи в city-service
|
||||
|
||||
## M2 — Worker (Day 2-3)
|
||||
1. Node Agent Auditor сервіс
|
||||
2. NATS integration
|
||||
3. Prometheus metrics
|
||||
|
||||
## M3 — UI (Day 3-4)
|
||||
1. Node Cabinet вкладка "DAGI Router"
|
||||
2. Таблиця агентів зі статусами
|
||||
3. Resync button
|
||||
|
||||
---
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Дата:** 2025-11-30
|
||||
**Статус:** READY FOR IMPLEMENTATION
|
||||
|
||||
179
docs/tasks/TASK_PHASE_DAGI_AGENT_AUTOSYNC_AND_METRICS_v1.md
Normal file
179
docs/tasks/TASK_PHASE_DAGI_AGENT_AUTOSYNC_AND_METRICS_v1.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# TASK_PHASE_DAGI_AGENT_AUTOSYNC_AND_METRICS_v1
|
||||
|
||||
## Проєкт
|
||||
DAARION.city — Node Cabinet / DAGI Router
|
||||
|
||||
## Мета
|
||||
Створити стабільний, ергономічний та самовідновлюваний кабінет Ноди, де:
|
||||
- DAGI-агенти кожної ноди відображаються в таблиці на вкладці "DAGI Router"
|
||||
- Статуси агентів (Active / Phantom / Stale / Error) автоматично синхронізуються
|
||||
- GPU/CPU/RAM/Disks та кількість агентів стабільно відображаються
|
||||
- Є набір API тестів для захисту від регресій
|
||||
|
||||
---
|
||||
|
||||
## Зроблено
|
||||
|
||||
### 1. Database Migration (036)
|
||||
**Файл:** `migrations/036_node_metrics_extended.sql`
|
||||
|
||||
Розширено `node_cache` полями:
|
||||
- CPU: `cpu_model`, `cpu_cores`, `cpu_usage`
|
||||
- GPU: `gpu_model`, `gpu_vram_total`, `gpu_vram_used`
|
||||
- RAM: `ram_total`, `ram_used`
|
||||
- Disk: `disk_total`, `disk_used`
|
||||
- Agents: `agent_count_router`, `agent_count_system`
|
||||
- Heartbeat: `last_heartbeat`, `dagi_router_url`
|
||||
|
||||
Початкові дані для NODE1 (Hetzner) та NODE2 (MacBook M4 Max).
|
||||
|
||||
### 2. Backend API Endpoints
|
||||
|
||||
**Файли:**
|
||||
- `services/city-service/repo_city.py` — repo методи
|
||||
- `services/city-service/routes_city.py` — FastAPI endpoints
|
||||
|
||||
#### Нові endpoints:
|
||||
|
||||
| Endpoint | Метод | Опис |
|
||||
|----------|-------|------|
|
||||
| `/internal/node/{node_id}/dagi-router/agents` | GET | Таблиця агентів для Node Cabinet |
|
||||
| `/internal/node/{node_id}/metrics/current` | GET | Метрики ноди (GPU/CPU/RAM/Disk) |
|
||||
| `/internal/node/{node_id}/metrics/update` | POST | Оновлення метрик (heartbeat) |
|
||||
| `/internal/node/{node_id}/dagi-router/phantom/sync` | POST | Синхронізація phantom агентів |
|
||||
| `/internal/node/{node_id}/dagi-router/stale/mark` | POST | Позначення stale агентів |
|
||||
|
||||
#### Response structures:
|
||||
|
||||
**GET /dagi-router/agents:**
|
||||
```json
|
||||
{
|
||||
"node_id": "node-2-macbook-m4max",
|
||||
"last_audit_at": "2025-11-30T14:35:00Z",
|
||||
"summary": {
|
||||
"active": 12,
|
||||
"phantom": 2,
|
||||
"stale": 5,
|
||||
"router_total": 14,
|
||||
"system_total": 17
|
||||
},
|
||||
"agents": [
|
||||
{
|
||||
"id": "daria",
|
||||
"name": "DARIA",
|
||||
"role": "city_guide",
|
||||
"status": "active",
|
||||
"node_id": "node-2-macbook-m4max",
|
||||
"models": [],
|
||||
"gpu": "Apple M4 Max GPU",
|
||||
"cpu": "16 cores",
|
||||
"last_seen_at": "2025-11-30T14:34:50Z",
|
||||
"has_cabinet": true,
|
||||
"cabinet_slug": "daria"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**GET /metrics/current:**
|
||||
```json
|
||||
{
|
||||
"node_id": "node-2-macbook-m4max",
|
||||
"node_name": "MacBook Pro M4 Max",
|
||||
"cpu_model": "Apple M4 Max",
|
||||
"cpu_cores": 16,
|
||||
"cpu_usage": 35.5,
|
||||
"gpu_model": "Apple M4 Max GPU",
|
||||
"gpu_memory_total": 40960,
|
||||
"gpu_memory_used": 28000,
|
||||
"ram_total": 65536,
|
||||
"ram_used": 40000,
|
||||
"disk_total": 1024000,
|
||||
"disk_used": 400000,
|
||||
"agent_count_router": 14,
|
||||
"agent_count_system": 17,
|
||||
"last_heartbeat": "2025-11-30T05:14:59Z"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Frontend Components
|
||||
|
||||
**Нові/оновлені файли:**
|
||||
- `apps/web/src/hooks/useDAGIAudit.ts` — хуки для API
|
||||
- `apps/web/src/components/node-dashboard/DAGIRouterCard.tsx` — таблиця агентів
|
||||
- `apps/web/src/components/node-dashboard/NodeMetricsCard.tsx` — метрики ноди
|
||||
- `apps/web/src/app/nodes/[nodeId]/page.tsx` — інтеграція в Node Cabinet
|
||||
|
||||
#### DAGIRouterCard Features:
|
||||
- Таблиця агентів з колонками: Agent, Status, Runtime, Last Seen, Cabinet
|
||||
- Фільтр по статусу (All / Active / Phantom / Stale)
|
||||
- Пошук по імені агента
|
||||
- Кнопка "Запустити аудит"
|
||||
- Кнопка "Sync" для phantom агентів
|
||||
- Лічильники Active/Phantom/Stale
|
||||
|
||||
#### NodeMetricsCard Features:
|
||||
- Progress bars для GPU/CPU/RAM/Disk
|
||||
- Показує модель GPU/CPU
|
||||
- Agent counts (Router / System)
|
||||
- Last heartbeat timestamp
|
||||
|
||||
### 4. API Tests
|
||||
|
||||
**Файл:** `tests/test_dagi_router_api.py`
|
||||
|
||||
Тести для:
|
||||
- `TestDAGIRouterAgents` — GET agents endpoint
|
||||
- `TestNodeMetrics` — GET metrics endpoint
|
||||
- `TestDAGIAudit` — POST audit endpoint
|
||||
- `TestPhantomStaleSync` — sync endpoints
|
||||
- `TestIntegration` — повний цикл
|
||||
|
||||
---
|
||||
|
||||
## Застосування на сервері
|
||||
|
||||
```bash
|
||||
# 1. Застосувати міграцію
|
||||
docker exec -i dagi-postgres psql -U postgres -d daarion < migrations/036_node_metrics_extended.sql
|
||||
|
||||
# 2. Перезапустити city-service
|
||||
docker-compose restart daarion-city-service
|
||||
|
||||
# 3. Зібрати frontend
|
||||
cd apps/web && npm run build
|
||||
|
||||
# 4. Запустити тести
|
||||
cd /opt/microdao-daarion
|
||||
pytest tests/test_dagi_router_api.py -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [x] API `/dagi-router/agents` повертає уніфіковану таблицю агентів
|
||||
- [x] API `/metrics/current` повертає метрики ноди
|
||||
- [x] Node Cabinet показує NodeMetricsCard з GPU/CPU/RAM/Disk
|
||||
- [x] Node Cabinet показує DAGIRouterCard з таблицею агентів
|
||||
- [x] Phantom агенти можна синхронізувати через UI
|
||||
- [x] Stale агенти відображаються окремо
|
||||
- [x] API тести покривають основні сценарії
|
||||
- [x] Обидві ноди (NODE1, NODE2) працюють однаково
|
||||
|
||||
---
|
||||
|
||||
## Залежності
|
||||
|
||||
- Migration 035 (`agent_prompts_seed.sql`)
|
||||
- Migration 022 (`node_cache` table)
|
||||
- Migration 030 (`guardian_agent_id`, `steward_agent_id`)
|
||||
|
||||
---
|
||||
|
||||
## Наступні кроки
|
||||
|
||||
1. Інтегрувати heartbeat agent на нодах для оновлення метрик
|
||||
2. Додати Grafana dashboard для візуалізації метрик
|
||||
3. Реалізувати автоматичний periodic audit (cron job)
|
||||
|
||||
214
docs/tasks/TASK_PHASE_INFRA_INVARIANTS_AND_DEPLOY_CHECKS_v1.md
Normal file
214
docs/tasks/TASK_PHASE_INFRA_INVARIANTS_AND_DEPLOY_CHECKS_v1.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# TASK_PHASE_INFRA_INVARIANTS_AND_DEPLOY_CHECKS_v1
|
||||
|
||||
## Проєкт
|
||||
DAARION.city — Infra / Deploy / DAGI / microdao
|
||||
|
||||
## Фаза
|
||||
Інваріанти інфраструктури + автоматичні перевірки після деплою
|
||||
|
||||
## Статус
|
||||
✅ **COMPLETED**
|
||||
|
||||
---
|
||||
|
||||
## Мета
|
||||
|
||||
Зробити деплой детермінованим і безпечним так, щоб базова логіка **Нода → DAGI Router → Агенти → microdao → System Prompts** не ламалася після оновлень.
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
### Симптоми
|
||||
- Після оновлень/деплоїв періодично:
|
||||
- зникають агенти у Кабінеті Ноди (0 agents total)
|
||||
- ламаються кабінети агентів (`404`, відсутні `public_slug`)
|
||||
- зникають метрики GPU/CPU/RAM/Disk
|
||||
- DAGI Router / microdao втрачають частину зв'язків
|
||||
|
||||
### Причина
|
||||
- Немає **формально зафіксованих інваріантів**, які перевіряються автоматично після кожного деплою
|
||||
- Деплой проходить навіть тоді, коли стан системи неконсистентний
|
||||
|
||||
---
|
||||
|
||||
## Рішення
|
||||
|
||||
### 1. Інваріанти зафіксовані в коді
|
||||
|
||||
Файл: `scripts/check-invariants.py`
|
||||
|
||||
#### Node Invariants
|
||||
| Node | Інваріант | Severity |
|
||||
|------|-----------|----------|
|
||||
| NODE1, NODE2 | Існує в `node_cache` | CRITICAL |
|
||||
| NODE1, NODE2 | `agent_count_router >= 1` | CRITICAL |
|
||||
| NODE1, NODE2 | `agent_count_system >= 1` | CRITICAL |
|
||||
| NODE1 | GPU configured | WARNING |
|
||||
| NODE1, NODE2 | Heartbeat < 10 min | WARNING |
|
||||
|
||||
#### Node Agents Invariants
|
||||
| Інваріант | Severity |
|
||||
|-----------|----------|
|
||||
| Node Guardian exists | CRITICAL |
|
||||
| Node Steward exists | CRITICAL |
|
||||
| Total agents >= 1 | CRITICAL |
|
||||
|
||||
#### DAGI Router Invariants
|
||||
| Інваріант | Severity |
|
||||
|-----------|----------|
|
||||
| `router_total >= 1` | WARNING |
|
||||
| `phantom_count <= 20` | WARNING |
|
||||
| `stale_count <= 20` | WARNING |
|
||||
|
||||
#### Core Agents Invariants
|
||||
| Agent | Required | Severity |
|
||||
|-------|----------|----------|
|
||||
| DAARWIZZ | core prompt | WARNING |
|
||||
| MicroDAO Orchestrator | core prompt | WARNING |
|
||||
| DevTools | core prompt | WARNING |
|
||||
| SOUL | core prompt | WARNING |
|
||||
| GREENFOOD | core prompt | WARNING |
|
||||
| Helion | core prompt | WARNING |
|
||||
| DRUID | core prompt | WARNING |
|
||||
| NUTRA | core prompt | WARNING |
|
||||
| Monitor | core prompt | WARNING |
|
||||
|
||||
### 2. Скрипт перевірки
|
||||
|
||||
```bash
|
||||
# Запуск перевірки
|
||||
python scripts/check-invariants.py --base-url http://localhost:7001
|
||||
|
||||
# Перевірка тільки NODE1
|
||||
python scripts/check-invariants.py --node node-1-hetzner-gex44
|
||||
|
||||
# JSON output
|
||||
python scripts/check-invariants.py --json
|
||||
```
|
||||
|
||||
#### Exit codes
|
||||
- `0` — всі критичні інваріанти пройшли
|
||||
- `1` — є критичні помилки
|
||||
|
||||
### 3. Smoke Tests
|
||||
|
||||
Файл: `tests/test_infra_smoke.py`
|
||||
|
||||
```bash
|
||||
# Запуск тестів
|
||||
pytest tests/test_infra_smoke.py -v
|
||||
|
||||
# З custom URL
|
||||
pytest tests/test_infra_smoke.py -v --base-url http://localhost:7001
|
||||
```
|
||||
|
||||
#### Тести
|
||||
- `TestHealthChecks` — `/healthz`, `/public/nodes`
|
||||
- `TestNodeMetrics` — метрики нод, agent counts
|
||||
- `TestNodeAgents` — Guardian, Steward
|
||||
- `TestDAGIRouter` — DAGI agents, summary
|
||||
- `TestCoreAgents` — prompts status, runtime prompts
|
||||
- `TestIntegration` — end-to-end flows
|
||||
|
||||
### 4. Інтеграція в Deploy
|
||||
|
||||
Файл: `scripts/deploy-prod.sh`
|
||||
|
||||
```bash
|
||||
# Деплой з автоматичною перевіркою інваріантів
|
||||
./scripts/deploy-prod.sh
|
||||
|
||||
# Деплой зі smoke тестами
|
||||
RUN_SMOKE_TESTS=true ./scripts/deploy-prod.sh
|
||||
```
|
||||
|
||||
#### Pipeline
|
||||
1. Pre-flight checks (Docker, .env, compose files)
|
||||
2. Database backup
|
||||
3. Pull/build images
|
||||
4. Start core services
|
||||
5. Run migrations
|
||||
6. Start all services
|
||||
7. Basic health checks
|
||||
8. **Infrastructure invariants check** ← NEW
|
||||
9. (Optional) Smoke tests
|
||||
10. Success/failure report
|
||||
|
||||
---
|
||||
|
||||
## Файли
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `scripts/check-invariants.py` | CLI для перевірки інваріантів |
|
||||
| `tests/test_infra_smoke.py` | Pytest smoke тести |
|
||||
| `scripts/deploy-prod.sh` | Оновлений deploy script |
|
||||
|
||||
---
|
||||
|
||||
## Використання
|
||||
|
||||
### Щоденна розробка
|
||||
|
||||
```bash
|
||||
# Перевірити інваріанти вручну
|
||||
python scripts/check-invariants.py --base-url http://localhost:7001
|
||||
|
||||
# Запустити smoke тести
|
||||
pytest tests/test_infra_smoke.py -v
|
||||
```
|
||||
|
||||
### Production Deploy
|
||||
|
||||
```bash
|
||||
# Повний деплой з інваріантами
|
||||
./scripts/deploy-prod.sh
|
||||
|
||||
# Якщо інваріанти не пройшли:
|
||||
# 1. Перевірити міграції
|
||||
psql -h localhost -U postgres -d daarion < migrations/037_node_agents_complete.sql
|
||||
psql -h localhost -U postgres -d daarion < migrations/038_agent_prompts_full_coverage.sql
|
||||
|
||||
# 2. Перезапустити перевірку
|
||||
python scripts/check-invariants.py
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Deploy
|
||||
run: ./scripts/deploy-prod.sh
|
||||
|
||||
- name: Check Invariants
|
||||
run: python scripts/check-invariants.py --base-url ${{ secrets.CITY_SERVICE_URL }}
|
||||
|
||||
- name: Run Smoke Tests
|
||||
run: pytest tests/test_infra_smoke.py -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
| Критерій | Статус |
|
||||
|----------|--------|
|
||||
| `scripts/check-invariants.py` існує і працює | ✅ |
|
||||
| Перевіряє NODE1 та NODE2 | ✅ |
|
||||
| Перевіряє Node Guardian/Steward | ✅ |
|
||||
| Перевіряє DAGI Router | ✅ |
|
||||
| Перевіряє core agents prompts | ✅ |
|
||||
| Exit code 1 при критичних помилках | ✅ |
|
||||
| Інтегровано в deploy-prod.sh | ✅ |
|
||||
| Smoke тести в pytest | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Наступні кроки
|
||||
|
||||
1. **Prometheus metrics** для інваріантів
|
||||
2. **Alerting** при порушенні інваріантів
|
||||
3. **GitHub Actions** CI/CD pipeline
|
||||
4. **Rollback automation** при failed invariants
|
||||
|
||||
142
docs/tasks/TASK_PHASE_NODE_AGENT_CABINETS_INTEGRATION_v1.md
Normal file
142
docs/tasks/TASK_PHASE_NODE_AGENT_CABINETS_INTEGRATION_v1.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# TASK_PHASE_NODE_AGENT_CABINETS_INTEGRATION_v1
|
||||
|
||||
## Проєкт
|
||||
DAARION.city — Node Cabinet / Agents / DAGI Router
|
||||
|
||||
## Мета
|
||||
Зробити єдиний, послідовний шар відображення агентів ноди:
|
||||
- DAGI Router → показує фактичних агентів ноди
|
||||
- Кабінет Ноди → показує тих самих агентів у секціях "Node Guardian & Steward"
|
||||
- Кабінет Агента (`/agents/:slug`) + System Prompts працюють для всіх активних агентів
|
||||
|
||||
---
|
||||
|
||||
## Виконано
|
||||
|
||||
### 1. Database Migration (037)
|
||||
**Файл:** `migrations/037_node_agents_complete.sql`
|
||||
|
||||
Створено/оновлено:
|
||||
- **Node Guardian** агентів для NODE1 та NODE2
|
||||
- **Node Steward** агентів для NODE1 та NODE2
|
||||
- Прив'язки `guardian_agent_id` та `steward_agent_id` в `node_cache`
|
||||
- **System Prompts** для всіх Node Agents
|
||||
- Синхронізація ключових агентів з `router-config.yml`
|
||||
|
||||
### 2. Backend API
|
||||
|
||||
**Новий endpoint:**
|
||||
`GET /internal/node/{node_id}/agents`
|
||||
|
||||
```json
|
||||
{
|
||||
"node_id": "node-2-macbook-m4max",
|
||||
"total": 4,
|
||||
"guardian": {
|
||||
"id": "monitor-node2",
|
||||
"name": "Node Guardian (НОДА2)",
|
||||
"slug": "monitor-node2",
|
||||
"kind": "node_guardian",
|
||||
"status": "online",
|
||||
"is_guardian": true
|
||||
},
|
||||
"steward": {
|
||||
"id": "node-steward-node2",
|
||||
"name": "Node Steward (НОДА2)",
|
||||
"slug": "node-steward-node2",
|
||||
"kind": "node_steward",
|
||||
"status": "online",
|
||||
"is_steward": true
|
||||
},
|
||||
"agents": [...]
|
||||
}
|
||||
```
|
||||
|
||||
**Оновлення:**
|
||||
- `repo_city.get_agent_by_id()` — тепер шукає по `id` АБО `public_slug`
|
||||
- `repo_city.get_node_agents()` — новий метод для отримання агентів ноди
|
||||
|
||||
### 3. Frontend
|
||||
|
||||
**Оновлені файли:**
|
||||
- `apps/web/src/hooks/useDAGIAudit.ts` — додано `useNodeAgents` hook
|
||||
- `apps/web/src/app/nodes/[nodeId]/page.tsx` — інтеграція з useNodeAgents
|
||||
- `apps/web/src/components/nodes/NodeGuardianCard.tsx` — посилання на `/agents/{slug}`
|
||||
|
||||
**Зміни:**
|
||||
- NodeGuardianCard використовує `slug` для посилань замість `id`
|
||||
- Node Cabinet отримує Guardian/Steward через новий API
|
||||
- Fallback на nodeProfile якщо API не повернув дані
|
||||
|
||||
### 4. Node Agents Seed Data
|
||||
|
||||
| Agent | Node | Kind | Slug |
|
||||
|-------|------|------|------|
|
||||
| Node Guardian (НОДА1) | node-1-hetzner-gex44 | node_guardian | monitor-node1 |
|
||||
| Node Guardian (НОДА2) | node-2-macbook-m4max | node_guardian | monitor-node2 |
|
||||
| Node Steward (НОДА1) | node-1-hetzner-gex44 | node_steward | node-steward-node1 |
|
||||
| Node Steward (НОДА2) | node-2-macbook-m4max | node_steward | node-steward-node2 |
|
||||
|
||||
### 5. System Prompts для Node Agents
|
||||
|
||||
- **NODE1 Guardian** — core + safety prompts
|
||||
- **NODE2 Guardian** — core prompt
|
||||
- **NODE1 Steward** — core prompt
|
||||
- **NODE2 Steward** — core prompt
|
||||
|
||||
---
|
||||
|
||||
## Застосування на сервері
|
||||
|
||||
```bash
|
||||
# 1. Застосувати міграцію
|
||||
docker exec -i dagi-postgres psql -U postgres -d daarion < migrations/037_node_agents_complete.sql
|
||||
|
||||
# 2. Перезапустити city-service
|
||||
docker-compose restart daarion-city-service
|
||||
|
||||
# 3. Зібрати frontend
|
||||
cd apps/web && npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Перевірка
|
||||
|
||||
```bash
|
||||
# 1. Перевірити Node Agents API
|
||||
curl http://localhost:7001/city/internal/node/node-2-macbook-m4max/agents | jq
|
||||
|
||||
# 2. Перевірити що агенти мають public_slug
|
||||
psql -U postgres -d daarion -c "SELECT id, display_name, public_slug, kind FROM agents WHERE kind LIKE 'node_%'"
|
||||
|
||||
# 3. Перевірити agent dashboard API
|
||||
curl http://localhost:7001/city/agents/monitor-node2/dashboard | jq '.profile.display_name'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Результат
|
||||
|
||||
Після застосування:
|
||||
|
||||
1. **Node Cabinet** (`/nodes/[nodeId]`):
|
||||
- Секція "Node Guardian & Steward" показує реальних агентів
|
||||
- Кнопки "Кабінет" ведуть на робочі сторінки `/agents/[slug]`
|
||||
|
||||
2. **Agent Cabinet** (`/agents/[slug]`):
|
||||
- Працює для Node Guardian та Node Steward
|
||||
- System Prompts заповнені
|
||||
|
||||
3. **DAGI Router Card**:
|
||||
- Active агенти мають робочі посилання в Кабінет
|
||||
- Phantom агенти можна синхронізувати
|
||||
|
||||
---
|
||||
|
||||
## Залежності
|
||||
|
||||
- Migration 036 (node_metrics_extended)
|
||||
- Migration 035 (agent_dagi_audit)
|
||||
- Migration 030 (node_guardian_steward)
|
||||
|
||||
268
docs/tasks/TASK_PHASE_NODE_SELF_HEALING_v1.md
Normal file
268
docs/tasks/TASK_PHASE_NODE_SELF_HEALING_v1.md
Normal file
@@ -0,0 +1,268 @@
|
||||
# TASK_PHASE_NODE_SELF_HEALING_v1
|
||||
|
||||
## Проєкт
|
||||
DAARION.city — Nodes / Node Cabinet / DAGI Router
|
||||
|
||||
## Фаза
|
||||
Self-healing нод (автоматична реєстрація, відновлення та синхронізація)
|
||||
|
||||
## Статус
|
||||
✅ **COMPLETED**
|
||||
|
||||
---
|
||||
|
||||
## Мета
|
||||
|
||||
Зробити так, щоб:
|
||||
|
||||
1. Ноди **ніколи не "зникали"** з Node Directory, якщо фізично існують і шлють heartbeat
|
||||
2. Реєстрація/оновлення нод виконувалась **агентами ноди**, а не ручними діями
|
||||
3. Node Directory → Node Cabinet → Node Metrics → DAGI Router були повністю узгоджені
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
### Симптом
|
||||
- `/nodes` (Node Directory) показує:
|
||||
- «Знайдено нод: 0»
|
||||
- «Помилка завантаження нод»
|
||||
- Хоча:
|
||||
- насправді NODE1/NODE2 є в `node_cache`
|
||||
- метрики, DAGI Router, агенти ноди працюють
|
||||
|
||||
### Причини
|
||||
- Node Directory фронт дивився на іншу структуру даних
|
||||
- Реєстрація ноди не відпрацьовувала після деплою
|
||||
- Немає самовідновлюваної логіки на рівні нод
|
||||
|
||||
---
|
||||
|
||||
## Рішення
|
||||
|
||||
### 1. Node Registry — єдине джерело істини
|
||||
|
||||
**Таблиця:** `node_registry`
|
||||
|
||||
```sql
|
||||
CREATE TABLE node_registry (
|
||||
id text PRIMARY KEY, -- node_id
|
||||
name text NOT NULL, -- Людська назва
|
||||
hostname text, -- Hostname
|
||||
environment text NOT NULL, -- production/development/staging
|
||||
roles text[] NOT NULL DEFAULT '{}', -- ['gpu', 'ai_runtime', ...]
|
||||
description text,
|
||||
is_active boolean NOT NULL DEFAULT true,
|
||||
registered_at timestamptz NOT NULL DEFAULT now(),
|
||||
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||
last_self_registration timestamptz, -- Остання самореєстрація
|
||||
self_registration_count integer DEFAULT 0
|
||||
);
|
||||
```
|
||||
|
||||
**View для Node Directory:**
|
||||
|
||||
```sql
|
||||
CREATE VIEW v_nodes_directory AS
|
||||
SELECT
|
||||
r.*,
|
||||
c.cpu_model, c.gpu_model, c.ram_total, ...
|
||||
c.last_heartbeat,
|
||||
c.agent_count_router,
|
||||
c.agent_count_system,
|
||||
CASE
|
||||
WHEN c.last_heartbeat < NOW() - INTERVAL '10 minutes' THEN 'stale'
|
||||
ELSE 'online'
|
||||
END AS connection_status
|
||||
FROM node_registry r
|
||||
LEFT JOIN node_cache c ON c.node_id = r.id
|
||||
WHERE r.is_active = true;
|
||||
```
|
||||
|
||||
### 2. Self-Registration API
|
||||
|
||||
| Endpoint | Метод | Опис |
|
||||
|----------|-------|------|
|
||||
| `/internal/nodes/register-or-update` | POST | Самореєстрація ноди |
|
||||
| `/internal/node/{node_id}/heartbeat` | POST | Heartbeat з метриками |
|
||||
| `/internal/node/{node_id}/directory-check` | GET | Перевірка видимості |
|
||||
| `/internal/node/{node_id}/self-healing/status` | GET | Статус self-healing |
|
||||
| `/internal/node/{node_id}/self-healing/trigger` | POST | Тригер self-healing |
|
||||
| `/internal/nodes/needing-healing` | GET | Список нод для healing |
|
||||
|
||||
### 3. Node Bootstrap Script
|
||||
|
||||
**Файл:** `scripts/node-bootstrap.sh`
|
||||
|
||||
```bash
|
||||
# Використання при старті ноди
|
||||
NODE_ID=node-2-macbook-m4max \
|
||||
NODE_NAME="MacBook Pro M4 Max" \
|
||||
NODE_ENVIRONMENT=development \
|
||||
NODE_ROLES=gpu,ai_runtime,development \
|
||||
./scripts/node-bootstrap.sh
|
||||
```
|
||||
|
||||
**Що робить:**
|
||||
1. Відправляє POST на `/internal/nodes/register-or-update`
|
||||
2. При успіху — відправляє початковий heartbeat
|
||||
3. При помилці — retry до 5 разів
|
||||
|
||||
### 4. Node Guardian Self-Healing Loop
|
||||
|
||||
**Файл:** `scripts/node-guardian-loop.py`
|
||||
|
||||
```bash
|
||||
# Запуск як фоновий процес
|
||||
NODE_ID=node-2-macbook-m4max \
|
||||
NODE_NAME="NODE2" \
|
||||
python scripts/node-guardian-loop.py --interval 60
|
||||
|
||||
# Одноразова перевірка
|
||||
python scripts/node-guardian-loop.py --node-id node-2-macbook-m4max --once
|
||||
```
|
||||
|
||||
**Що перевіряє:**
|
||||
1. Чи нода видима в Node Directory
|
||||
2. Чи є heartbeat
|
||||
3. Чи є Guardian/Steward агенти
|
||||
4. Чи є агенти в router
|
||||
|
||||
**Self-healing дії:**
|
||||
1. Якщо не видима — виконує self-registration
|
||||
2. Якщо heartbeat старий — відправляє новий
|
||||
3. Якщо статус error — тригерить healing через API
|
||||
|
||||
---
|
||||
|
||||
## Файли
|
||||
|
||||
| Файл | Опис |
|
||||
|------|------|
|
||||
| `migrations/039_node_registry_self_healing.sql` | Міграція для node_registry |
|
||||
| `services/city-service/repo_city.py` | Функції для self-healing |
|
||||
| `services/city-service/routes_city.py` | API endpoints |
|
||||
| `scripts/node-bootstrap.sh` | Bootstrap скрипт |
|
||||
| `scripts/node-guardian-loop.py` | Self-healing loop |
|
||||
|
||||
---
|
||||
|
||||
## Інваріанти Self-Healing
|
||||
|
||||
| Умова | Дія |
|
||||
|-------|-----|
|
||||
| Нода не в node_registry | → self_register() |
|
||||
| heartbeat > 10 хв | → send_heartbeat() |
|
||||
| agent_count_router = 0 | → alert + try reinstall |
|
||||
| guardian_agent_id = NULL | → alert |
|
||||
| self_healing_status = error | → trigger_healing() |
|
||||
|
||||
---
|
||||
|
||||
## Використання
|
||||
|
||||
### При першому деплої ноди
|
||||
|
||||
```bash
|
||||
# 1. Запустити міграцію
|
||||
psql -d daarion < migrations/039_node_registry_self_healing.sql
|
||||
|
||||
# 2. Запустити bootstrap
|
||||
NODE_ID=node-2-macbook-m4max \
|
||||
NODE_NAME="MacBook Pro M4 Max" \
|
||||
NODE_ENVIRONMENT=development \
|
||||
./scripts/node-bootstrap.sh
|
||||
```
|
||||
|
||||
### Запуск Guardian Loop
|
||||
|
||||
```bash
|
||||
# Через systemd
|
||||
[Unit]
|
||||
Description=DAARION Node Guardian
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Environment=NODE_ID=node-2-macbook-m4max
|
||||
Environment=NODE_NAME=NODE2
|
||||
Environment=CITY_SERVICE_URL=http://localhost:7001
|
||||
ExecStart=/usr/bin/python3 /path/to/scripts/node-guardian-loop.py
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
### Через Docker Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
node-guardian:
|
||||
image: python:3.11-slim
|
||||
environment:
|
||||
- NODE_ID=node-2-macbook-m4max
|
||||
- NODE_NAME=NODE2
|
||||
- CITY_SERVICE_URL=http://city-service:7001
|
||||
command: python /app/scripts/node-guardian-loop.py
|
||||
volumes:
|
||||
- ./scripts:/app/scripts
|
||||
depends_on:
|
||||
- city-service
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Healing сценарії
|
||||
|
||||
### Сценарій 1: Нода зникла з Directory після деплою
|
||||
|
||||
```
|
||||
1. Node Guardian запускається
|
||||
2. check_visibility() → false
|
||||
3. self_register() → успіх
|
||||
4. check_visibility() → true
|
||||
5. ✅ Нода знову в Directory
|
||||
```
|
||||
|
||||
### Сценарій 2: Heartbeat застарів
|
||||
|
||||
```
|
||||
1. Node Guardian перевіряє статус
|
||||
2. self_healing_status = "stale_heartbeat"
|
||||
3. send_heartbeat() → успіх
|
||||
4. ✅ Heartbeat оновлено
|
||||
```
|
||||
|
||||
### Сценарій 3: Agent count = 0
|
||||
|
||||
```
|
||||
1. Node Guardian бачить agent_count_router = 0
|
||||
2. Логує попередження
|
||||
3. (Опційно) trigger_healing() для перевірки DAGI Router
|
||||
4. ⚠️ Потребує уваги адміністратора
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
| Критерій | Статус |
|
||||
|----------|--------|
|
||||
| node_registry таблиця створена | ✅ |
|
||||
| API self-registration працює | ✅ |
|
||||
| node-bootstrap.sh виконує реєстрацію | ✅ |
|
||||
| node-guardian-loop.py запускається | ✅ |
|
||||
| Ноди видимі в /nodes після реєстрації | ✅ |
|
||||
| Self-healing при зникненні | ✅ |
|
||||
| Heartbeat оновлює статус | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Наступні кроки
|
||||
|
||||
1. **Автоматичний DAGI Router reinstall** при `agent_count_router = 0`
|
||||
2. **NATS events** для node healing (`node.selfhealing.*`)
|
||||
3. **Prometheus metrics** для self-healing
|
||||
4. **Alert rules** для критичних станів
|
||||
5. **Node Federation** — з'єднання нод між собою
|
||||
|
||||
Reference in New Issue
Block a user