hermes-hub/agents/inbox/2026-08-25-A26-accounts-without-slots.md
Hermes Team 8cb57dd6a1 docs(agents): задание A26 — аккаунты без слотов, распределение и пороги квот
Владелец сформулировал, ради чего задумывался хаб: вручную распределять
аккаунты по агентам и следить за квотами, подставляя другой аккаунт там, где
лимит подходит к концу. Модель слотов этому мешает — она навязывает
внутреннее устройство конфигурации и уже привела к тому, что подключённый
аккаунт не появился в маршрутизации.

Задание опирается на три факта, снятых исполнением, чтобы агенты не
переписывали работающее: один профиль уже может обслуживать все шесть ролей;
произвольный идентификатор профиля регистрируется, то есть потолок в три
аккаунта Codex держит только зашитый список в auto_assigner; порогов квот в
коде нет вовсе.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 14:40:37 +07:00

16 KiB
Raw Blame History

Задание A26: аккаунты без слотов, распределение по агентам и пороги квот

Дата поступления

2026-08-25

База

Проверочный HEAD на момент выдачи: d4b99a4.

Ветка

antigravity/accounts-without-slots

Порядок исполнения

Два прохода: Flash реализует, Pro проводит аудит. Пункт P0-6 написан для аудитора.


Порядок работы с git

cd <каталог репозитория>; git fetch origin --prune; git status
git checkout main; git pull --ff-only origin main
git checkout -b antigravity/accounts-without-slots
git commit -m "..."          <- сначала коммит
git push -u origin antigravity/accounts-without-slots

В main напрямую не пушить. В конце — push и проверка git log --oneline -1, git status чистый.


Ради чего это всё

Дословно от владельца:

«вот для этого хаб и делался. чтобы вручную правильно распределять аккаунты и играться с лимитами. где подзаканчиваются, там ставить другой аккаунт»

Сейчас продукт этого не даёт. Модель «слотов» — десять предсозданных ячеек Antigravity, три Codex, три OpenCode — навязывает пользователю внутреннее устройство конфигурации. Владелец выбирает слот, ничего не зная о последствиях, и получает результат, которого не ожидал: аккаунт подключён, а на экранах его нет, потому что слот не входит ни в одну цепочку. Это уже случилось вживую.

Нужен обратный порядок: сначала аккаунты, потом назначение.


Что уже проверено исполнением — заново не выясняйте

Три факта, снятые ревьюером на d4b99a4. Они сильно сокращают работу.

1. Один профиль может обслуживать все шесть ролей. Движок это держит уже сейчас:

persist_role_chain(role, ['ag-w1']) для всех шести ролей -> True
конфигурация: все шесть цепочек равны ['ag-w1']

Значит требование «если есть только Antigravity, он встаёт во всех агентах» не требует изменений в маршрутизаторе. Не переписывайте router_engine.

2. Произвольный идентификатор профиля регистрируется.

ensure_profile_definition('openai-codex', 'codex-worker-9') -> True
'codex-worker-9' in load_router_config().profiles -> True

Значит потолок «три аккаунта Codex» — это только зашитый список provider_slots в auto_assigner.py:144, а не структурное ограничение. Снятие потолка не требует переделки формата конфигурации.

3. Порогов квот в коде нет вообще. Поиск по threshold|min_quota|quota_floor|switch_at в router/ не даёт ни одного совпадения. Это делается с нуля.


P0-1. Снять потолок на число аккаунтов

Дословно: «например у меня есть 4 кодекса, и их все я хочу добавить. или 5 опенкодов».

Сейчас AutoAssigner.find_free_slot (auto_assigner.py:140) перебирает жёсткий список и возвращает None, когда список кончился. Четвёртый Codex подключить невозможно.

Требуется: число аккаунтов провайдера ничем не ограничено. Когда предопределённые имена кончились, идентификатор выдаётся автоматически по понятной схеме (codex-4, codex-5, …), с проверкой, что такого ещё нет.

Идентификатор — деталь реализации, и в интерфейсе он не должен быть главным. Владелец мыслит аккаунтами и почтами, а не слотами.

P0-2. «Аккаунты» показывают только настоящие аккаунты

Дословно: «надо убрать все ячейки со вкладки аккаунты. как добавляю аккаунт, тогда он там появляется. не надо захламлять страницу».

Сейчас в умолчаниях предсозданы 24 профиля, и страница показывает их все, включая никогда не подключённые: «Аккаунт не добавлен», «Холодный резерв». У владельца это 24 карточки при одном реальном аккаунте.

Требуется показывать только подключённые.

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

P0-3. Назначение аккаунта агенту — в «Обзоре»

Дословно: «просто загрузка аккаунтов, а уже в обзоре прикреплять нужный аккаунт к агенту».

На «Обзоре» уже есть схема ролей и выбор модели в узле (A24). Добавить туда выбор аккаунта: какой обслуживает эту роль и в каком порядке резервирования.

Действия существуют — assign_role, save_chain, reorder_chain; второй реализации не заводить.

Ключевое требование, вытекающее из факта №1: один аккаунт можно назначить сразу нескольким агентам, вплоть до всех шести. Интерфейс не должен этому препятствовать и не должен считать это ошибкой.

P0-4. Кнопка «Авто»

Дословно: «или при нажатии авто, сам распределяет аккаунты согласно маршрутизации».

