hermes-hub/agents/inbox/2026-08-30-A35-hub-must-actually-route-hermes.md
Hermes Team 2f4866fffa docs(agents): задание A35 — настройки хаба не применяются в Hermes ни разу
Владелец заметил, что настройки Hermes не соответствуют настройкам хаба.
Проверка подтвердила худшее: хаб не участвует в вызовах Hermes вообще.

Доказано исполнением. В исходниках Hermes, agent/conversation_loop.py:3221,
middleware вызывается без параметра role — передаются model, provider,
base_url, session_id, task_id, platform, но не роль. А плагин при
неопределённой роли делает next_call(request), то есть пропускает вызов мимо
маршрутизатора. Подача того же набора аргументов на живой плагин:

    как зовёт Hermes (без роли)  ->  МИМО хаба
    если роль передана           ->  обработал хаб

Механизм исправен целиком, его просто никто не включает: аккаунты, цепочки,
квоты и переключение при исчерпании настраиваются и не применяются.

Пропуск появился не по небрежности, а как защита: раньше при неопределённой
роли всё уходило как orchestrator, цепочка исчерпывалась, и текст ошибки
роутера подставлялся вместо ответа модели. Поэтому задание требует третьего
пути — выводить роль из того, что Hermes уже передаёт, с настраиваемой ролью
по умолчанию, сохранив предохранитель на исчерпанную цепочку.

Hermes править запрещено: чужой продукт, правка затрётся при обновлении.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 21:51:23 +07:00

145 lines
11 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.

