5.8 KiB
5.8 KiB
Dev Report: ORCH-41 — Конфигурируемые модели LLM + effort агентов
Дата: 2026-06-05 Статус: DONE
Задача
Вынести модель LLM и режим работы (--effort) агентов конвейера из хардкода
src/agents/launcher.py в конфиг — per-agent (env) + per-project (projects_json).
Репо orchestrator, ветка feat/ORCH-41-agent-models от main (HEAD 8da571d), PR в main, НЕ мержить.
Сделано
- config.py: per-agent модель + effort + fallback (Settings, префикс ORCH_)
- projects.py: ProjectConfig.agent_models / agent_efforts (frozen → field(default_factory=dict)) + парсинг из projects_json
- launcher.py: резолверы resolve_agent_model / resolve_agent_effort, убран хардкод "model":"opus", сборка флагов --model/--effort/--fallback-model
- Тесты: test_resolve_agent_model.py (12), test_resolve_agent_effort.py (9) = 21 новых
- Docs: INFRA.md, internals.md, CHANGELOG.md
- pytest tests/ -q из клона ветки в прод-образе → 423 passed, 0 failed
- push + git log origin/main..origin/feat/ORCH-41-agent-models показывает коммит
- PR #36 создан (НЕ смержен)
Изменённые файлы
src/config.py— поля Settings:agent_model_default="claude-opus-4-8"+agent_model_<analyst|architect|developer|reviewer|tester|deployer>=""agent_effort_default="high"+ per-agent (думающие=high, tester/deployer=medium)agent_fallback_model=""- env:
ORCH_AGENT_MODEL_<AGENT>,ORCH_AGENT_EFFORT_<AGENT>,ORCH_AGENT_FALLBACK_MODEL
src/projects.py—from dataclasses import dataclass, field;ProjectConfig.agent_models: dict = field(default_factory=dict)+agent_efforts: dict = field(default_factory=dict); хелпер_coerce_str_map(...)(валидация → {str:str}, мусор → {}); парсинг обоих полей в_parse_projects_json.src/agents/launcher.py:VALID_EFFORTS = {low,medium,high,xhigh,max}_resolve_agent_attr(...)— общий приватный резолвер приоритетаresolve_agent_model(agent, project_id=None)/resolve_agent_effort(agent, project_id=None)(effort валидируется, невалид → warning + опускается)- убран
"model":"opus"из architect/reviewer в AGENT_CONFIGS - в
_spawn:project_idрезолвится из repo черезget_project_by_repo(repo).plane_project_id - сборка
model_flag/effort_flag/fb_flagи подстановка{model_flag}{effort_flag}{fb_flag}в cmd
tests/test_resolve_agent_model.py,tests/test_resolve_agent_effort.py— новыеdocs/operations/INFRA.md— env-карта + раздел «Модель и effort агентов»docs/architecture/internals.md— конфиг-буллеты ORCH-41CHANGELOG.md— запись в [Unreleased] → Added
Приоритет резолвинга (оба резолвера)
ProjectConfig.agent_models[agent]/agent_efforts[agent](per-project, из projects_json)settings.agent_model_<agent>/agent_effort_<agent>(per-agent env, если непусто)settings.agent_model_default/agent_effort_default- пусто → флаг не передаётся, дефолт CLI
Результат
pytest tests/ -q -p no:cacheprovider(клон ветки, окружение прод-образа orchestrator): 423 passed, 1 warning (402 baseline + 21 новых), 0 failed.- Ручная проверка резолвинга:
resolve_agent_model("developer")→claude-opus-4-8resolve_agent_model("architect")→claude-opus-4-8(раньше резолвилось в opus-4-7 через хардкод "opus")resolve_agent_effort("developer")→high,resolve_agent_effort("tester")→medium
- Коммит на origin:
git log origin/main..origin/feat/ORCH-41-agent-models→8a292b9 feat(agents): ... (ORCH-41) - PR: admin/orchestrator#36 (status: open, НЕ смержен)
Пример конфига per-project (ORCH_PROJECTS_JSON)
{"plane_project_id":"8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a","repo":"orchestrator","work_item_prefix":"ORCH",
"agent_models":{"developer":"claude-opus-4-8","reviewer":"claude-sonnet-4-6"},
"agent_efforts":{"developer":"xhigh","tester":"low"}}
Оба поля опциональны → старые записи реестра работают без изменений (default = {}).
Проблемы и решения
- Nested-heredoc через ssh+docker рвал кавычки → перешёл на патч-скрипты, передаваемые base64 в контейнер и запускаемые python3 (детерминированные
assert count==1на якорях). - 3 теста effort падали: autouse-фикстура задавала per-agent effort (level 2), поэтому смена только
*_defaultне влияла → в этих тестах дополнительно обнуляю per-agent значение. - curl в контейнере отсутствует → PR создан через
httpx(зависимость проекта).
Off-limits соблюдено
- Гейты/webhook/HMAC/очередь не тронуты.
- Версия модели НЕ хардкодится — только
defaultв коде (configurable). - frozen dataclass + dict → field(default_factory=dict).
- Прод/env не менялся; раннеры не регистрировались; nohup не использовался.
- PR НЕ смержен.