Действие auto_assign_all существует (action_handler.py:509), но что оно делает и совпадает ли с ожиданием владельца — проверьте исполнением и опишите в отчёте. Отчёт без запуска не принимается.

Ожидаемое поведение:

  • Один провайдер. Есть только Antigravity — он встаёт во все шесть ролей. Владелец дальше сам меняет модель у каждого агента. Это нормальный режим, а не вырожденный случай.
  • Несколько провайдеров. Распределение идёт по назначению роли: «оркестратор у меня первый кодекс, а кодер антигравити» — у каждой роли есть предпочтительный провайдер, и авто-распределение ему следует, а не раскладывает аккаунты подряд.
  • Несколько аккаунтов одного провайдера разводятся по разным ролям, чтобы не жечь квоту одного на всё сразу.

Порядок предпочтений по ролям возьмите из текущего config/router_profiles.example.yaml — он и выражает замысел владельца. Решите его менять — сначала спросите в отчёте, молча не меняйте.

P0-5. Пороги квот: предупреждение или переключение

Дословно: «выставлять минимальные лимиты (например 10% или 5%) и при достижении этих лимитов или оповещение или автоматом переключает на резервный аккаунт».

Это то, ради чего хаб задумывался. Требуется:

  1. Настраиваемый порог — общий и, если несложно, отдельный для аккаунта. Значения владельца: 10% и 5%. В код их не зашивать, это умолчание, а не константа.
  2. Выбор поведения при достижении: только оповестить либо переключиться на следующий аккаунт в цепочке. Решает владелец, не код.
  3. Оповещение видно в интерфейсе — в «Состоянии» и в журнале событий. Достаточно ли тоста — решите и обоснуйте.
  4. Переключение обратимо. Квоты восстанавливаются по reset_at; отставленный по порогу аккаунт обязан вернуться в строй сам. Урок A23 уже оплачен: у AUTH_REQUIRED не было выхода, и шесть профилей выпали навсегда. Повторять нельзя.

Данные есть: quota_collector собирает проценты и reset_at, они видны в карточках.

Честность обязательна: порог срабатывает по измеренной квоте. Неизвестная квота («Н/Д») — не повод считать её нулевой и переключаться. Нет данных — так и сказать, поведение не менять.

P0-6. Аудит вторым проходом

Для проверяющего. Список составлен из дефектов, уже проходивших мимо первого прохода.

  1. Выдуманные значения. Находились захардкоженные коды устройства GRK-7842, CDX-9104, запасной коммит fb23bff в манифесте. Здесь особый риск в P0-5: соблазн подставить «разумный» процент при отсутствии данных.
  2. Тесты, закрепляющие дефект. test_headless_server_auth_matrix дважды защищал заглушку: сначала требовал неверный адрес x.ai/device, затем слова «Headless» и «agy», хотя вход через веб уже работал. Новые тесты должны описывать желаемое поведение.
  3. Запустить изменённое. Импорт ничего не доказывает. На днях вложенная функция оказалась не видна части точек вызова и давала NameError внутри обработки успеха — поймал ruff, а не тест.
  4. Кэш состояния. Только что чинилось: учётные данные сохранялись, но refresh(force_scan=False) состояние не обновлял, и подключённый аккаунт не появлялся никогда. Любое изменение состава аккаунтов обязано быть видно сразу, без перезапуска.
  5. Побочные изменения в файлах, которых задание не касалось, — объяснить каждое.
  6. Пропущенный пункт назвать пропущенным.

Ограничения

  • Десктоп (router/ui/**) не трогать: он выводится из обращения.
  • Правило честности без исключений. Нет данных — «Н/Д» и причина.
  • Действия только через существующий action_handler; второй реализации assign_role, save_chain, set_model быть не должно.
  • Меняете контракт — правьте docs/web-api/CONTRACT.md и скажите в отчёте.
  • Конфигурацию владельца литералами не править.
  • Тег v0.1.1 не создавать.

Критерии приёмки

  1. Ветка в origin, git status чист.
  2. Подключается пятый аккаунт одного провайдера; проверено исполнением, вывод в отчёте.
  3. «Аккаунты» показывают только подключённые; при нуле подключённых — внятное пустое состояние, а не 24 пустые карточки.
  4. Аккаунт назначается агенту из «Обзора»; один аккаунт назначается всем шести ролям; изменение доходит до router_profiles.yaml и переживает перезапуск.
  5. «Авто» описано по факту запуска: что делает при одном провайдере, при двух, при нескольких аккаунтах одного провайдера.
  6. Порог настраивается, значение не зашито; при достижении срабатывает выбранное поведение; при неизвестной квоте не срабатывает.
  7. Аккаунт, отставленный по порогу, возвращается в строй после восстановления квоты без ручного вмешательства; проверено тестом.
  8. Изменения состава аккаунтов видны в интерфейсе сразу, без перезапуска.
  9. Ни одного выдуманного значения; проверено отдельно и описано в отчёте.
  10. ruff check . чисто; релизный гейт не ухудшен.
  11. Скриншоты: «Аккаунты» с одним аккаунтом, «Обзор» с назначением, настройка порога.
  12. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed. На main сейчас 432 passed, 2 skipped.

Главное

Владелец хочет управлять аккаунтами, а не слотами: загрузил аккаунты, распределил по агентам, следит за квотами и переставляет, когда они подходят к концу. Всё остальное в задании обслуживает это.

Порядок сдачи

Передать точный FINAL_COMMIT_SHA. Сдано только после появления коммита в origin.