Разрешение провайдера во время выполнения

Hermes использует общий механизм разрешения провайдера во время выполнения, применяемый в:

Основные реализации:

get_provider_profile() в providers/ возвращает ProviderProfile для указанного идентификатора провайдера. runtime_provider.py вызывает эту функцию во время разрешения, чтобы получить канонические base_url, env_vars (список приоритета), api_mode и fallback_models без необходимости дублировать эти данные в нескольких файлах. Добавления нового плагина в plugins/model-providers/<your-provider>/ (или $HERMES_HOME/plugins/model-providers/<your-provider>/), который вызывает register_provider(), достаточно, чтобы runtime_provider.py подхватил его — ветвление в самом резолвере не требуется.

Если вы пытаетесь добавить нового первоклассного инференс-провайдера, прочтите Adding Providers и Model Provider Plugin guide вместе с этой страницей.

Приоритет разрешения

На высоком уровне разрешение провайдера использует:

  1. явный запрос из CLI/среды выполнения

  2. конфигурацию модели/провайдера в config.yaml

  3. переменные окружения

  4. значения по умолчанию для конкретного провайдера или авторазрешение

Этот порядок важен, поскольку Hermes использует сохранённый выбор модели/провайдера как источник истины для обычных запусков. Это предотвращает случайное переопределение конечной точки, выбранной пользователем в hermes model, устаревшим экспортом из shell.

Провайдеры

Текущие семейства провайдеров включают (см. plugins/model-providers/ для полного набора встроенных):

Результат разрешения во время выполнения

Резолвер времени выполнения возвращает такие данные, как:

Почему это важно

Этот резолвер — основная причина, по которой Hermes может разделять логику аутентификации/выполнения между:

AI Gateway

Установите AI_GATEWAY_API_KEY в ~/.hermes/.env и запускайте с флагом --provider ai-gateway. Hermes получает доступные модели из эндпоинта /models gateway, фильтруя языковые модели с поддержкой tool-use.

OpenRouter, AI Gateway и пользовательские OpenAI-совместимые base URLs

Hermes содержит логику для предотвращения утечки неверного API-ключа на пользовательскую конечную точку, когда существует несколько ключей провайдеров (например, OPENROUTER_API_KEY, AI_GATEWAY_API_KEY и OPENAI_API_KEY).

API-ключ каждого провайдера привязан к своему собственному base URL:

Hermes также различает:

Это различие особенно важно для:

Нативный путь Anthropic

Anthropic — это больше не просто «через OpenRouter».

Когда разрешение провайдера выбирает anthropic, Hermes использует:

Разрешение учётных данных для нативного Anthropic теперь предпочитает обновляемые учётные данные Claude Code скопированным токенам окружения, когда оба присутствуют. На практике это означает:

Путь OpenAI Codex

Codex использует отдельный путь Responses API:

Маршрутизация вспомогательных моделей

Вспомогательные задачи, такие как:

могут использовать собственную маршрутизацию провайдера/модели, а не основную диалоговую модель.

Когда вспомогательная задача настроена с провайдером main, Hermes разрешает её через тот же общий путь выполнения, что и обычный чат. На практике это означает:

Резервные модели

Hermes поддерживает настроенную цепочку резервных провайдеров — список пар (provider, model), перебираемых по порядку при возникновении ошибок у основной модели. Устаревший словарь fallback_model с одной парой по-прежнему принимается для обратной совместимости (и мигрируется при первой записи).

Как это работает внутри

  1. Хранение: AIAgent.__init__ сохраняет словарь fallback_model и устанавливает _fallback_activated = False.

  2. Точки срабатывания: _try_activate_fallback() вызывается из трёх мест в основном цикле повторных попыток в run_agent.py:

  3. После исчерпания попыток при невалидных ответах API (None choices, отсутствующий контент)
  4. При неповторяемых клиентских ошибках (HTTP 401, 403, 404)
  5. После исчерпания попыток при временных ошибках (HTTP 429, 500, 502, 503)

  6. Процесс активации (_try_activate_fallback):

  7. Немедленно возвращает False, если уже активирован или не настроен
  8. Вызывает resolve_provider_client() из auxiliary_client.py для создания нового клиента с правильной аутентификацией
  9. Определяет api_mode: codex_responses для openai-codex, anthropic_messages для anthropic, chat_completions для всего остального
  10. Заменяет на месте: self.model, self.provider, self.base_url, self.api_mode, self.client, self._client_kwargs
  11. Для отката anthropic: создаёт нативный клиент Anthropic вместо OpenAI-совместимого
  12. Переоценивает кэширование промптов (включено для моделей Claude на OpenRouter)
  13. Устанавливает _fallback_activated = True — предотвращает повторное срабатывание
  14. Сбрасывает счётчик попыток в 0 и продолжает цикл

  15. Процесс конфигурации:

  16. CLI: cli.py читает CLI_CONFIG["fallback_model"] → передаёт в AIAgent(fallback_model=...)
  17. Gateway: gateway/run.py._load_fallback_model() читает config.yaml → передаёт в AIAgent
  18. Валидация: оба ключа provider и model должны быть непустыми, иначе резервный режим отключается

Что НЕ поддерживает резервный режим

Cron-задания поддерживают резервный режим: run_job() читает fallback_providers (или устаревший fallback_model) из config.yaml и передаёт его в AIAgent(fallback_model=...), следуя шаблону _load_fallback_model() из gateway. См. Cron Internals.

Тестовое покрытие

См. tests/test_fallback_model.py для всесторонних тестов, охватывающих всех поддерживаемых провайдеров, семантику одноразового срабатывания и граничные случаи.