Simbiot Harness — ритмичный агент кооператива 42
Find a file
Simbiot Harness 0523135bf1 feat(portal-chat): прямой канал портал↔агент без Matrix (t-261001123122-5ea554)
- portal_channel.py: HTTP-клиент портала — pull входящих чата портала
  (GET /api/agent/<имя>/channel/poll?since=ms), push ответов (POST outbox,
  ack входящих по msg_id), сек-рефлекс (≤20с) + cron main().
- tg_inbox: чаты 'portal:*' доставляются push'ем на портал (ReplySent),
  reply_to = портальный update_id (portal: ack consumed входящего).
- scheduler: ReflexObserved хук на portal_channel.sec_reflex — pull работает
  и без LLM-тика, и на машинах без TG.
- es: проекционный бранчPortalDelivered выпилен (маркер — ReplySent от
  tg_inbox); MessageIgnored branch остался нетронутым.
- Диагноз: SSH портал→агенты закрыт (timeout :22/:8765 к #83) — канал на
  исходящем HTTP, AGENT_TOKEN+PORTAL_URL уже пекутся в /etc/coop-reporter.env,
  agent-scope env добавлены в cloud-init .env (SIMBIOT_AGENT_TOKEN/NAME/CHAT=1).
2026-10-01 13:34:26 +00:00
docs fix(guard)+feat(dash): requeue ready-гонка не валила тик (e-261001083543-0eab6d); дашборд «🔧 в работе» + elapsed (t-261001082111); пакет покупателя предпродажи (t-261001085722) 2026-10-01 09:11:23 +00:00
harness feat(portal-chat): прямой канал портал↔агент без Matrix (t-261001123122-5ea554) 2026-10-01 13:34:26 +00:00
scripts fix(tg): send_reply грузит .env до sendChatAction (свежий процесс терял индикатор); safe-restart: пост-рестарт верификация сек-тика на команде; tests/test_tg_commands.py (41 проверка) 2026-09-30 02:42:09 +00:00
tests fix(runtime): ROUTER_BASE_URL и ключ читаются из .env (e-261001091912) + тест 2026-10-01 10:09:13 +00:00
.gitignore feat(proactive): инициативные реплики харнеса в чат — ритм/анти-спам/банк тем AUM (t-260930073419) 2026-09-30 11:15:49 +00:00
architecture.html feat: эскалации (min→hour→day) + фикс хвоста событий в CLI 2026-09-29 16:13:23 +00:00
cli.py feat(scheduler): батч-обработка задач в тике — пачка ready-задач в бюджете контекста (t-260930101325-010ba3) 2026-09-30 14:13:30 +00:00
events.db feat(tg-cmd): без-LLM команды бота /лестница /статус /задачи /помощь — мгновенные ответы сек-рефлексом + setMyCommands (t-260929210755-9bf6a6) 2026-09-30 02:30:27 +00:00
README.md docs(readme): лестница выровнена с levels.py — min 256k → hour 512k → day 1M (e-261001082710); week/month → roadmap v0.2 ( Alex: старая таблица в ридми) 2026-10-01 11:02:34 +00:00
simbiot-presentation.html feat(gate): гейт важности LLM-тика по per-level порогу + model в событиях 2026-09-30 08:29:54 +00:00

Simbiot Harness

Ритмичный агент: живёт тактами, как человек. CQRS + Event Sourcing на спине, Strands Harness SDK как исполнительное ядро, модели через 9router.

Главная цель (фиксация Alex, 2026-09-30)

Метрика харнеса — максимизация долгосрочной AUM (доход/ресурс всех проектов кооператива в длинном горизонте). Главный вопрос к любому уровню и любой задаче: «добавит ≥1% к AUM в горизонте год+?» — что приносит короткий доход, но съедает долгосрочную базу, приоритет ниже. На этой цели стоит автоприоритизация доски задач (t-260929161138; уточнение автоприоритизации день+час — t-260930153845, задача e-260930161330).

Лестница (v0.1)

Уровень Интервал Контекст Модель Задачи
sec 1 с 0 (без LLM) — рефлекс: телеметрия, алерты
min 1 мин 256K auto (effort low) S-триаж: входящие, быстрые фиксы
hour 1 ч 512K auto (medium) S/M-задачи, дайджест часа
day 1 д 1M auto (high) M/L-задачи, манифест дня

Конфиг согласован Алексом (e-261001082710): min 256k → hour 512k → day 1M (ctx_tokens в harness/levels.py); week/month/quarter/year — в roadmap v0.2.

Принципы: тик идемпотентен (UNIQUE(level, seq)); занятый уровень поглощает тик (TickAbsorbed + детерминированная заглушка дайджеста, без LLM); запущенная задача не прерывается; наверх идут только дайджесты.

События (ES-спина)

CycleTicked, TickAbsorbed, ReflexObserved, DigestWritten, TaskSubmitted, TaskClaimed, TaskCompleted, TaskFailed, TaskPromoted, TaskAwaitDelivery, DeliverySent, InitiativeSent, 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
  • harness/tg_commands.py — без-LLM команды бота (сек-рефлекс)
  • cli.py — init/task/task-await/tasks/status/events/requeue

CLI

./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 task "…" -a              # автодоставка результата в TG при готовности
./venv/bin/python cli.py task-await <task-id>     # пометить существующую: доставить в TG
./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
# батч-режим (t-260930064924): один сводный ответ закрывает несколько входящих
./venv/bin/python cli.py tg-reply m-1,m-2,m-3 -c "текст"   # ReplySent на каждое, одна отправка
# идемпотентные уведомления/файлы (t-260930083937): повтор — SKIP, дублей в чат нет
./venv/bin/python cli.py tg-notify "текст" -k <ключ>
./venv/bin/python cli.py tg-deliver-file <путь> -c "подпись" [--force]

Автодоставка артефактов (t-260929205927)

Задача, заказанная из TG (cli.py task -a / task-await), помечается TaskAwaitDelivery. При завершении (TaskCompleted) результат (answer) уходит в чат сам — DeliverySent, без повторного запроса. Push в тике (сразу после завершения) + pull-страховка (delivery-демон каждые 15с: досылает недоставленное, если тик умер между завершением и отправкой). Идемпотентно: один раз доставлено — повторно не шлётся; после requeue доработка доставляется снова. Формат: «✅ Готово: