Проверка кандидата A28-A31 в браузере вскрыла блокирующую регрессию: при
переписывании клиента в A29 функции удалили, а вызовы в разметке оставили.
Консоль на живой сборке:
openAddAccountWizard is not defined «+ Добавить аккаунт» не работает
checkUpdates is not defined падает при каждой загрузке
handleNodeAccountChange не сменить аккаунт у агента
handleNodeModelChange не сменить модель
handleRefreshProviderModels не обновить список моделей
Подключить аккаунт в новой сборке невозможно, назначить агенту тоже. При этом
startDeviceAuth и startRedirectAuth в коде остались, но не вызываются ниоткуда.
A34 собирает в один порядок: восстановление подключения (блокирует остальное),
адаптеры OpenRouter и NVIDIA с несколькими аккаунтами, интерфейс автопоиска
локальных серверов поверх готовой серверной части, и удаление десктопа по A32.
Задание опирается на ветку review/a28-a31-fixes, где лежат исправления
ревьюера, и перечисляет их отдельным разделом, чтобы не переделывались.
A32 добавлен в репозиторий: он был написан ранее, но остался только локально.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17 KiB
Задание A34: восстановить подключение аккаунтов, добавить OpenRouter и NVIDIA, удалить десктоп
Дата поступления
2026-08-30
База
Работать поверх ветки ревьюера review/a28-a31-fixes (529192b), а не поверх main и не поверх своей прошлой ветки. В ней уже лежат A28–A31, слитые с main, плюс исправления ревьюера.
git fetch origin --prune
git checkout -b antigravity/a34-restore-and-providers origin/review/a28-a31-fixes
В main напрямую не пушить. В конце — push, git log --oneline -1, git status чистый.
Порядок исполнения
Два прохода: Flash реализует, Pro проводит аудит. Пункт P0-6 написан для аудитора.
Пункты выполняются по порядку. P0-1 блокирует всё остальное: пока нельзя подключить аккаунт, ни новых провайдеров, ни автопоиска проверить не на чем.
Что уже сделано ревьюером — не переделывать
Снято исполнением на кандидате A28–A31 и исправлено в 529192b:
- Дублирование ролей.
RoleRegistry.migrate_legacy_rolesсуществовала, но не вызывалась ниоткуда; интерфейс показывал 19 агентов вместо 13, шесть пар неотличимы по названию. Миграция подключена, порядок обработки исправлен, цепочки владельца сохраняются. Проверено на его живой конфигурации: 19 → 13, цепочки совпадают. - Сохранённый workflow мигрируется вместе с ролями, иначе рёбра ссылались на исчезнувших агентов.
- Поиск локальных серверов — новый модуль
router/local_discovery.pyи действиеdiscover_local_models. Серверная часть готова и проверена; не хватает только интерфейса (P0-3). - Глобальный мьютекс Antigravity снят ранее (
7e83c38): три параллельных вызова занимали 3.01 с, стали 1.00 с. Возвращать нельзя, есть тест. - CORS закрыт по умолчанию (
c35bc48). Список источников — настройкаweb_api_allowed_origins.
P0-1. Восстановить подключение аккаунтов — блокирующее
При переписывании клиента в A29 функции удалили, а вызовы оставили. Проверено в браузере на живом кандидате, консоль:
openAddAccountWizard is not defined ← «+ Добавить аккаунт» ничего не делает
checkUpdates is not defined ← падает при каждой загрузке страницы
Полный список повисших обработчиков — определений 0, вызовы есть:
openAddAccountWizard нельзя подключить аккаунт
handleNodeAccountChange нельзя сменить аккаунт у агента в «Обзоре»
handleNodeModelChange нельзя сменить модель
handleRefreshProviderModels нельзя обновить список моделей
checkUpdates проверка обновлений падает на загрузке
При этом startDeviceAuth и startRedirectAuth в коде остались и работают, но не вызываются ниоткуда — стали мёртвыми. Их надо не писать заново, а связать с восстановленным мастером.
Требуется вернуть работоспособность каждому пункту списка. Действия на сервере существуют и менять их не нужно:
add_account, start_device_auth, poll_device_auth,
start_redirect_auth, submit_redirect_callback, poll_redirect_auth,
assign_role, set_model, refresh_models, check_updates
Что мастер обязан уметь, по провайдерам:
- Grok, OpenAI Codex — код устройства. Адрес и код приходят от провайдера, подставлять свои нельзя.
- Antigravity, Claude — вход по ссылке с возвратом. Ссылку можно открыть на любой машине. Принимается и полный адрес возврата, и один только код. При работе с другой машины показывается готовая команда проброса порта возврата.
- Локальный сервер — адрес и необязательный ключ, плюс автопоиск из P0-3.
- Выбор слота обязателен и делается владельцем. Автоподбор ошибается:
find_free_slotопределяет занятость по файлу учётных данных, аagyна Windows держит их в keyring, поэтому все слоты выглядят свободными и всегда возвращается первый. Вход затирал бы работающий аккаунт. В списке слотов видно, какие заняты и кем, и участвует ли слот в маршрутизации.
Проверять исполнением, а не глазами. Откройте страницу, нажмите каждую кнопку, посмотрите консоль. Ни одного ReferenceError при загрузке и при работе.
P0-2. OpenRouter и NVIDIA, аккаунтов по несколько
Владелец подключил их в Hermes напрямую, мимо хаба: «главный кодекс стоит, подключил себе нвидеа и опенроутер и грок». Хаб их не видит — адаптеров нет, упоминаний в коде нет вовсе.
Оба OpenAI-совместимы, поэтому образец есть: adapters/local_adapter.py и adapters/deepseek_adapter.py работают ровно так же — POST {base_url}/chat/completions, GET {base_url}/models.
- Адаптеры
openrouterиnvidia. Базовый адрес — настройка, не константа. Для OpenRouter этоhttps://openrouter.ai/api/v1, у NVIDIA свой; но зашивать нельзя, владелец может использовать прокси. - Несколько аккаунтов на провайдера, без потолка. Потолок в A26 уже снят:
find_free_slotвыдаёт идентификаторы сама, когда предопределённые кончились (codex-4,codex-5). Сделать так же. - Ключ вводится в мастере и хранится там же, где ключи прочих провайдеров. В снапшот, в журнал и в
/api/settingsон попадать не должен — тест на это уже есть. - Обнаружение моделей через
GET /models. У OpenRouter список большой; показывать надо тот, что вернул провайдер, а не подмножество из головы. - Квоты. OpenRouter отдаёт остаток кредитов, у NVIDIA свои лимиты. Отдаёт — показывать; не отдаёт — «Н/Д» с причиной, а не ноль и не пустая полоса, которую можно принять за исчерпание.
- Логотипы провайдеров у владельца есть в каталоге с макетами. Файла нет — нейтральная заглушка, а не чужой знак.
P0-3. Автопоиск локальных моделей в интерфейсе
Серверная часть готова ревьюером, писать её заново не нужно.
router/local_discovery.py discover_local_servers()
action_handler действие discover_local_models
Опрашивает Ollama 11434, LM Studio 1234, llama.cpp 8080–8082, vLLM 8000, Jan, GPT4All, Text Generation WebUI — параллельно, девять портов за 1.5 с. Возвращает только ответившие, со списком моделей от самого сервера.
Требуется кнопка «Найти на этом компьютере» в шаге подключения локального провайдера:
- Нажатие — опрос, показ найденного: имя сервера, адрес, список моделей.
- Выбор найденного заполняет адрес; вводить руками по-прежнему можно.
- Ничего не найдено — так и сказать, с подсказкой запустить Ollama, LM Studio или llama.cpp либо ввести адрес вручную. Пустой список это результат, а не ошибка.
- Порт, занятый чужим сервисом, показывается с причиной — иначе владелец будет гадать, почему заведомо работающий сервер не виден.
- Опрос идёт в фоне, интерфейс не блокируется.
Учесть: хаб может работать на сервере, а браузер у владельца на другой машине. Поиск идёт там, где работает хаб, и это надо сказать в интерфейсе прямо, иначе результат будет непонятен.
P0-4. Удаление десктопа (задание A32 целиком)
Выполняется после P0-1: пока веб не подключает аккаунты, удалять десктоп нельзя.
Полный текст — agents/inbox/2026-08-25-A32-remove-desktop.md, здесь коротко:
router/ui/** 20 файлов, ~6 910 строк
hermes_hub_app.py ~1 345 строк, CustomTkinter
cli_commands.py:481 команда запуска десктопа
HermesHubSetup.cs:575 ярлык «Hermes Hub (Desktop).lnk»
HermesHubSetup.cs:140 проверка зависимостей ТРЕБУЕТ customtkinter
pyproject.toml:40 customtkinter>=6.0.0
Сначала таблица паритета «умение десктопа → где в вебе → проверено», и только потом удаление. Непокрытое умение не удалять, а назвать в отчёте.
Отдельно: в b4ae08e появился обход «GUI helpers importable without customtkinter». После удаления десктопа эта прослойка не нужна — снять её, а не оставлять.
Обновление пойдёт поверх установок с десктопом на трёх машинах владельца: старый ярлык обязан убираться, учётные данные, настройки и цепочки ролей — уцелеть.
P0-5. Проверка на живой установке
- Собрать оба установщика, поставить на Windows и на Linux.
- Подключить хотя бы по одному аккаунту каждого потока: код устройства, вход по ссылке, локальный сервер.
- Разложить аккаунты по ролям и убедиться, что порядок переживает перезапуск.
- Проверить обновление поверх старой установки.
P0-6. Аудит вторым проходом
- Повисшие вызовы. Собрать все
onclick/onchangeи убедиться, что каждая функция определена. Именно этот класс дефекта и пропустили в A29: разметка звала пять функций, которых нет. - Консоль браузера чистая при загрузке и при работе.
- Выдуманные значения. Особый риск в P0-2: квоты и списки моделей новых провайдеров. Ни одного числа, которого не дал провайдер.
- Ключи не утекают в снапшот, журнал и
/api/settings. - Мьютекс Antigravity не вернулся — есть тест, он должен проходить.
- Побочные изменения объяснить.
- Пропущенный пункт назвать пропущенным.
Ограничения
- Не переделывать то, что перечислено в разделе «сделано ревьюером».
- Без сборки, без npm, без фреймворка — решение обосновано в контракте.
- Действия только через
action_handler; новые — с правкойdocs/web-api/CONTRACT.md. - Правило честности без исключений: нет данных — «Н/Д» и причина.
- Тег
v0.1.1не создавать.
Критерии приёмки
- Ветка в
originотreview/a28-a31-fixes,git statusчист. - В консоли браузера нет
ReferenceErrorни при загрузке, ни при работе; все обработчики определены — проверено списком. - Аккаунт подключается всеми тремя потоками; слот выбирает владелец, занятые видны.
- Аккаунт назначается агенту и меняется модель — из «Обзора» и из «Маршрутизации»; переживает перезапуск.
- OpenRouter и NVIDIA подключаются, аккаунтов больше трёх на провайдера; ключи не утекают; модели берутся у провайдера.
- Квоты новых провайдеров показаны настоящие либо «Н/Д» с причиной.
- Кнопка автопоиска находит запущенные локальные серверы; пустой результат объяснён; чужой сервис на порту назван с причиной.
router/ui/**иhermes_hub_app.pyудалены,customtkinterиз зависимостей убран, ярлык один; обновление поверх старой установки сохраняет данные.- Таблица паритета приложена.
ruff check .чисто; релизный гейт не ухудшен.- Скриншоты: мастер на каждом из трёх потоков, автопоиск локальных, «Обзор» с назначением аккаунта, «Маршрутизация».
- Отчёт:
START_HEAD,FINAL_HEAD,origin/main,git status,X passed / Y skipped / Z failed. На ветке ревьюера сейчас 475 passed, 2 skipped.
Главное
Сейчас в новой сборке нельзя подключить ни одного аккаунта и нельзя назначить его агенту — разметка зовёт пять функций, которых в коде нет. Всё остальное в задании бессмысленно, пока это не восстановлено.
Порядок сдачи
Передать точный FINAL_COMMIT_SHA. Сдано только после появления коммита в origin.