simbiot-harness/README.md
Simbiot Harness c68335e7fb feat(dashboard): веб-дашборд задач харнеса — все задачи/статусы/размеры/уровни, лестница, эскалации, дайджесты; автообновление 5с (t-260929164722-60dae2)
- harness/dashboard.py: stdlib-only HTTP-сервер, /api/state (read-only из event store через run_projections — та же проекция, что у scheduler/CLI), /api/health на отдельном порту 8766 (без auth — для systemd healthcheck)
- harness/dashboard.html: страница в стиле architecture.html (paper/ink/signal), fetch каждые 5с, честный errbox при недоступности API, XSS-экранирование всех полей
- auth: SIMBIOT_DASH_TOKEN из /etc/simbiot/dashboard.env (env-файл юнита, 600); без/с неверным токеном — 401; токен в query → cookie
- systemd-юнит simbiot-dashboard.service (после scheduler, restart=always), порт 8765/tcp в UFW
2026-09-29 18:04:38 +00:00

105 lines
No EOL
5.6 KiB
Markdown
Raw 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.

# Simbiot Harness
Ритмичный агент: живёт тактами, как человек. CQRS + Event Sourcing на спине,
Strands Harness SDK как исполнительное ядро, модели через 9router.
## Лестница (v0.1)
| Уровень | Интервал | Контекст | Модель | Задачи |
|---|---|---|---|---|
| sec | 1 с | 0 (без LLM) | — | рефлекс: телеметрия, алерты |
| min | 1 мин | ~4K | auto→flash | S-триаж: входящие, быстрые фиксы |
| hour | 1 ч | ~32K | auto | S/M-задачи |
| day | 1 д | ~128K | auto | M/L-задачи, манифест дня |
Принципы: тик идемпотентен (`UNIQUE(level, seq)`); занятый уровень поглощает
тик (`TickAbsorbed` + детерминированная заглушка дайджеста, без LLM);
запущенная задача не прерывается; наверх идут только дайджесты.
## События (ES-спина)
`CycleTicked`, `TickAbsorbed`, `ReflexObserved`, `DigestWritten`,
`TaskSubmitted`, `TaskClaimed`, `TaskCompleted`, `TaskFailed`, `TaskPromoted`,
`EscalationRaised`, `EscalationAcknowledged`,
`BudgetSpent`, `CycleError`, `HarnessInit`, `PolicySet` — append-only,
проекции пересобираются replay'ем, стейт = производное от событий.
## Структура
- `harness/es.py` — event store + проекции (checkpoint + replay)
- `harness/levels.py` — конфигурация уровней
- `harness/scheduler.py` — демон лестницы
- `harness/isolated_runner.py` + `_llm_worker.py` — LLM-тик в сабпроцессе
(глобальный asyncio-рантайм Strands не переживает 2+ `create_harness`)
- `harness/commands.py` — command side
- `cli.py` — init/task/tasks/status/events/requeue
## CLI
```bash
./venv/bin/python cli.py init --identity "…"
./venv/bin/python cli.py task "…" -m 240 # -m minutes-to-live estimate: S/M/L
./venv/bin/python cli.py tasks
./venv/bin/python cli.py status
./venv/bin/python cli.py events -n 50
./venv/bin/python cli.py requeue <task-id> -r "причина"
./venv/bin/python cli.py promote <task-id> -r "вне класса уровня" # S→M→L
./venv/bin/python cli.py escalate "причина" -f min -c "контекст" -s critical
./venv/bin/python cli.py escalations --open # открытые эскалации
./venv/bin/python cli.py escalation-ack <esc-id> -n "что сделал" # закрыть
./venv/bin/python cli.py tg-reply <msg-id> "текст" # ответ на входящее TG
```
## Эскалации
Важное с нижних уровней поднимается наверх событием `EscalationRaised`
(min→hour→day; day — вершина, эскалировать некуда). Открытые эскалации
инжектятся в контекст верхних уровней (`build_context`) в приоритетной секции
— нижний уровень не тонет в чужих проблемах, верхний видит выжимку, а не сырь.
Уровень-адресат закрывает эскалацию `escalation-ack` (событие
`EscalationAcknowledged`). Падение LLM-тика (`CycleError`) эскалируется
автоматически — scheduler поднимает warn-эскалацию на уровень выше.
## Запуск
```bash
systemctl enable --now simbiot-harness
journalctl -u simbiot-harness -f
```
## Telegram-инбокс
Бот @juno42bot → long polling (`simbiot-harness-tg.service`) →
`MessageReceived` в стор → минутный уровень видит входящие в контексте →
отвечает `cli.py tg-reply` (Telegram-отправка + `ReplySent` закрывает входящее).
Белый список чатов в `.env` (`SIMBIOT_TG_ALLOWED`), чужие → `MessageIgnored`.
## Дашборд задач
Веб-страница со всеми задачами (статусы/размеры/уровни) + лестница циклов +
эскалации + свежие дайджесты, автообновление каждые 5с (JSON-API `/api/state`).
```bash
systemctl status simbiot-dashboard # порт 8765, healthcheck 8766
TOKEN=$(grep -oP '(?<=SIMBIOT_DASH_TOKEN=).*' /etc/simbiot/dashboard.env)
xdg-open "http://<host>:8765/?token=$TOKEN" # токен пишется в cookie
curl "http://127.0.0.1:8765/api/state?token=$TOKEN" | jq . # машиночитаемо
```
Реализация: `harness/dashboard.py` (stdlib-only http.server, read-only из
event store через `run_projections()` — консистентно с scheduler/CLI) +
`harness/dashboard.html`. Авторизация: `SIMBIOT_DASH_TOKEN` из
`/etc/simbiot/dashboard.env` (env-файл юнита, режим 600); без токена — 401.
UFW: порт 8765/tcp открыт (токен-защищён).
## Модели
9router (router.cil.by), отдельный ключ `sk-simbiot` в `.env`, комбо `auto`:
glm-5.3 → kimi-k3 → deepseek-v4-pro → v4.1-flash → flash. Бюджет виден
в событиях `BudgetSpent` (по уровням) и в дашборде 9router по ключу.
## v0.2 (roadmap)
- прерывание срочной реакцией / пауза (сейчас absorbed детерминирован)
- уровни week/month/quarter/year
- инбокс из Telegram/портала