# Задание A35: настройки хаба должны применяться в Hermes
## Дата поступления
2026-08-30
## База
Ветка ревьюера `review/a28-a31-fixes` (`ab2ee12`).
```
git fetch origin --prune
git checkout -b antigravity/a35-role-resolution origin/review/a28-a31-fixes
```
В `main` напрямую не пушить.
## Порядок исполнения
Два прохода: **Flash** реализует, **Pro** проводит аудит. Пункт **P0-5** написан для аудитора.
Идёт **параллельно A34** (его делает Codex). Пересечения по файлам почти нет: здесь `hermes_plugin.py` и `router_engine.py`, там веб-клиент и адаптеры. Границу соблюдать.
---
## Задача
Владелец сформулировал так: «надо проверить, чтобы хаб реально работал с Hermes. Сейчас получается, что настройки в Hermes вообще не соответствуют настройкам в хабе. А мы делаем хаб, чтобы все настройки в нём работали и в Hermes».
Проверка подтвердила: **не работают.** Хаб сейчас — панель, которая ничем не управляет.
---
## Что проверено исполнением — заново не выясняйте
**1. Hermes не передаёт роль.** В его исходниках, `agent/conversation_loop.py:3221`:
```python
run_llm_execution_middleware(
api_kwargs, _perform_api_call,
original_request=..., task_id=..., turn_id=..., api_request_id=...,
session_id=..., platform=..., model=..., provider=..., base_url=...,
api_mode=..., api_call_count=..., middleware_trace=...
)
```
Параметра `role` нет. Есть `model`, `provider`, `base_url`, `session_id`, `task_id`, `platform` — этого достаточно, см. P0-1.
**2. Без роли плагин пропускает вызов мимо хаба.** `hermes_plugin.py:42`:
```python
if not resolved_role:
if callable(next_call):
return next_call(request)
```
**3. Измерено на живом плагине**, подачей ровно того, что шлёт Hermes:
```
как зовёт Hermes (без роли) -> МИМО хаба, собственный вызов Hermes
если роль передана -> обработал хаб, маршрутизация сработала
```
Механизм исправен целиком. Его просто никто не включает: аккаунты, цепочки, квоты и переключение при исчерпании настраиваются и **не применяются ни разу**.
**4. Почему так сделано — это защита, а не небрежность.** `resolve_role` намеренно не угадывает роль по тексту: «no guessing from prompts». Раньше при неопределённой роли всё шло как `orchestrator`, цепочка исчерпывалась, и **текст ошибки роутера подставлялся вместо ответа модели** — владелец получал сообщение хаба там, где ждал ответ. Пропуск появился как безопасный откат после этой аварии.
Сейчас выбор стоит так: хаб либо молчит, либо врёт. Задание — сделать третье.
---
## P0-1. Определение роли по тому, что Hermes всё-таки передаёт
Порядок разрешения, сверху вниз:
1. **Явная роль** — если когда-нибудь появится в `kwargs`, `request`, `metadata`. Работает уже сейчас, не ломать.
2. **По модели и провайдеру.** Hermes передаёт `model` и `provider`. Если запрошенная модель или провайдер — основные у какой-то роли, берём её. Соответствие строится **из конфигурации**, а не из литералов в коде.
3. **По устойчивости сессии.** Передаётся `session_id`. Если для этой сессии роль уже определялась, брать её же: механизм `session_affinity` есть и работает.
4. **Роль по умолчанию — настройка.** Не подошло ничего — берём настраиваемую роль, а не молчим. Значение по умолчанию выбрать и обосновать в отчёте; **в код не зашивать**.
Пропуск мимо хаба остаётся только на случай, когда маршрутизатор выключен целиком.
## P0-2. Предохранитель снимать нельзя
Исчерпанная цепочка **обязана** уходить в `next_call`, а не подставлять текст ошибки вместо ответа модели. Это уже стоило владельцу рабочего дня.
Требуется тест, который падает, если ответ роутера с `router_error` окажется в ответе Hermes.
Отдельно: включение маршрутизации не должно ломать Hermes при пустой конфигурации. Нет ни одного подключённого аккаунта — вызов уходит вниз, а не превращается в ошибку.
## P0-3. Видно, что происходит
Владелец должен понимать, что хаб теперь участвует в вызовах.
1. **В журнале событий** — какая роль выбрана, по какому признаку (явная, по модели, по сессии, по умолчанию) и какой профиль отработал.
2. **В аналитике** вызовы Hermes должны появиться. Сейчас там пусто именно потому, что до хаба ничего не доходит.
3. Признак выбора роли — не выдумка, а факт: если взята роль по умолчанию, так и написать.
## P0-4. Проверка на живом Hermes
Отчёт без этого не принимается.
1. Запустить Hermes, дать ему задачу, убедиться по журналу, что **вызов прошёл через хаб** и через ожидаемый аккаунт.
2. Проверить, что смена цепочки в интерфейсе меняет то, чем Hermes реально отвечает.
3. Проверить исчерпание: отключить первый аккаунт в цепочке и убедиться, что переключение произошло, а Hermes продолжил работать.
4. Проверить пустую конфигурацию: Hermes работает как раньше.
Пункт 2 — суть задания. Пока смена настройки в хабе не меняет поведение Hermes, задание не выполнено.
## P0-5. Аудит вторым проходом
1. **Угадывание по тексту запроса.** Его не должно появиться: правило «no guessing from prompts» введено осознанно. Признаки — только явные поля.
2. **Литеральные соответствия модель→роль** в коде. Их быть не должно, всё из конфигурации.
3. **Предохранитель на исчерпанную цепочку** — проверить отдельно, тестом и руками.
4. **Запустить с живым Hermes**, а не только тестами.
5. **Побочные изменения** объяснить.
6. **Пропущенный пункт назвать пропущенным.**
---
## Ограничения
- **Hermes не править.** Это чужой продукт; правка `conversation_loop.py` будет затираться при каждом его обновлении. Работать только с тем, что он уже передаёт.
- Зона: `hermes_plugin.py`, `router_engine.py`, `router_config.py`, `settings_service.py`, соответствующие тесты. Веб-клиент и адаптеры — зона A34, туда не заходить.
- Правило честности без исключений.
- Тег `v0.1.1` не создавать.
## Критерии приёмки
1. Ветка в `origin` от `review/a28-a31-fixes`, `git status` чист.
2. Вызов Hermes без роли **доходит до маршрутизатора**; проверено подачей того же набора аргументов, что в `conversation_loop.py:3221`.
3. Признак выбора роли записывается в журнал и различим: явная, по модели, по сессии, по умолчанию.
4. Роль по умолчанию настраивается, значение не зашито.
5. Изменение цепочки в интерфейсе меняет поведение живого Hermes; **приложить вывод**.
6. Исчерпанная цепочка уходит в `next_call`, текст ошибки роутера в ответ Hermes не попадает; есть тест.
7. Пустая конфигурация не ломает Hermes.
8. Вызовы Hermes видны в аналитике.
9. `ruff check .` чисто; релизный гейт не ухудшен.
10. Отчёт: `START_HEAD`, `FINAL_HEAD`, `origin/main`, `git status`, `X passed / Y skipped / Z failed`. На ветке ревьюера сейчас **475 passed, 2 skipped**.
## Главное
Хаб делается ради того, чтобы аккаунтами и лимитами управлять из одного места, и чтобы это управление действовало в Hermes. Сейчас оно не действует ни в одной точке: каждый вызов проходит мимо. Это самая важная задача в очереди — без неё всё остальное остаётся витриной.
## Порядок сдачи
Передать точный `FINAL_COMMIT_SHA`.