Skip to content

Provider Runtime Resolution

hermes agent Provider Runtime Resolution

Hermes 有一个共享的 provider runtime resolver,会在以下场景中使用:

  • CLI
  • gateway
  • cron jobs
  • ACP
  • auxiliary model calls

主要实现:

  • hermes_cli/runtime_provider.py —— credential resolution、_resolve_custom_runtime()
  • hermes_cli/auth.py —— provider registry、resolve_provider()
  • hermes_cli/model_switch.py —— 共享的 /model switch pipeline(CLI + gateway)
  • agent/auxiliary_client.py —— auxiliary model routing
  • providers/ —— ABC + registry entry points(ProviderProfileregister_providerget_provider_profilelist_providers
  • plugins/model-providers/<name>/ —— 每个 provider 的插件(bundled),用于声明 api_modebase_urlenv_varsfallback_models,并在首次访问时将自己注册到 registry。位于 $HERMES_HOME/plugins/model-providers/<name>/ 的用户插件会覆盖同名 bundled 插件。

providers/ 中的 get_provider_profile() 会根据给定的 provider id 返回一个 ProviderProfileruntime_provider.py 会在 resolution time 调用它,以获取 canonical base_urlenv_vars 优先级列表、api_modefallback_models,无需在多个文件中重复这些数据。只要在 plugins/model-providers/<your-provider>/(或 $HERMES_HOME/plugins/model-providers/<your-provider>/)下添加一个调用 register_provider() 的新插件,runtime_provider.py 就能识别它 —— resolver 本身不需要新增 branch。

如果你想添加一个新的一等 inference provider,请在阅读本页的同时阅读 Adding Providers 和 Model Provider Plugin guide。

在高层次上,provider resolution 使用:

  1. 显式 CLI / runtime 请求
  2. config.yaml 中的 model / provider 配置
  3. 环境变量
  4. provider-specific defaults 或 auto resolution

这个顺序很重要,因为 Hermes 会把已保存的 model / provider 选择视为正常运行时的事实来源。这可以防止过时的 shell export 静默覆盖用户上次在 hermes model 中选择的 endpoint。

当前 provider families 包括(完整的 bundled set 请参见 plugins/model-providers/):

  • AI Gateway(Vercel)
  • OpenRouter
  • Nous Portal
  • OpenAI Codex
  • Copilot / Copilot ACP
  • Anthropic(native)
  • Google / Gemini(geminigoogle-gemini-cli
  • Alibaba / DashScope(alibabaalibaba-coding-plan
  • DeepSeek
  • Z.AI
  • Kimi / Moonshot(kimi-codingkimi-coding-cn
  • MiniMax(minimaxminimax-cnminimax-oauth
  • Kilo Code
  • Hugging Face
  • OpenCode Zen / OpenCode Go
  • AWS Bedrock
  • Azure Foundry
  • NVIDIA NIM
  • xAI(Grok)
  • Arcee
  • GMI Cloud
  • StepFun
  • Qwen OAuth
  • Xiaomi
  • Ollama Cloud
  • LM Studio
  • Tencent TokenHub
  • Custom(provider: custom)—— 适用于任何 OpenAI-compatible endpoint 的一等 provider
  • Named custom providers(config.yaml 中的 custom_providers 列表)

runtime resolver 会返回如下数据:

  • provider
  • api_mode
  • base_url
  • api_key
  • source
  • provider-specific metadata,例如 expiry / refresh info

这个 resolver 是 Hermes 能够在以下场景之间共享 auth / runtime logic 的主要原因:

  • hermes chat
  • gateway message handling
  • 在 fresh sessions 中运行的 cron jobs
  • ACP editor sessions
  • auxiliary model tasks

~/.hermes/.env 中设置 AI_GATEWAY_API_KEY,并使用 --provider ai-gateway 运行。Hermes 会从 gateway 的 /models endpoint 获取可用模型,并过滤出支持 tool-use 的 language models。

OpenRouter、AI Gateway 和自定义 OpenAI-compatible base URLs

Section titled “OpenRouter、AI Gateway 和自定义 OpenAI-compatible base URLs”

当存在多个 provider keys(例如 OPENROUTER_API_KEYAI_GATEWAY_API_KEYOPENAI_API_KEY)时,Hermes 包含防止将错误 API key 泄露给自定义 endpoint 的逻辑。

每个 provider 的 API key 都限定到自己的 base URL:

  • OPENROUTER_API_KEY 只会发送到 openrouter.ai endpoints
  • AI_GATEWAY_API_KEY 只会发送到 ai-gateway.vercel.sh endpoints
  • OPENAI_API_KEY 用于 custom endpoints,并作为 fallback

Hermes 还会区分:

  • 用户选择的真实 custom endpoint
  • 未配置 custom endpoint 时使用的 OpenRouter fallback path

这种区分对于以下场景尤其重要:

  • local model servers
  • 非 OpenRouter / 非 AI Gateway 的 OpenAI-compatible APIs
  • 切换 providers 而不重新运行 setup
  • 通过 config.yaml 保存的 custom endpoints,即使当前 shell 中没有 export OPENAI_BASE_URL,也应该继续工作

Anthropic 现在不再只是 “via OpenRouter”。

当 provider resolution 选择 anthropic 时,Hermes 使用:

  • api_mode = anthropic_messages
  • native Anthropic Messages API
  • agent/anthropic_adapter.py 进行转换

Native Anthropic 的 credential resolution 现在会在两者都存在时,优先使用可刷新的 Claude Code credentials,而不是复制的 env tokens。实际含义是:

  • 当 Claude Code credential files 包含 refreshable auth 时,它们会被视为首选来源
  • 手动设置的 ANTHROPIC_TOKEN / CLAUDE_CODE_OAUTH_TOKEN 仍然可以作为显式覆盖
  • Hermes 会在 native Messages API calls 前预先刷新 Anthropic credentials
  • Hermes 在收到 401 后仍会重建 Anthropic client 并重试一次,作为 fallback path

Codex 使用单独的 Responses API path:

  • api_mode = codex_responses
  • 专用的 credential resolution 和 auth store support

Auxiliary tasks 可以使用独立于主 conversational model 的 provider / model routing,例如:

  • vision
  • web extraction summarization
  • context compression summaries
  • session search summarization
  • skills hub operations
  • MCP helper operations
  • memory flushes

当 auxiliary task 配置为 provider main 时,Hermes 会通过与普通 chat 相同的 shared runtime path 来解析它。实际含义是:

  • env-driven custom endpoints 仍然可用
  • 通过 hermes model / config.yaml 保存的 custom endpoints 也可用
  • auxiliary routing 可以区分真实保存的 custom endpoint 和 OpenRouter fallback

Hermes 支持配置 fallback provider chain —— 一个按顺序尝试的 (provider, model) entries 列表,用于 primary model 遇到错误时。旧版单对 fallback_model dict 仍然为了向后兼容而被接受(并会在第一次写入时迁移)。

  1. Storage:AIAgent.__init__ 存储 fallback_model dict,并设置 _fallback_activated = False

  2. Trigger points:_try_activate_fallback() 会从 run_agent.py 主 retry loop 中的三个位置调用:

  • 在 invalid API responses 达到 max retries 后(None choices、缺失 content)
  • 在 non-retryable client errors 上(HTTP 401、403、404)
  • 在 transient errors 达到 max retries 后(HTTP 429、500、502、503)
  1. Activation flow(_try_activate_fallback):
  • 如果已经 activated 或未配置,立即返回 False
  • 调用 auxiliary_client.py 中的 resolve_provider_client(),使用正确 auth 构建新 client
  • 确定 api_modeopenai-codex 使用 codex_responsesanthropic 使用 anthropic_messages,其他所有使用 chat_completions
  • 原地替换:self.modelself.providerself.base_urlself.api_modeself.clientself._client_kwargs
  • 对于 anthropic fallback:构建 native Anthropic client,而不是 OpenAI-compatible
  • 重新评估 prompt caching(OpenRouter 上的 Claude models 启用)
  • 设置 _fallback_activated = True —— 防止再次触发
  • 将 retry count 重置为 0,并继续 loop
  1. Config flow:
  • CLI:cli.py 读取 CLI_CONFIG["fallback_model"] → 传给 AIAgent(fallback_model=...)
  • Gateway:gateway/run.py._load_fallback_model() 读取 config.yaml → 传给 AIAgent
  • Validation:providermodel keys 都必须非空,否则 fallback 会被禁用
  • Subagent delegation(tools/delegate_tool.py):subagents 会继承 parent 的 provider,但不会继承 fallback config
  • Auxiliary tasks:使用它们自己的独立 provider auto-detection chain(见上面的 Auxiliary model routing)

Cron jobs 支持 fallback:run_job() 会从 config.yaml 读取 fallback_providers(或旧版 fallback_model),并传给 AIAgent(fallback_model=...),与 gateway 的 _load_fallback_model() 模式一致。参见 Cron Internals。

参见 tests/test_fallback_model.py,其中包含覆盖所有 supported providers、one-shot semantics 和 edge cases 的综合测试。

  • Agent Loop Internals
  • ACP Internals
  • Context Compression & Prompt Caching
-
0:000:00