hermes-hub/agents/inbox/2026-08-31-A42-provider-connect.md
Hermes Team 8b67f0dadb docs(agents): вернуть в репозиторий постановки A42-A56 и отчёт A30
Тринадцать файлов существовали только на диске ПК владельца, в рабочей
копии, отставшей от origin/main на 122 коммита. Их реализация и тесты
давно влиты: tests/test_a42_provider_connect.py,
test_a49_subagents_skills_memory.py, test_a51_hub_controls_hermes.py,
test_a52_local_models_supervisor_dual.py, test_a55_account_connection.py,
test_a56_context_compression.py и другие. Постановок, объясняющих, что
эти тесты обязаны доказывать, в репозитории не было.

Правило записано в agents/AGENTS.md: задание живёт в репозитории, а не в
переписке и не в личных папках на диске.

A48, A50 и A54 не переносятся: они уже есть на origin под другими именами,
содержимое совпадает с точностью до перевода строки в конце файла.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 18:16:35 +07:00

14 KiB
Raw Permalink Blame History

Задание A42: подключение провайдеров — OpenRouter, NVIDIA, Ollama, квота Codex

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

2026-08-31

База

origin/main (ff303b5) — туда уже слиты правки ревьюера по вебу и A41 (чистая первая установка).

git fetch origin --prune
git checkout -b antigravity/a42-provider-connect origin/main

В main напрямую не пушить.

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

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

Это задание по коду. Вёрстка и холст — отдельное задание A43, туда не залезать.


Задача

Владелец сообщает: «опенроутер не подключается, нвидиа не подключаются, кодекс выдаёт ошибку по квоте, хотя квоты полные, оллама не выдаёт облачные модели».

Причины найдены ревьюером и проверены по коду. Заново их выяснять не нужно — нужно чинить.

Что проверено ревьюером

OpenRouter и NVIDIA реализованы наполовину

adapters/__init__.py      OpenRouterAdapter и NvidiaAdapter в реестре есть
web/static/index.html:163 пункты в списке провайдеров есть
app.js:2482               шаг мастера с полем API-ключа и Base URL есть

action_handler.py:574     add_account сохраняет ТОЛЬКО для
                          (local, local-llm, llama.cpp, ollama, vllm)
                          и только при непустом base_url
action_handler.py:588     для всех остальных возвращается ok=True с текстом
                          «Навигация» — и не сохраняется ничего

То есть мастер докладывает об успехе и не сохраняет ничего. Аккаунт не появляется, потому что его никто не создал.

Дальше по цепочке пусто тоже:

auto_assigner.py:129  слоты объявлены для ollama; openrouter и nvidia отсутствуют
auto_assigner.py:219  роли по умолчанию — то же самое
router_config.py      в конфигурации по умолчанию нет ни одного из трёх
model_discovery_service.py:216  _probe_provider не имеет ветки ни для
                                openrouter, ни для nvidia, и возвращает None

Ollama обнаруживает не то

model_discovery_service.py:325 заводит ollama в одну ветку с local, llama.cpp, vllm. Эта ветка:

  1. перебирает зашитые идентификаторы local-1 и local-2 — профиль ollama-1 не смотрит вообще;
  2. читает учётные данные провайдера local, а не ollama;
  3. по умолчанию идёт на http://127.0.0.1:8081/v1 — это порт llama.cpp, а не Ollama (11434);
  4. дёргает /v1/models и ничего не знает про облачные модели Ollama.

Скриншот владельца: «Список моделей ещё не получен от провайдера ollama» при подключённом ollama-1.

Та же болезнь рядом: ветка Codex перебирает зашитые codex-orch, codex-worker-1, codex-worker-2. После A26 идентификаторы выдаются автоматически (codex-4, codex-5), и такой профиль обнаружение пропустит.

«Квота исчерпана» при полной квоте

На скриншоте у Codex значок «Квота исчерпана», а Session и Weekly показывают Н. То есть вердикт об исчерпании выносится там, где квота не измерена вовсе.

unified_health.py:467   ветка: max_cd > 0 либо overall_state == QUOTA_EXHAUSTED
                        → health_state = STATUS_QUOTA_EXHAUSTED
unified_health.py:470   ветка RATE_LIMITED идёт НИЖЕ

max_cd берётся из frec.reset_at > now — это окно отката после ошибки, а не остаток квоты. Отсюда два разных дефекта:

  1. Любой откат показывается как исчерпание квоты, хотя квота может быть полной.
  2. Ветка RATE_LIMITED практически мертва: при активном лимите запросов reset_at всегда в будущем, поэтому строка 467 срабатывает раньше и лимит запросов выдаёт себя за исчерпанную квоту.

И третье, в health_tracker.py:483: при пустом имени модели или значении default исчерпанным помечается весь аккаунт (record.overall_state). Hermes имя модели передаёт не всегда.

Классификатор в codex_adapter.py:132 ловит подстроку quota в любом месте текста ошибки — проверить, не попадают ли туда сообщения, к квоте не относящиеся.


