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—— 共享的/modelswitch pipeline(CLI + gateway)agent/auxiliary_client.py—— auxiliary model routingproviders/—— ABC + registry entry points(ProviderProfile、register_provider、get_provider_profile、list_providers)plugins/model-providers/<name>/—— 每个 provider 的插件(bundled),用于声明api_mode、base_url、env_vars、fallback_models,并在首次访问时将自己注册到 registry。位于$HERMES_HOME/plugins/model-providers/<name>/的用户插件会覆盖同名 bundled 插件。
providers/ 中的 get_provider_profile() 会根据给定的 provider id 返回一个 ProviderProfile。runtime_provider.py 会在 resolution time 调用它,以获取 canonical 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 就能识别它 —— resolver 本身不需要新增 branch。
如果你想添加一个新的一等 inference provider,请在阅读本页的同时阅读 Adding Providers 和 Model Provider Plugin guide。
在高层次上,provider resolution 使用:
- 显式 CLI / runtime 请求
config.yaml中的 model / provider 配置- 环境变量
- provider-specific defaults 或 auto resolution
这个顺序很重要,因为 Hermes 会把已保存的 model / provider 选择视为正常运行时的事实来源。这可以防止过时的 shell export 静默覆盖用户上次在 hermes model 中选择的 endpoint。
Providers
Section titled “Providers”当前 provider families 包括(完整的 bundled set 请参见 plugins/model-providers/):
- AI Gateway(Vercel)
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic(native)
- Google / Gemini(
gemini、google-gemini-cli) - Alibaba / DashScope(
alibaba、alibaba-coding-plan) - DeepSeek
- Z.AI
- Kimi / Moonshot(
kimi-coding、kimi-coding-cn) - MiniMax(
minimax、minimax-cn、minimax-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 resolution 的输出
Section titled “Runtime resolution 的输出”runtime resolver 会返回如下数据:
providerapi_modebase_urlapi_keysource- provider-specific metadata,例如 expiry / refresh info
为什么这很重要
Section titled “为什么这很重要”这个 resolver 是 Hermes 能够在以下场景之间共享 auth / runtime logic 的主要原因:
hermes chat- gateway message handling
- 在 fresh sessions 中运行的 cron jobs
- ACP editor sessions
- auxiliary model tasks
AI Gateway
Section titled “AI Gateway”在 ~/.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_KEY、AI_GATEWAY_API_KEY 和 OPENAI_API_KEY)时,Hermes 包含防止将错误 API key 泄露给自定义 endpoint 的逻辑。
每个 provider 的 API key 都限定到自己的 base URL:
OPENROUTER_API_KEY只会发送到openrouter.aiendpointsAI_GATEWAY_API_KEY只会发送到ai-gateway.vercel.shendpointsOPENAI_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 中没有 exportOPENAI_BASE_URL,也应该继续工作
Native Anthropic path
Section titled “Native Anthropic path”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
OpenAI Codex path
Section titled “OpenAI Codex path”Codex 使用单独的 Responses API path:
api_mode = codex_responses- 专用的 credential resolution 和 auth store support
Auxiliary model routing
Section titled “Auxiliary model routing”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
Fallback models
Section titled “Fallback models”Hermes 支持配置 fallback provider chain —— 一个按顺序尝试的 (provider, model) entries 列表,用于 primary model 遇到错误时。旧版单对 fallback_model dict 仍然为了向后兼容而被接受(并会在第一次写入时迁移)。
内部工作方式
Section titled “内部工作方式”-
Storage:
AIAgent.__init__存储fallback_modeldict,并设置_fallback_activated = False。 -
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)
- Activation flow(
_try_activate_fallback):
- 如果已经 activated 或未配置,立即返回
False - 调用
auxiliary_client.py中的resolve_provider_client(),使用正确 auth 构建新 client - 确定
api_mode:openai-codex使用codex_responses,anthropic使用anthropic_messages,其他所有使用chat_completions - 原地替换:
self.model、self.provider、self.base_url、self.api_mode、self.client、self._client_kwargs - 对于
anthropicfallback:构建 native Anthropic client,而不是 OpenAI-compatible - 重新评估 prompt caching(OpenRouter 上的 Claude models 启用)
- 设置
_fallback_activated = True—— 防止再次触发 - 将 retry count 重置为 0,并继续 loop
- Config flow:
- CLI:
cli.py读取CLI_CONFIG["fallback_model"]→ 传给AIAgent(fallback_model=...) - Gateway:
gateway/run.py._load_fallback_model()读取config.yaml→ 传给AIAgent - Validation:
provider和modelkeys 都必须非空,否则 fallback 会被禁用
什么不支持 fallback
Section titled “什么不支持 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