Перейти к содержанию

Runtime

На этой странице

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

  • CLI
  • gateway
  • cron-задачах
  • ACP
  • вспомогательных вызовах моделей

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

  • hermes_cli/runtime_provider.py — разрешение учётных данных, _resolve_custom_runtime()
  • hermes_cli/auth.py — реестр провайдеров, resolve_provider()
  • hermes_cli/model_switch.py — общий конвейер переключения /model (CLI + gateway)
  • agent/auxiliary_client.py — маршрутизация вспомогательных моделей
  • providers/ — ABC + точки входа в реестр (ProviderProfile, register_provider, get_provider_profile, list_providers)
  • plugins/model-providers/<name>/ — плагины для каждого провайдера (встроенные), которые объявляют api_mode, base_url, env_vars, fallback_models и регистрируют себя в реестре при первом обращении. Пользовательские плагины в $HERMES_HOME/plugins/model-providers/<name>/ переопределяют встроенные с тем же именем.

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 его подхватил — никаких ветвлений в самом резолвере не требуется.

Если вы пытаетесь добавить нового провайдера первого класса для инференса, прочитайте Добавление провайдеров и Руководство по плагинам провайдеров моделей вместе с этой страницей.

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

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

  1. явный запрос CLI/времени выполнения
  2. конфигурацию модели/провайдера в config.yaml
  3. переменные окружения
  4. значения по умолчанию или автоматическое разрешение, специфичные для провайдера

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

Провайдеры

Текущие семейства провайдеров включают:

  • AI Gateway (Vercel)
  • OpenRouter
  • Nous Portal
  • OpenAI Codex
  • Copilot / Copilot ACP
  • Anthropic (нативный)
  • Google / Gemini
  • Alibaba / DashScope
  • DeepSeek
  • Z.AI
  • Kimi / Moonshot
  • MiniMax
  • MiniMax China
  • Kilo Code
  • Hugging Face
  • OpenCode Zen / OpenCode Go
  • Custom (provider: custom) — провайдер первого класса для любой OpenAI-совместимой конечной точки
  • Именованные пользовательские провайдеры (список custom_providers в config.yaml)

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

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

  • provider
  • api_mode
  • base_url
  • api_key
  • source
  • метаданные, специфичные для провайдера, такие как информация об истечении срока/обновлении

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

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

  • hermes chat
  • обработкой сообщений gateway
  • cron-задачами, запускаемыми в новых сессиях
  • сессиями редактора ACP
  • задачами вспомогательных моделей

AI Gateway

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

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

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

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

  • OPENROUTER_API_KEY отправляется только на эндпоинты openrouter.ai
  • AI_GATEWAY_API_KEY отправляется только на эндпоинты ai-gateway.vercel.sh
  • OPENAI_API_KEY используется для пользовательских конечных точек и как запасной вариант

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

  • реальную пользовательскую конечную точку, выбранную пользователем
  • запасной путь OpenRouter, используемый, когда пользовательская конечная точка не настроена

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

  • локальных серверов моделей
  • OpenAI-совместимых API, не являющихся OpenRouter или AI Gateway
  • переключения провайдеров без повторного запуска настройки
  • сохранённых в конфигурации пользовательских конечных точек, которые должны продолжать работать, даже если OPENAI_BASE_URL не экспортирован в текущем shell

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

Anthropic теперь не только «через OpenRouter».

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

  • api_mode = anthropic_messages
  • нативный Anthropic Messages API
  • agent/anthropic_adapter.py для трансляции

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

  • файлы учётных данных Claude Code рассматриваются как предпочтительный источник, когда они содержат обновляемую аутентификацию
  • ручные значения ANTHROPIC_TOKEN / CLAUDE_CODE_OAUTH_TOKEN по-прежнему работают как явные переопределения
  • Hermes предварительно проверяет обновление учётных данных Anthropic перед нативными вызовами Messages API
  • Hermes по-прежнему повторяет запрос один раз при получении 401 после пересоздания клиента Anthropic, как запасной путь

Путь OpenAI Codex

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

  • api_mode = codex_responses
  • выделенное разрешение учётных данных и поддержка хранилища аутентификации

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

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

  • vision
  • суммаризация извлечённых веб-данных
  • суммаризация сжатия контекста
  • суммаризация поиска по сессиям
  • операции skills hub
  • операции MCP helper
  • сброс памяти (memory flushes)

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

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

  • управляемые через окружение пользовательские конечные точки по-прежнему работают
  • пользовательские конечные точки, сохранённые через hermes model / config.yaml, также работают
  • вспомогательная маршрутизация может отличить реальную сохранённую пользовательскую конечную точку от запасного пути OpenRouter

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

Hermes поддерживает настроенную пару резервной модели/провайдера, обеспечивая автоматическое переключение при возникновении ошибок основной модели.

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

  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 должны быть непустыми, иначе резервный режим отключён

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

  • Делегирование сабагентам (tools/delegate_tool.py): сабагенты наследуют провайдера родителя, но не конфигурацию резервного режима
  • Вспомогательные задачи: используют собственную независимую цепочку автоопределения провайдера (см. Маршрутизация вспомогательных моделей выше)

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

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

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

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