Добавление провайдеров

Hermes уже умеет работать с любым OpenAI-совместимым эндпоинтом через путь кастомного провайдера. Заводить встроенный провайдер стоит только ради первоклассного UX для конкретного сервиса:

  • специфичная авторизация или обновление токена
  • курированный каталог моделей
  • записи в меню hermes model и мастере установки
  • псевдонимы провайдера для синтаксиса provider:model
  • нестандартная форма API, под которую нужен адаптер

Если провайдер — просто «ещё один OpenAI-совместимый base URL и API-ключ», именованного кастомного провайдера будет достаточно.

Ментальная модель

Встроенный провайдер должен сойтись на нескольких уровнях:

  1. hermes_cli/auth.py — определяет, как находятся учётные данные.
  2. hermes_cli/runtime_provider.py — превращает их в данные рантайма:
    • provider
    • api_mode
    • base_url
    • api_key
    • source
  3. run_agent.py смотрит на api_mode, чтобы решить, как строить и отправлять запросы.
  4. hermes_cli/models.py и hermes_cli/main.py делают провайдер видимым в CLI. (hermes_cli/setup.py делегирует всё main.py автоматически — менять его не нужно.)
  5. 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_responses
  • anthropic_messages

Этот путь включает всё из Пути A плюс:

  • адаптер провайдера в agent/
  • бранчи в run_agent.py для построения запросов, диспатча, извлечения usage, обработки прерываний и нормализации ответов
  • тесты адаптера

Чеклист файлов

Обязательно для каждого встроенного провайдера

  1. hermes_cli/auth.py
  2. hermes_cli/models.py
  3. hermes_cli/runtime_provider.py
  4. hermes_cli/main.py
  5. agent/auxiliary_client.py
  6. agent/model_metadata.py
  7. тесты
  8. пользовательская документация в website/docs/
совет

hermes_cli/setup.py править не нужно. Мастер установки делегирует выбор провайдера и модели функции select_provider_and_model() из main.py — любой добавленный туда провайдер автоматически доступен в hermes setup.

Дополнительно для нативных / не-OpenAI провайдеров

  1. agent/<provider>_adapter.py
  2. run_agent.py
  3. pyproject.toml, если нужен SDK провайдера

Быстрый путь: простые провайдеры с API-ключом

Если ваш провайдер — это просто OpenAI-совместимый эндпоинт, который аутентифицируется одним API-ключом, трогать auth.py, runtime_provider.py, main.py и прочие файлы из полного чеклиста не придётся.

Достаточно двух шагов:

  1. Создать директорию плагина в plugins/model-providers/<your-provider>/, а в ней:
    • __init__.py — вызывает register_provider(profile) на уровне модуля
    • plugin.yaml — манифест (name, kind: model-provider, version, description)
  2. Всё. Плагины провайдеров подгружаются сами при первом вызове get_provider_profile() или list_providers() — подхватываются и встроенные плагины (этого репозитория), и пользовательские из $HERMES_HOME/plugins/model-providers/.

Как только плагин вызывает register_provider(), само собой подключается следующее:

  1. Запись PROVIDER_REGISTRY в auth.py (резолвинг учётных данных, поиск переменных окружения)
  2. api_mode выставляется в chat_completions
  3. base_url берётся из конфига или объявленной переменной окружения
  4. env_vars проверяются для API-ключа в порядке приоритета
  5. Список fallback_models регистрируется за провайдером
  6. Флаг --provider CLI принимает id провайдера
  7. Меню hermes model включает провайдер
  8. Мастер hermes setup делегирует выбор main.py автоматически
  9. Синтаксис псевдонима provider:model работает
  10. Резолвер рантайма возвращает корректные base_url и api_key
  11. Флаг --provider <name> CLI принимает id провайдера
  12. Активация резервной модели чисто переключается на провайдер

Пользовательские плагины в $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-codex
  • kimi-coding
  • minimax-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:

  • id
  • name
  • auth_type="api_key"
  • inference_base_url
  • api_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.py
  • tests/cli/test_cli_provider_resolution.py
  • tests/hermes_cli/test_model_switch_custom_providers.py (и смежные tests/hermes_cli/test_model_switch_*.py)
  • tests/hermes_cli/test_setup_model_provider.py
  • tests/run_agent/test_provider_parity.py
  • tests/run_agent/test_run_agent.py
  • tests/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.md
  • website/docs/user-guide/configuration.md
  • website/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_MODELS
  • resolve_runtime_provider
  • _model_flow_
  • select_provider_and_model
  • api_mode
  • _API_KEY_PROVIDER_AUX_MODELS
  • self.client.

Связанная документация

ESC