cmd_check проверяет хаб и Eva (код 0 или 3), флаг run --once, scripts/e2e-hub.sh поднимает тестовый хаб во временном JIRA_HUB_HOME. Решения 33–35 в design.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.6 KiB
Архитектура
Агент — один файл src/agent.py и запускатель src/run.py (Python 3.9, только стандартная библиотека). Тесты в
tests/ работают на фейках хаба и Eva. Спека: ../jira-hub/openspec/changes/wiki-module/; решения агента:
openspec/changes/eva-agent-mvp/design.md. Общие части — копия jira-agent v14 (../jira-agent/ARCHITECTURE.md).
Разделы файла src/agent.py
| Раздел | Классы и функции | Ответственность | Что использует |
|---|---|---|---|
| Настройки | load_config |
читает agent.json, проверяет обязательные поля (hub_url, hub_token, eva.base_url, eva.token) |
— |
| Самообновление (состояние) | read_update_state, write_update_state |
update.json рядом с agent.py |
os, json |
| HTTP | Http, HttpError, RedirectAway, TooBig, _SameOriginRedirect |
запросы; Http.send — запрос с готовым телом; fetch_bytes — содержимое файла байтами, не больше предела; перенаправление на другой адрес — RedirectAway без перехода |
urllib |
| Eva | EvaClient |
клиент Eva (Bearer-токен): счётчики вызовов и 429, время последнего вызова. Каркас; JSON-RPC и повторы — в задачах 2–3 | Http |
| Папка | FolderTransport |
транспорт folder: к хабу через общую папку: req/<id>.json → реле хаба → resp/<id>.json; ошибки как у Http |
os, uuid |
| Хаб | HubClient |
claim, release, settings, command, result, upload_file (POST /agent/files), wiki_pages (POST /agent/wiki/pages); при hub_url = folder:… делегирует FolderTransport |
Http, FolderTransport |
| Журнал | Journal, _parse_at |
дозапись journal.jsonl: claimed → started → finished → acked; восстановление; prune |
файловая система |
| Исполнитель | Executor, HubError |
по методу do_<тип> на команду: do_wiki_sync, do_wiki_fetch (в каркасе — failed «не реализовано»); сбой хаба внутри команды — HubError |
EvaClient, HubClient |
| Самообновление | Updater, launcher_version |
после claim без команды — проверка agent_release, скачивание, sha256, компиляция, selftest, staged; подтверждение ok новой версией |
HubClient, subprocess |
| Цикл | Runner |
claim, пауза до команды (по времени последнего вызова Eva), журнал, выполнение, отчёт до подтверждения, восстановление при старте; выход EXIT_UPDATE (75) |
HubClient, EvaClient, Journal, Executor |
| CLI | cmd_run, cmd_check, cmd_selftest, cmd_prune, main, acquire_lock |
команды run (--once — выйти при первом пустом claim), check (хаб GET /agent/settings + Eva CmfDocument.list; код 0 или 3), selftest, prune (run и prune берут блокировку <журнал>.lock); сигналы |
Runner, Journal |
Запускатель src/run.py
Дословная копия запускателя jira-agent (LAUNCHER_VERSION = 2, переменная окружения JIRA_AGENT_LAUNCHER). Не импортирует
agent.py. Запускает agent.py run дочерним процессом; код 75 — подмена на agent.py.new с пробным периодом и
откатом; иначе перезапуск с паузой. Проверка идентичности — test_run_py_is_copy.
Границы
- Код новой версии приходит только через API хаба (
GET /agent/release); общая папка для кода не используется. - Токены хаба и Eva — только в
agent.json; в журнал, хаб, логи и тексты ошибок не попадают. - Темп вызовов Eva задаёт хаб (
wiki_pacingвGET /agent/settings), агент его не хранит. - Одна команда в полёте: следующая берётся после выполнения и подтверждения отчёта.
- Отчёт до подтверждения:
send_resultповторяет каждые 10 с; 404/409/422 от хаба считаются закрытием. - Команды только читают Eva, поэтому после перезапуска выполняются заново (design 9).
- Поля протокола
jira_calls/rate_limited— общие для агентов хаба; агент кладёт в них число вызовов Eva и 429. - Тесты не ходят во внешние сервисы.
Сквозной прогон
scripts/e2e-hub.sh: настоящий хаб (jira-hub serve из worktree jira-hub/.wt/wiki, временный JIRA_HUB_HOME, свободный
порт) + scripts/fake_eva_serve.py + agent.py run --once по HTTP. Живой хаб и его данные не затрагиваются.
Открытые вопросы
- Живая проверка на виртуалке с настоящей Eva (после merge hub#92).