P0-1. OpenRouter и NVIDIA подключаются по-настоящему

  1. add_account сохраняет профиль для openrouter, nvidia, nvidia-nim: создаёт определение профиля, пишет учётные данные (ключ и адрес), назначает роль — по образцу существующей локальной ветки.
  2. Слоты и роли по умолчанию для обоих провайдеров в AutoAssigner, как сделано для ollama.
  3. Адреса по умолчанию: https://openrouter.ai/api/v1 и https://integrate.api.nvidia.com/v1; владелец может переопределить в мастере.
  4. Ветка с мнимым успехом не должна остаться ловушкой. Провайдер, для которого сохранение не реализовано, обязан получать честный отказ с причиной, а не ok: True. Это главное требование пункта: молчаливый успех стоил владельцу нескольких попыток подключения.

P0-2. Обнаружение моделей для трёх провайдеров

  1. OpenRouter: запрос списка моделей по адресу профиля с его ключом.
  2. NVIDIA: то же самое.
  3. Ollama — отдельная ветка, не общая с llama.cpp:
    • адрес берётся из самого профиля, а не из зашитых local-1/local-2;
    • учётные данные читаются для провайдера ollama;
    • по умолчанию http://127.0.0.1:11434;
    • локальные модели — через нативный /api/tags;
    • облачные модели Ollama — отдельный источник, требующий ключа. Выяснить по действующей документации Ollama способ и адрес; не выдумывать эндпоинт. Если способ не подтверждён — так и написать в отчёте, а в интерфейсе показать Н с причиной.
  4. Зашитые идентификаторы профилей убрать везде, включая ветку Codex: перебирать профили провайдера из конфигурации. После A26 идентификаторы выдаются автоматически, и любой зашитый список рано или поздно промахнётся.
  5. Ошибка обнаружения показывается с текстом ответа сервера. Сейчас _probe_provider возвращает None и когда ветки нет, и когда сервер отказал — владелец не может отличить одно от другого.

P0-3. Квота говорит только то, что измерено

  1. Откат после ошибки — это не исчерпание квоты. Разделить состояния: исчерпание объявлять по измеренному остатку, откат показывать как откат с причиной и временем окончания.
  2. Порядок веток исправить: лимит запросов не должен выдавать себя за исчерпанную квоту.
  3. Ошибка без имени модели не помечает весь аккаунт. Помечать конкретное семейство; общий вердикт — только при подтверждении.
  4. Ярлык называет источник. «Квота исчерпана» — когда есть измерение. Иначе «Откат до HH:MM после ошибки: текст».
  5. Классификатор Codex проверить на ложные срабатывания подстроки quota.

P0-4. Проверка исполнением

Заглушек недостаточно, но и ключей владельца у исполнителя нет. Поэтому:

  1. Сохранение профиля проверить с заведомо неверным ключом: профиль обязан создаться, а проверка подключения — вернуть внятную ошибку авторизации, а не тишину.
  2. Ollama проверить на живом сервере: локальные модели через /api/tags обязаны появиться в списке.
  3. Квота: смоделировать откат после ошибки и убедиться, что интерфейс не пишет «квота исчерпана» при неизмеренной квоте.
  4. Отказ вместо мнимого успеха проверить отдельно.

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

  1. Искать оставшиеся зашитые идентификаторы профилей по всему коду — это повторяющийся класс дефекта.
  2. Проверить, что мнимых успехов не осталось: действие, ничего не сохранившее, не возвращает ok: True.
  3. Эндпоинт облачных моделей Ollama сверить с документацией. Выдуманный адрес — дефект того же рода, что выдуманные метрики в A38.
  4. Побочные изменения объяснить.
  5. Пропущенный пункт назвать пропущенным.

Ограничения

  • Ключи владельца не запрашивать и в репозиторий не класть.
  • Каталог ~/.hermes/agy_profiles/ не трогать.
  • Вёрстку и холст не менять — это A43.
  • Версию 0.1.1 не поднимать.
  • Правило честности без исключений: неизмеренное показывать как Н с причиной.

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

  1. Ветка в origin, git status чист.
  2. OpenRouter и NVIDIA подключаются: профиль создаётся, учётные данные сохраняются, аккаунт виден в списке; проверено.
  3. Действие, ничего не сохранившее, возвращает отказ с причиной; проверено.
  4. Обнаружение моделей работает для openrouter, nvidia и ollama; для Ollama проверено на живом сервере.
  5. Зашитых идентификаторов профилей в обнаружении не осталось.
  6. Ошибка обнаружения доходит до интерфейса с текстом.
  7. Откат после ошибки не показывается как исчерпание квоты; лимит запросов показывается как лимит запросов.
  8. Ошибка без имени модели не помечает весь аккаунт.
  9. ruff check . чисто; релизный гейт не ухудшен.
  10. Отчёт: START_HEAD, FINAL_HEAD, origin/main, git status, X passed / Y skipped / Z failed. На origin/main сейчас 491 passed.

Главное

Два провайдера нельзя подключить вовсе, и мастер при этом рапортует об успехе — владелец несколько раз повторял заведомо безрезультатное действие. Третий подключается, но опрашивается по чужому адресу и чужому имени профиля. А Codex объявляется исчерпанным по квоте в тот момент, когда квота не измерена ни разу. Общее у всех четырёх — интерфейс утверждает то, чего не проверял.

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

Передать точный FINAL_COMMIT_SHA.