homelab-codex-ws/kb/services/planner-agent.md
oskar 6b85c7ef68 feat(kb): SPLIT service+runbook — 10 serwisow -> 20 dokumentow
Wzorzec mechaniczny: sekcje deploy/verify/install/testy wycinane do
kb/runbooks/<serwis>-*.md, reszta zostaje dokumentem type: service.
Wzajemne `links` w obie strony. Tresc sekcji nietknieta — przenoszone
doslownie, dodany wylacznie naglowek H1 nowego runbooka.

kb-query, paperless-worker, planner-agent, ha-diag-agent, ollama-piha,
narty27, home-assistant, ha-mcp, job-gmail-header-backfill, job-mail-body-ingest.

Weryfikacja: dla kazdego pliku multizbior niepustych linii
(main + runbook) == oryginal z HEAD. Zero zgubionych, zero dodanych.

Recon szacowal 13 splitow service+runbook; faktycznie 2-typowych jest 10,
pozostale 5 (paperless, nextcloud, gokapi, fleet-prometheus, deploy-runner)
sa 3-typowe i ida osobno jako splity wielotypowe.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:58:46 +02:00

153 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
okf: "0.1"
type: service
visibility: private
status: active
updated: 2026-05-27
links:
- ../runbooks/planner-agent-deploy.md
---
# planner-agent
Asynchroniczny agent diagnozujący zdarzenia zdrowotne w homelabowej infrastrukturze.
Nasłuchuje na kanałach Redis pub/sub, wysyła zdarzenie do LLM i zapisuje propozycję
akcji do `actions/pending/` — gdzie musi ją zaakceptować operator.
---
## Co robi
```
Redis pub/sub LLM (Ollama → Haiku → Sonnet)
health_events ──────────────► diagnoza zdarzenia
world_updates ──────────────► propozycja JSON
cooldown gate (5 min / svc_key)
actions/pending/<action_id>.json
events/<date>/<node>/evt-*.json
(typ: remediation_started)
```
**HITL invariant:** planner pisze wyłącznie do `actions/pending/`.
Executor wymaga pliku w `actions/approved/` — planner nigdy tego katalogu nie dotyka.
### Obsługiwane kanały
| Kanał | Źródło | Opis |
|-------|--------|------|
| `health_events` | node-agent, stability-agent | Zdarzenia zdrowotne kontenerów i systemu |
| `world_updates` | observer (control-plane) | Zmiany w world state |
### Benign events (pomijane bez wywołania LLM)
`service_healthy`, `service_recovered`, `node_online`, `deployment_completed`,
`deployment_started`, `remediation_started`, `remediation_completed`
---
## Fallback chain LLM
```
1. ollama/<OLLAMA_MODEL> timeout 8 s (lokalny GPU — SOLARIA)
2. claude-haiku-4-5-20251001 timeout 30 s (Anthropic cloud)
3. claude-sonnet-4-6 timeout 30 s (Anthropic cloud)
```
Model jest odrzucany, gdy:
- przekroczy timeout
- zwróci błąd sieci / API
- odpowie tekstem pasującym do wzorca odmowy (`"I cannot"`, `"nie wiem"`, …)
- zwróci JSON niezgodny ze schematem propozycji
Metryki każdego wywołania są publikowane na kanał Redis `llm_router_metrics`.
### Schemat propozycji (JSON Schema)
```json
{
"action": "restart | redeploy | notify | ignore",
"service": "<nazwa serwisu>",
"node": "<nazwa noda>",
"reason": "<wyjaśnienie, min. 10 znaków>",
"confidence": <0.01.0>,
"requires_human": <true|false>
}
```
Mapowanie na typ executora:
| LLM action | Executor type | Risk level |
|------------|--------------------|------------|
| restart | container_restart | low |
| redeploy | redeploy | guarded |
| notify | notify | low |
| ignore | *(nie zapisuje)* | — |
---
## Zmienne środowiskowe
Wszystkie zmienne runtime żyją w `/opt/homelab/config/planner-agent/.env` na węźle.
**Nie commituj tego pliku** — nie jest w repo.
```dotenv
# Ollama — lokalny GPU węzła (np. SOLARIA)
# Użyj host-gateway zamiast localhost (kontener nie może sięgnąć hosta przez localhost)
OLLAMA_HOST=http://host-gateway:11434
OLLAMA_MODEL=qwen2.5-coder:14b # dowolny model dostępny w ollama list
# Redis na piha
REDIS_URL=redis://100.108.208.3:6379
# Tożsamość noda
NODE_NAME=solaria
# Cooldown między propozycjami dla tego samego serwisu
COOLDOWN_SECONDS=300
# Ścieżka do runtime state
RUNTIME_PATH=/opt/homelab
# Opcjonalnie — wymagane do cloud fallback (haiku/sonnet)
# ANTHROPIC_API_KEY=sk-ant-...
```
`ANTHROPIC_API_KEY` jest jedyną zmienną przekazywaną przez sekcję `environment`
w docker-compose.yml (nie jest w env_file — sekret injektowany przez operatora).
---
## Healthcheck
Skrypt `healthcheck.sh` sprawdza czy plik heartbeat
`/opt/homelab/state/planner-agent.heartbeat` jest świeższy niż 300 s.
Heartbeat jest pisany na górze każdej iteracji pętli (≤5 s interwał).
```bash
# Ręczny test healthchecku
docker exec planner-agent /bin/sh /app/healthcheck.sh
```
---
## Struktura plików
```
services/planner-agent/
├── src/
│ ├── planner.py # Główna pętla agenta
│ └── llm_router.py # Routing LLM z fallback chain
├── tests/
│ ├── test_planner.py # 49 testów
│ └── test_llm_router.py # 34 testy
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── service.yaml # Kontrakt operacyjny dla agentów
├── healthcheck.sh
└── README.md
```