feat: implement swapper metrics and node cabinet ui
This commit is contained in:
@@ -73,8 +73,7 @@
|
||||
alter table node_cache
|
||||
add column swapper_healthy boolean,
|
||||
add column swapper_models_loaded integer,
|
||||
add column swapper_models_total integer,
|
||||
add column swapper_state jsonb; -- Для повного списку моделей
|
||||
add column swapper_models_total integer;
|
||||
```
|
||||
|
||||
Міграція: `migrations/039_node_cache_swapper_metrics.sql`.
|
||||
@@ -91,9 +90,8 @@ import requests
|
||||
def collect_swapper_metrics(swapper_base_url: str) -> dict:
|
||||
result = {
|
||||
"swapper_healthy": False,
|
||||
"swapper_models_loaded": 0,
|
||||
"swapper_models_total": 0,
|
||||
"swapper_state": {}
|
||||
"swapper_models_loaded": None,
|
||||
"swapper_models_total": None,
|
||||
}
|
||||
try:
|
||||
# healthz
|
||||
@@ -111,8 +109,8 @@ def collect_swapper_metrics(swapper_base_url: str) -> dict:
|
||||
loaded = sum(1 for m in models if m.get("loaded") is True)
|
||||
result["swapper_models_total"] = total
|
||||
result["swapper_models_loaded"] = loaded
|
||||
result["swapper_state"] = data # Зберігаємо весь стан
|
||||
except Exception:
|
||||
# залишаємо None → UI покаже "невідомо"
|
||||
pass
|
||||
|
||||
return result
|
||||
@@ -133,7 +131,6 @@ payload = {
|
||||
"swapper_healthy": swapper_metrics["swapper_healthy"],
|
||||
"swapper_models_loaded": swapper_metrics["swapper_models_loaded"],
|
||||
"swapper_models_total": swapper_metrics["swapper_models_total"],
|
||||
"swapper_state": swapper_metrics["swapper_state"]
|
||||
}
|
||||
requests.post(f"{CITY_URL}/internal/node/{node_id}/metrics/update", json=payload, timeout=5)
|
||||
```
|
||||
@@ -145,6 +142,16 @@ requests.post(f"{CITY_URL}/internal/node/{node_id}/metrics/update", json=payload
|
||||
* приймати нові поля;
|
||||
* оновлювати відповідні колонки в `node_cache`.
|
||||
|
||||
Приклад (ескіз):
|
||||
|
||||
```python
|
||||
swapper_healthy = body.get("swapper_healthy")
|
||||
swapper_models_loaded = body.get("swapper_models_loaded")
|
||||
swapper_models_total = body.get("swapper_models_total")
|
||||
|
||||
# update node_cache set ... where node_id = ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Backend: Swapper detail endpoint
|
||||
@@ -170,7 +177,11 @@ requests.post(f"{CITY_URL}/internal/node/{node_id}/metrics/update", json=payload
|
||||
```
|
||||
|
||||
Джерело:
|
||||
* `node_cache` (нові колонки + jsonb `swapper_state`).
|
||||
|
||||
* по можливості прямо через Swapper API;
|
||||
* частину агрегованих значень (loaded/total) можна брати з `node_cache`.
|
||||
|
||||
Цей endpoint буде використовуватись Node Cabinet для розгорнутої таблиці моделей.
|
||||
|
||||
---
|
||||
|
||||
@@ -194,18 +205,42 @@ export function useNodeSwapper(nodeId: string) {
|
||||
|
||||
* заголовок: `Swapper Service`;
|
||||
* статус:
|
||||
|
||||
* `🟢 Healthy` / `🟡 Degraded` / `🔴 Down` (на основі `healthy` + `models_loaded`);
|
||||
* коротке резюме:
|
||||
|
||||
* `Моделі: 3/5 завантажено`;
|
||||
* кнопка/кнопка-розкривалка `Переглянути моделі`:
|
||||
|
||||
* список моделей (name, type, loaded).
|
||||
|
||||
Макет (ескіз):
|
||||
|
||||
```txt
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 🧠 Swapper Service [↻] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Статус: 🟢 Healthy │
|
||||
│ Моделі: 3 / 5 завантажено │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ d-model-3b | llm | 🟢 loaded │
|
||||
│ d-code-7b | code | 🟢 loaded │
|
||||
│ vision-8b | vlm | 🔴 not loaded│
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.3. Інтеграція в Node Cabinet
|
||||
|
||||
На сторінці `/nodes/[nodeId]`:
|
||||
|
||||
* додати `NodeSwapperCard` поруч із `NodeMetricsCard` / `DAGIRouterCard` у секцію Service Agents.
|
||||
|
||||
Наприклад:
|
||||
|
||||
* **Node Core**: Guardian/Steward
|
||||
* **Service Agents**: DAGI Router, Swapper, Multimodal (Swapper Card тут)
|
||||
* **Control & Intelligence**: Tools & Planner, Security, Archivist.
|
||||
|
||||
---
|
||||
|
||||
## 6. Tests
|
||||
@@ -214,14 +249,17 @@ export function useNodeSwapper(nodeId: string) {
|
||||
|
||||
* Тест міграції `node_cache` (наявність нових колонок).
|
||||
* Тест `POST /internal/node/{id}/metrics/update`:
|
||||
|
||||
* при передачі полів Swapper правильно оновлює `node_cache`.
|
||||
* Тест `GET /internal/node/{id}/swapper`:
|
||||
|
||||
* при коректній відповіді Swapper API повертає очікувану структуру;
|
||||
* якщо Swapper лежить — `healthy=false`, моделі порожні.
|
||||
|
||||
### 6.2. Frontend
|
||||
|
||||
* Snapshot-тест `NodeSwapperCard` для випадків:
|
||||
|
||||
* healthy + моделі є;
|
||||
* unhealthy + немає моделей;
|
||||
* loading/error state.
|
||||
@@ -232,17 +270,21 @@ export function useNodeSwapper(nodeId: string) {
|
||||
|
||||
1. node-guardian-loop регулярно збирає Swapper-метрики та відправляє їх у city-service.
|
||||
2. `node_cache` містить свіжі поля:
|
||||
|
||||
* `swapper_healthy`
|
||||
* `swapper_models_loaded`
|
||||
* `swapper_models_total`
|
||||
* `swapper_state` (JSONB)
|
||||
3. `GET /internal/node/{id}/metrics/current` відображає Swapper-метрики для обох нод.
|
||||
4. `GET /internal/node/{id}/swapper` повертає детальну інформацію про Swapper (мінімум: healthy + models).
|
||||
5. У Кабінеті Ноди (`/nodes/[nodeId]`) є блок Swapper Service:
|
||||
|
||||
* показує статус,
|
||||
* показує кількість завантажених моделей,
|
||||
* дозволяє переглянути список моделей.
|
||||
6. `scripts/check-deploy-post.py` оновлено для перевірки Swapper.
|
||||
6. `scripts/check-deploy-post.py` можна оновити, щоб:
|
||||
|
||||
* додати 1–2 перевірки Swapper-статусу (healthy/models_loaded),
|
||||
* і вони проходили при нормальному стані.
|
||||
|
||||
---
|
||||
|
||||
@@ -251,11 +293,12 @@ export function useNodeSwapper(nodeId: string) {
|
||||
* `migrations/039_node_cache_swapper_metrics.sql`
|
||||
* Оновлений `node-guardian-loop.py` (з Swapper-метриками)
|
||||
* Оновлені endpoints:
|
||||
|
||||
* `POST /internal/node/{id}/metrics/update`
|
||||
* `GET /internal/node/{id}/swapper`
|
||||
* Frontend:
|
||||
|
||||
* `useNodeSwapper(nodeId)`
|
||||
* `NodeSwapperCard`
|
||||
* Інтеграція в Node Cabinet
|
||||
* Тести (backend + frontend)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user