hermes-hub/agents/inbox/2026-08-30-A34-restore-wizard-providers-desktop.md
Hermes Team 1b03f03ea5 docs(agents): задания A32 и A34 — восстановление подключения аккаунтов, OpenRouter и NVIDIA, удаление десктопа
Проверка кандидата 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>
2026-08-30 20:48:11 +07:00

17 KiB
Raw Permalink Blame History

Задание A34: восстановить подключение аккаунтов, добавить OpenRouter и NVIDIA, удалить десктоп

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

2026-08-30

База

Работать поверх ветки ревьюера review/a28-a31-fixes (529192b), а не поверх main и не поверх своей прошлой ветки. В ней уже лежат A28A31, слитые с 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 блокирует всё остальное: пока нельзя подключить аккаунт, ни новых провайдеров, ни автопоиска проверить не на чем.


Что уже сделано ревьюером — не переделывать

Снято исполнением на кандидате A28A31 и исправлено в 529192b:

  1. Дублирование ролей. RoleRegistry.migrate_legacy_roles существовала, но не вызывалась ниоткуда; интерфейс показывал 19 агентов вместо 13, шесть пар неотличимы по названию. Миграция подключена, порядок обработки исправлен, цепочки владельца сохраняются. Проверено на его живой конфигурации: 19 → 13, цепочки совпадают.
  2. Сохранённый workflow мигрируется вместе с ролями, иначе рёбра ссылались на исчезнувших агентов.
  3. Поиск локальных серверов — новый модуль router/local_discovery.py и действие discover_local_models. Серверная часть готова и проверена; не хватает только интерфейса (P0-3).
  4. Глобальный мьютекс Antigravity снят ранее (7e83c38): три параллельных вызова занимали 3.01 с, стали 1.00 с. Возвращать нельзя, есть тест.
  5. 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.

  1. Адаптеры openrouter и nvidia. Базовый адрес — настройка, не константа. Для OpenRouter это https://openrouter.ai/api/v1, у NVIDIA свой; но зашивать нельзя, владелец может использовать прокси.
  2. Несколько аккаунтов на провайдера, без потолка. Потолок в A26 уже снят: find_free_slot выдаёт идентификаторы сама, когда предопределённые кончились (codex-4, codex-5). Сделать так же.
  3. Ключ вводится в мастере и хранится там же, где ключи прочих провайдеров. В снапшот, в журнал и в /api/settings он попадать не должен — тест на это уже есть.
  4. Обнаружение моделей через GET /models. У OpenRouter список большой; показывать надо тот, что вернул провайдер, а не подмножество из головы.
  5. Квоты. OpenRouter отдаёт остаток кредитов, у NVIDIA свои лимиты. Отдаёт — показывать; не отдаёт — «Н/Д» с причиной, а не ноль и не пустая полоса, которую можно принять за исчерпание.
  6. Логотипы провайдеров у владельца есть в каталоге с макетами. Файла нет — нейтральная заглушка, а не чужой знак.

P0-3. Автопоиск локальных моделей в интерфейсе

Серверная часть готова ревьюером, писать её заново не нужно.

router/local_discovery.py     discover_local_servers()
action_handler                действие discover_local_models

Опрашивает Ollama 11434, LM Studio 1234, llama.cpp 80808082, vLLM 8000, Jan, GPT4All, Text Generation WebUI — параллельно, девять портов за 1.5 с. Возвращает только ответившие, со списком моделей от самого сервера.

Требуется кнопка «Найти на этом компьютере» в шаге подключения локального провайдера:

  1. Нажатие — опрос, показ найденного: имя сервера, адрес, список моделей.
  2. Выбор найденного заполняет адрес; вводить руками по-прежнему можно.
  3. Ничего не найдено — так и сказать, с подсказкой запустить Ollama, LM Studio или llama.cpp либо ввести адрес вручную. Пустой список это результат, а не ошибка.
  4. Порт, занятый чужим сервисом, показывается с причиной — иначе владелец будет гадать, почему заведомо работающий сервер не виден.
  5. Опрос идёт в фоне, интерфейс не блокируется.

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

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. Проверка на живой установке

  1. Собрать оба установщика, поставить на Windows и на Linux.
  2. Подключить хотя бы по одному аккаунту каждого потока: код устройства, вход по ссылке, локальный сервер.
  3. Разложить аккаунты по ролям и убедиться, что порядок переживает перезапуск.
  4. Проверить обновление поверх старой установки.

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

  1. Повисшие вызовы. Собрать все onclick/onchange и убедиться, что каждая функция определена. Именно этот класс дефекта и пропустили в A29: разметка звала пять функций, которых нет.
  2. Консоль браузера чистая при загрузке и при работе.
  3. Выдуманные значения. Особый риск в P0-2: квоты и списки моделей новых провайдеров. Ни одного числа, которого не дал провайдер.
  4. Ключи не утекают в снапшот, журнал и /api/settings.
  5. Мьютекс Antigravity не вернулся — есть тест, он должен проходить.
  6. Побочные изменения объяснить.
  7. Пропущенный пункт назвать пропущенным.

Ограничения

  • Не переделывать то, что перечислено в разделе «сделано ревьюером».
  • Без сборки, без npm, без фреймворка — решение обосновано в контракте.
  • Действия только через action_handler; новые — с правкой docs/web-api/CONTRACT.md.
  • Правило честности без исключений: нет данных — «Н/Д» и причина.
  • Тег v0.1.1 не создавать.

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

  1. Ветка в origin от review/a28-a31-fixes, git status чист.
  2. В консоли браузера нет ReferenceError ни при загрузке, ни при работе; все обработчики определены — проверено списком.
  3. Аккаунт подключается всеми тремя потоками; слот выбирает владелец, занятые видны.
  4. Аккаунт назначается агенту и меняется модель — из «Обзора» и из «Маршрутизации»; переживает перезапуск.
  5. OpenRouter и NVIDIA подключаются, аккаунтов больше трёх на провайдера; ключи не утекают; модели берутся у провайдера.
  6. Квоты новых провайдеров показаны настоящие либо «Н/Д» с причиной.
  7. Кнопка автопоиска находит запущенные локальные серверы; пустой результат объяснён; чужой сервис на порту назван с причиной.
  8. router/ui/** и hermes_hub_app.py удалены, customtkinter из зависимостей убран, ярлык один; обновление поверх старой установки сохраняет данные.
  9. Таблица паритета приложена.
  10. ruff check . чисто; релизный гейт не ухудшен.
  11. Скриншоты: мастер на каждом из трёх потоков, автопоиск локальных, «Обзор» с назначением аккаунта, «Маршрутизация».
  12. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed. На ветке ревьюера сейчас 475 passed, 2 skipped.

Главное

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

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

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