Добавление провайдеров
Hermes уже умеет работать с любым OpenAI-совместимым эндпоинтом через путь кастомного провайдера. Заводить встроенный провайдер стоит только ради первоклассного UX для конкретного сервиса:
- специфичная авторизация или обновление токена
- курированный каталог моделей
- записи в меню
hermes modelи мастере установки - псевдонимы провайдера для синтаксиса
provider:model - нестандартная форма API, под которую нужен адаптер
Если провайдер — просто «ещё один OpenAI-совместимый base URL и API-ключ», именованного кастомного провайдера будет достаточно.
Ментальная модель
Встроенный провайдер должен сойтись на нескольких уровнях:
hermes_cli/auth.py— определяет, как находятся учётные данные.hermes_cli/runtime_provider.py— превращает их в данные рантайма:providerapi_modebase_urlapi_keysource
run_agent.pyсмотрит наapi_mode, чтобы решить, как строить и отправлять запросы.hermes_cli/models.pyиhermes_cli/main.pyделают провайдер видимым в CLI. (hermes_cli/setup.pyделегирует всёmain.pyавтоматически — менять его не нужно.)agent/auxiliary_client.pyиagent/model_metadata.pyотвечают за работу побочных задач и бюджетирование токенов.
Главная абстракция здесь — api_mode.
- Большинство провайдеров используют
chat_completions. - У Codex это
codex_responses. - У Anthropic —
anthropic_messages. - Новый не-OpenAI-протокол, как правило, означает новый адаптер и новый бранч
api_mode.
Сначала выберите путь реализации
Путь A — OpenAI-совместимый провайдер
Берите его, когда провайдер принимает стандартные chat-completions запросы.
Типичный объём работы:
- добавить метаданные авторизации
- добавить каталог моделей / псевдонимы
- добавить резолвинг рантайма
- подключить CLI-меню
- задать дефолты aux-модели
- написать тесты и пользовательскую документацию
Новый адаптер или новый api_mode тут обычно не нужны.
Путь B — Нативный провайдер
Берите его, когда провайдер не ведёт себя как OpenAI chat completions.
Примеры, уже реализованные в репозитории:
codex_responsesanthropic_messages
Этот путь включает всё из Пути A плюс:
- адаптер провайдера в
agent/ - бранчи в
run_agent.pyдля построения запросов, диспатча, извлечения usage, обработки прерываний и нормализации ответов - тесты адаптера
Чеклист файлов
Обязательно для каждого встроенного провайдера
hermes_cli/auth.pyhermes_cli/models.pyhermes_cli/runtime_provider.pyhermes_cli/main.pyagent/auxiliary_client.pyagent/model_metadata.py- тесты
- пользовательская документация в
website/docs/
hermes_cli/setup.py править не нужно. Мастер установки делегирует выбор провайдера и модели функции select_provider_and_model() из main.py — любой добавленный туда провайдер автоматически доступен в hermes setup.
Дополнительно для нативных / не-OpenAI провайдеров
agent/<provider>_adapter.pyrun_agent.pypyproject.toml, если нужен SDK провайдера
Быстрый путь: простые провайдеры с API-ключом
Если ваш провайдер — это просто OpenAI-совместимый эндпоинт, который аутентифицируется одним API-ключом, трогать auth.py, runtime_provider.py, main.py и прочие файлы из полного чеклиста не придётся.
Достаточно двух шагов:
- Создать директорию плагина в
plugins/model-providers/<your-provider>/, а в ней:__init__.py— вызываетregister_provider(profile)на уровне модуляplugin.yaml— манифест (name, kind: model-provider, version, description)
- Всё. Плагины провайдеров подгружаются сами при первом вызове
get_provider_profile()илиlist_providers()— подхватываются и встроенные плагины (этого репозитория), и пользовательские из$HERMES_HOME/plugins/model-providers/.
Как только плагин вызывает register_provider(), само собой подключается следующее:
- Запись
PROVIDER_REGISTRYвauth.py(резолвинг учётных данных, поиск переменных окружения) api_modeвыставляется вchat_completionsbase_urlберётся из конфига или объявленной переменной окруженияenv_varsпроверяются для API-ключа в порядке приоритета- Список
fallback_modelsрегистрируется за провайдером - Флаг
--providerCLI принимает id провайдера - Меню
hermes modelвключает провайдер - Мастер
hermes setupделегирует выборmain.pyавтоматически - Синтаксис псевдонима
provider:modelработает - Резолвер рантайма возвращает корректные
base_urlиapi_key - Флаг
--provider <name>CLI принимает id провайдера - Активация резервной модели чисто переключается на провайдер
Пользовательские плагины в $HERMES_HOME/plugins/model-providers/<name>/ переопределяют встроенные плагины с тем же именем (в register_provider() побеждает последний записавший) — поэтому сторонний разработчик может пропатчить или заменить любой встроенный профиль, не трогая репозиторий.
Смотрите plugins/model-providers/nvidia/ или plugins/model-providers/gmi/ как шаблон, а за описанием полей, идиомами хуков и сквозными примерами — полное руководство по плагину Model Provider.
Полный путь: OAuth и сложные провайдеры
Полный чеклист ниже нужен, когда провайдеру требуется хотя бы что-то из этого:
- OAuth или обновление токена (Nous Portal, Codex, Google Gemini, Qwen Portal, Copilot)
- нестандартная форма API, под которую нужен новый адаптер (Anthropic Messages, Codex Responses)
- кастомное определение эндпоинта или мультирегиональное зондирование (z.ai, Kimi)
- курированный статический каталог моделей или динамическая выборка через
/models - собственные записи
hermes modelс уникальными флоу авторизации
Шаг 1: Выберите единственный канонический id провайдера
Возьмите один id и используйте его везде.
Примеры из репозитория:
openai-codexkimi-codingminimax-cn
Тот же id должен фигурировать в:
PROVIDER_REGISTRYвhermes_cli/auth.py_PROVIDER_LABELSвhermes_cli/models.py_PROVIDER_ALIASESвhermes_cli/auth.pyиhermes_cli/models.py- choices флага
--providerвhermes_cli/main.py - бранчах выбора модели и мастера установки
- дефолтах aux-модели
- тестах
Разойдись id между этими файлами — и провайдер окажется подключён наполовину: авторизация работает, а /model, мастер установки или резолвинг рантайма молча его пропускают.
Шаг 2: Добавьте метаданные авторизации в hermes_cli/auth.py
Для провайдеров с API-ключом добавьте в PROVIDER_REGISTRY запись ProviderConfig:
idnameauth_type="api_key"inference_base_urlapi_key_env_vars- опциональный
base_url_env_var
И добавьте псевдонимы в _PROVIDER_ALIASES.
Готовые провайдеры подскажут шаблон:
- простой путь с API-ключом: Z.AI, MiniMax
- путь с API-ключом и определением эндпоинта: Kimi, Z.AI
- нативный резолвинг токена: Anthropic
- путь через OAuth / auth-store: Nous, OpenAI Codex
На этом этапе ответьте на несколько вопросов:
- Какие переменные окружения проверяет Hermes и в каком порядке приоритета?
- Нужны ли провайдеру переопределения base URL?
- Требуется ли зондирование эндпоинта или обновление токена?
- Что скажет ошибка авторизации, когда учётных данных нет?
Если провайдеру мало «найти API-ключ», заведите для него отдельный резолвер учётных данных, а не размазывайте логику по несвязанным бранчам.
Шаг 3: Добавьте каталог моделей и псевдонимы в hermes_cli/models.py
Обновите каталог провайдера, чтобы он заработал в меню и в синтаксисе provider:model.
Типичные правки:
_PROVIDER_MODELS_PROVIDER_LABELS_PROVIDER_ALIASES- порядок отображения провайдера внутри
list_available_providers() provider_model_ids(), если провайдер поддерживает динамическую выборку через/models
Когда провайдер отдаёт живой список моделей, отдайте предпочтение ему, а _PROVIDER_MODELS оставьте статическим фолбэком.
Этот же файл делает рабочими такие входные данные:
anthropic:claude-sonnet-4-6
kimi:model-name
Без псевдонимов здесь провайдер авторизуется как надо, но на парсинге /model всё сломается.
Шаг 4: Резолвинг данных рантайма в hermes_cli/runtime_provider.py
resolve_runtime_provider() — общий путь для CLI, шлюза, cron, ACP и вспомогательных клиентов.
Добавьте бранч, который возвращает словарь как минимум с такими полями:
{
"provider": "your-provider",
"api_mode": "chat_completions", # или ваш нативный режим
"base_url": "https://...",
"api_key": "...",
"source": "env|portal|auth-store|explicit",
"requested_provider": requested_provider,
}
У OpenAI-совместимого провайдера api_mode обычно так и остаётся chat_completions.
С приоритетом API-ключей будьте аккуратны. В Hermes уже есть логика, которая не даёт ключу OpenRouter утечь на посторонние эндпоинты. Новый провайдер должен так же чётко понимать, какой ключ к какому base URL.
Шаг 5: Подключите CLI в hermes_cli/main.py
Пока провайдер не появится в интерактивном флоу hermes model, обнаружить его не получится.
Обновите в hermes_cli/main.py:
- словарь
provider_labels - список
providersвselect_provider_and_model() - диспатч провайдера (
if selected_provider == ...) - choices аргумента
--provider - choices login/logout, если провайдер поддерживает эти флоу
- функцию
_model_flow_<provider>()либо переиспользуйте_model_flow_api_key_provider(), если она подходит
hermes_cli/setup.py менять не нужно — он вызывает select_provider_and_model() из main.py, поэтому новый провайдер сам появляется и в hermes model, и в hermes setup.
Шаг 6: Поддержите работу вспомогательных вызовов
Здесь важны два файла.
agent/auxiliary_client.py
Добавьте дешёвую и быструю дефолтную aux-модель в _API_KEY_PROVIDER_AUX_MODELS, если это прямой провайдер с API-ключом.
К вспомогательным задачам относятся:
- суммаризация vision
- суммаризация извлечённого веб-контента
- суммаризация для сжатия контекста
- суммаризация поиска по сессии
- сбросы памяти
Нет разумного дефолта aux-модели — и побочные задачи либо неудачно свалятся в фолбэк, либо внезапно потянут дорогую основную модель.
agent/model_metadata.py
Пропишите длины контекста для моделей провайдера, чтобы бюджетирование токенов, пороги сжатия и лимиты оставались вменяемыми.
Шаг 7: Если провайдер нативный — добавьте адаптер и поддержку в run_agent.py
Когда провайдер не сводится к обычным chat completions, изолируйте специфичную логику в agent/<provider>_adapter.py.
Задача run_agent.py — оркестрация. Он должен звать хелперы адаптера, а не собирать payload провайдера руками по всему файлу.
Нативному провайдеру обычно нужна работа в таких местах.
Новый файл адаптера
Типичные обязанности:
- построить SDK / HTTP-клиент
- резолвить токены
- конвертировать сообщения в OpenAI-стиле в формат запроса провайдера
- при необходимости конвертировать схемы инструментов
- нормализовать ответы провайдера обратно в то, что ждёт
run_agent.py - извлекать данные usage и finish-reason
run_agent.py
Найдите api_mode и пройдитесь по каждой точке переключения. Как минимум убедитесь:
__init__выбирает новыйapi_mode- конструирование клиента работает для провайдера
_build_api_kwargs()знает, как форматировать запросы_interruptible_api_call()диспатчит на правильный вызов клиента- пути прерывания / перестройки клиента работают
- валидация ответа принимает форму провайдера
- finish-reason извлекается корректно
- использование токенов извлекается корректно
- активация резервной модели чисто переключается на новый провайдер
- пути суммаризации и сброса памяти всё ещё работают
Заодно найдите в run_agent.py все self.client.. Любой путь кода, который рассчитывает на стандартный клиент OpenAI, сломается, если нативный провайдер заводит другой объект клиента или self.client = None.
Кэширование промптов и специфичные для провайдера поля запросов
Кэширование промптов и провайдерские настройки легко поломать регрессией.
Примеры, уже реализованные в репозитории:
- у Anthropic есть нативный путь кэширования промптов
- OpenRouter получает поля маршрутизации провайдера
- не каждому провайдеру стоит слать каждую опцию на стороне запроса
Добавляя нативный провайдер, перепроверьте: Hermes шлёт только те поля, которые этот провайдер действительно понимает.
Шаг 8: Тесты
Как минимум затроньте тесты, которые охраняют подключение провайдера.
Типичные места:
tests/hermes_cli/test_runtime_provider_resolution.pytests/cli/test_cli_provider_resolution.pytests/hermes_cli/test_model_switch_custom_providers.py(и смежныеtests/hermes_cli/test_model_switch_*.py)tests/hermes_cli/test_setup_model_provider.pytests/run_agent/test_provider_parity.pytests/run_agent/test_run_agent.pytests/test_<provider>_adapter.pyдля нативного провайдера
Для примеров только из документации набор файлов может быть другим. Суть — покрыть:
- резолвинг авторизации
- меню CLI / выбор провайдера
- резолвинг провайдера рантайма
- путь выполнения агента
- парсинг
provider:model - специфичную для адаптера конвертацию сообщений
Запуск тестов с отключённым xdist:
source venv/bin/activate
python -m pytest tests/hermes_cli/test_runtime_provider_resolution.py tests/cli/test_cli_provider_resolution.py tests/hermes_cli/test_setup_model_provider.py tests/run_agent/test_provider_parity.py -n0 -q
Под более глубокие изменения перед пушем прогоните весь набор тестов:
source venv/bin/activate
python -m pytest tests/ -n0 -q
Шаг 9: Живая проверка
После тестов прогоните реальный smoke-тест.
source venv/bin/activate
python -m hermes_cli.main chat -q "Say hello" --provider your-provider --model your-model
Если меняли меню, проверьте и интерактивные флоу:
source venv/bin/activate
python -m hermes_cli.main model
python -m hermes_cli.main setup
Для нативных провайдеров обязательно проверьте хотя бы один вызов инструмента, а не только ответ обычным текстом.
Шаг 10: Обновите пользовательскую документацию
Если провайдер выходит как первоклассная опция, обновите и пользовательскую документацию:
website/docs/getting-started/quickstart.mdwebsite/docs/user-guide/configuration.mdwebsite/docs/reference/environment-variables.md
Можно идеально подключить провайдер на уровне кода и всё равно оставить пользователей в неведении о нужных переменных окружения или флоу настройки.
Чеклист OpenAI-совместимого провайдера
Используйте, если провайдер работает со стандартными chat completions.
-
ProviderConfigдобавлен вhermes_cli/auth.py - псевдонимы добавлены в
hermes_cli/auth.pyиhermes_cli/models.py - каталог моделей добавлен в
hermes_cli/models.py - бранч рантайма добавлен в
hermes_cli/runtime_provider.py - подключение CLI добавлено в
hermes_cli/main.py(setup.py наследует автоматически) - aux-модель добавлена в
agent/auxiliary_client.py - длины контекста добавлены в
agent/model_metadata.py - тесты рантайма / CLI обновлены
- пользовательская документация обновлена
Чеклист нативного провайдера
Используйте, когда провайдеру нужен новый путь протокола.
- всё из чеклиста OpenAI-совместимого провайдера
- адаптер добавлен в
agent/<provider>_adapter.py - новый
api_modeподдерживается вrun_agent.py - путь прерывания / перестройки работает
- извлечение usage и finish-reason работает
- резервный путь работает
- тесты адаптера добавлены
- живой smoke-тест проходит
Типичные ошибки
1. Провайдер добавлен в auth, но не в парсинг моделей
Учётные данные резолвятся корректно, а ввод через /model и provider:model не работает.
2. Забыли, что config["model"] может быть строкой или словарём
Изрядной части кода выбора провайдера приходится нормализовать оба варианта.
3. Решили, что встроенный провайдер обязателен
Если сервис просто совместим с OpenAI, кастомный провайдер нередко закрывает задачу пользователя при меньших затратах на поддержку.
4. Забытые вспомогательные пути
Основной путь чата работает, а суммаризация, сбросы памяти или vision-хелперы — нет, потому что маршрутизацию aux так и не обновили.
5. Бранчи нативного провайдера, спрятанные в run_agent.py
Ищите api_mode и self.client.. Очевидный путь запроса — не обязательно единственный.
6. Отправка OpenRouter-специфичных параметров другим провайдерам
Поля вроде маршрутизации провайдера уместны только у тех провайдеров, которые их поддерживают.
7. Обновили hermes model, но не hermes setup
О провайдере должны знать оба флоу.
Полезные символы для поиска при реализации
Чтобы выловить все точки, где провайдер оставляет след, ищите эти символы:
PROVIDER_REGISTRY_PROVIDER_ALIASES_PROVIDER_MODELSresolve_runtime_provider_model_flow_select_provider_and_modelapi_mode_API_KEY_PROVIDER_AUX_MODELSself.client.