Тринадцать файлов существовали только на диске ПК владельца, в рабочей копии, отставшей от 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>
14 KiB
Задание 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. Эта ветка:
- перебирает зашитые идентификаторы
local-1иlocal-2— профильollama-1не смотрит вообще; - читает учётные данные провайдера
local, а неollama; - по умолчанию идёт на
http://127.0.0.1:8081/v1— это порт llama.cpp, а не Ollama (11434); - дёргает
/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 — это окно отката после ошибки, а не остаток квоты. Отсюда два разных дефекта:
- Любой откат показывается как исчерпание квоты, хотя квота может быть полной.
- Ветка
RATE_LIMITEDпрактически мертва: при активном лимите запросовreset_atвсегда в будущем, поэтому строка 467 срабатывает раньше и лимит запросов выдаёт себя за исчерпанную квоту.
И третье, в health_tracker.py:483: при пустом имени модели или значении default исчерпанным помечается весь аккаунт (record.overall_state). Hermes имя модели передаёт не всегда.
Классификатор в codex_adapter.py:132 ловит подстроку quota в любом месте текста ошибки — проверить, не попадают ли туда сообщения, к квоте не относящиеся.
P0-1. OpenRouter и NVIDIA подключаются по-настоящему
add_accountсохраняет профиль дляopenrouter,nvidia,nvidia-nim: создаёт определение профиля, пишет учётные данные (ключ и адрес), назначает роль — по образцу существующей локальной ветки.- Слоты и роли по умолчанию для обоих провайдеров в
AutoAssigner, как сделано дляollama. - Адреса по умолчанию:
https://openrouter.ai/api/v1иhttps://integrate.api.nvidia.com/v1; владелец может переопределить в мастере. - Ветка с мнимым успехом не должна остаться ловушкой. Провайдер, для которого сохранение не реализовано, обязан получать честный отказ с причиной, а не
ok: True. Это главное требование пункта: молчаливый успех стоил владельцу нескольких попыток подключения.
P0-2. Обнаружение моделей для трёх провайдеров
- OpenRouter: запрос списка моделей по адресу профиля с его ключом.
- NVIDIA: то же самое.
- Ollama — отдельная ветка, не общая с llama.cpp:
- адрес берётся из самого профиля, а не из зашитых
local-1/local-2; - учётные данные читаются для провайдера
ollama; - по умолчанию
http://127.0.0.1:11434; - локальные модели — через нативный
/api/tags; - облачные модели Ollama — отдельный источник, требующий ключа. Выяснить по действующей документации Ollama способ и адрес; не выдумывать эндпоинт. Если способ не подтверждён — так и написать в отчёте, а в интерфейсе показать
Н/Дс причиной.
- адрес берётся из самого профиля, а не из зашитых
- Зашитые идентификаторы профилей убрать везде, включая ветку Codex: перебирать профили провайдера из конфигурации. После A26 идентификаторы выдаются автоматически, и любой зашитый список рано или поздно промахнётся.
- Ошибка обнаружения показывается с текстом ответа сервера. Сейчас
_probe_providerвозвращаетNoneи когда ветки нет, и когда сервер отказал — владелец не может отличить одно от другого.
P0-3. Квота говорит только то, что измерено
- Откат после ошибки — это не исчерпание квоты. Разделить состояния: исчерпание объявлять по измеренному остатку, откат показывать как откат с причиной и временем окончания.
- Порядок веток исправить: лимит запросов не должен выдавать себя за исчерпанную квоту.
- Ошибка без имени модели не помечает весь аккаунт. Помечать конкретное семейство; общий вердикт — только при подтверждении.
- Ярлык называет источник. «Квота исчерпана» — когда есть измерение. Иначе «Откат до HH:MM после ошибки: текст».
- Классификатор Codex проверить на ложные срабатывания подстроки
quota.
P0-4. Проверка исполнением
Заглушек недостаточно, но и ключей владельца у исполнителя нет. Поэтому:
- Сохранение профиля проверить с заведомо неверным ключом: профиль обязан создаться, а проверка подключения — вернуть внятную ошибку авторизации, а не тишину.
- Ollama проверить на живом сервере: локальные модели через
/api/tagsобязаны появиться в списке. - Квота: смоделировать откат после ошибки и убедиться, что интерфейс не пишет «квота исчерпана» при неизмеренной квоте.
- Отказ вместо мнимого успеха проверить отдельно.
P0-5. Аудит вторым проходом
- Искать оставшиеся зашитые идентификаторы профилей по всему коду — это повторяющийся класс дефекта.
- Проверить, что мнимых успехов не осталось: действие, ничего не сохранившее, не возвращает
ok: True. - Эндпоинт облачных моделей Ollama сверить с документацией. Выдуманный адрес — дефект того же рода, что выдуманные метрики в A38.
- Побочные изменения объяснить.
- Пропущенный пункт назвать пропущенным.
Ограничения
- Ключи владельца не запрашивать и в репозиторий не класть.
- Каталог
~/.hermes/agy_profiles/не трогать. - Вёрстку и холст не менять — это A43.
- Версию
0.1.1не поднимать. - Правило честности без исключений: неизмеренное показывать как
Н/Дс причиной.
Критерии приёмки
- Ветка в
origin,git statusчист. - OpenRouter и NVIDIA подключаются: профиль создаётся, учётные данные сохраняются, аккаунт виден в списке; проверено.
- Действие, ничего не сохранившее, возвращает отказ с причиной; проверено.
- Обнаружение моделей работает для openrouter, nvidia и ollama; для Ollama проверено на живом сервере.
- Зашитых идентификаторов профилей в обнаружении не осталось.
- Ошибка обнаружения доходит до интерфейса с текстом.
- Откат после ошибки не показывается как исчерпание квоты; лимит запросов показывается как лимит запросов.
- Ошибка без имени модели не помечает весь аккаунт.
ruff check .чисто; релизный гейт не ухудшен.- Отчёт:
START_HEAD,FINAL_HEAD,origin/main,git status,X passed / Y skipped / Z failed. Наorigin/mainсейчас 491 passed.
Главное
Два провайдера нельзя подключить вовсе, и мастер при этом рапортует об успехе — владелец несколько раз повторял заведомо безрезультатное действие. Третий подключается, но опрашивается по чужому адресу и чужому имени профиля. А Codex объявляется исчерпанным по квоте в тот момент, когда квота не измерена ни разу. Общее у всех четырёх — интерфейс утверждает то, чего не проверял.
Порядок сдачи
Передать точный FINAL_COMMIT_SHA.