* remove Vercel AI Gateway provider and Vercel Sandbox terminal backend Both Vercel-hosted integrations are removed end-to-end. Users on the AI Gateway should switch to OpenRouter or one of the other aggregators (Nous Portal, Kilo Code). Users on the Vercel Sandbox backend should switch to Docker, Modal, Daytona, or SSH. What's removed: - `plugins/model-providers/ai-gateway/` provider plugin - `hermes_cli/vercel_auth.py` Vercel-Sandbox auth helper - `tools/environments/vercel_sandbox.py` terminal backend - `ai-gateway` provider wiring across auth, doctor, setup, models, config, status, providers, main, web_server, model_normalize, dump - `vercel_sandbox` backend wiring across terminal_tool, file_tools, code_execution_tool, file_operations, approval, skills_tool, environments/local, credential_files, lazy_deps, prompt_builder, cli, gateway/run - `AI_GATEWAY_BASE_URL` constant, `_AI_GATEWAY_HEADERS` auxiliary-client header set, run_agent base-URL header/reasoning special-cases - `[vercel]` pyproject extra and `vercel`/`vercel-workers` from uv.lock - env vars: `AI_GATEWAY_API_KEY`, `AI_GATEWAY_BASE_URL`, `VERCEL_TOKEN`, `VERCEL_PROJECT_ID`, `VERCEL_TEAM_ID`, `VERCEL_OIDC_TOKEN`, `TERMINAL_VERCEL_RUNTIME` - Tests: deletes test_ai_gateway_models.py and test_vercel_sandbox_environment.py; scrubs references across 23 surviving test files (no entire tests deleted unless they were dedicated to AI Gateway / Sandbox) - Docs: provider tables, env-var reference, setup guides, security notes, tool config, terminal-backend tables — English plus zh-Hans i18n parity - `hermes-agent` skill: provider table entry and remote-backend list What stays (intentional): - `popular-web-designs/templates/vercel.md` — CSS design reference, unrelated to Vercel-the-AI-product - `x-vercel-id` in `stream_diag.py` headers — generic Vercel CDN response header, useful diag signal on any Vercel-hosted endpoint - `vercel-labs/agent-browser` URL in browser config — lightpanda browser project, different OSS effort - `userStories.json` historical contributor entry mentioning Vercel Sandbox — archive, not active docs Validation: - 1153 tests in the 22 targeted files pass (`scripts/run_tests.sh`) - Full repo `py_compile` clean - Live import of every touched module + invariant check (no `ai-gateway` in `PROVIDER_REGISTRY`, no `_AI_GATEWAY_HEADERS`, no `vercel_sandbox` in `_REMOTE_TERMINAL_BACKENDS`) * test: convert profile-count check from change-detector to invariant The hardcoded "== 34" assertion broke when ai-gateway was removed. Per AGENTS.md change-detector-test guidance, assert the relationship (registry count >= number of plugin dirs) instead of a literal count. Counts shift when providers are added/removed; that's expected.
8.3 KiB
| sidebar_position | title | description |
|---|---|---|
| 4 | Provider 运行时解析 | Hermes 如何在运行时解析 provider、凭据、API 模式及辅助模型 |
Provider 运行时解析
Hermes 拥有一个共享的 provider 运行时解析器,用于以下场景:
- CLI
- gateway
- cron 任务
- ACP
- 辅助模型调用
主要实现:
hermes_cli/runtime_provider.py— 凭据解析,_resolve_custom_runtime()hermes_cli/auth.py— provider 注册表,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>/— 每个 provider 的插件(内置),声明api_mode、base_url、env_vars、fallback_models并在首次访问时将自身注册到注册表。用户插件位于$HERMES_HOME/plugins/model-providers/<name>/,会覆盖同名的内置插件。
providers/ 中的 get_provider_profile() 为给定 provider id 返回一个 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 自动识别它——无需在解析器本身中添加分支。
如果你想添加一个新的一等推理 provider,请结合本页阅读 添加 Provider 和 Model Provider 插件指南。
解析优先级
从高层来看,provider 解析使用以下顺序:
- 显式 CLI/运行时请求
config.yaml中的模型/provider 配置- 环境变量
- provider 特定的默认值或自动解析
该顺序很重要,因为 Hermes 将已保存的模型/provider 选择视为正常运行的真实来源。这可以防止过时的 shell 导出变量悄悄覆盖用户在 hermes model 中最后选择的端点。
Provider
当前 provider 系列包括(完整内置集合见 plugins/model-providers/):
- OpenRouter
- Nous Portal
- OpenAI Codex
- Copilot / Copilot ACP
- Anthropic(原生)
- 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 兼容端点的一等 provider - 命名自定义 provider(
config.yaml中的custom_providers列表)
运行时解析的输出
运行时解析器返回的数据包括:
providerapi_modebase_urlapi_keysource- provider 特定的元数据,如过期/刷新信息
为什么这很重要
该解析器是 Hermes 能够在以下场景之间共享认证/运行时逻辑的主要原因:
hermes chat- gateway 消息处理
- 在全新会话中运行的 cron 任务
- ACP 编辑器会话
- 辅助模型任务
OpenRouter 与自定义 OpenAI 兼容 base URL
Hermes 包含相关逻辑,以避免在存在多个 provider 密钥时(例如同时存在 OPENROUTER_API_KEY 和 OPENAI_API_KEY)将错误的 API key 泄露给自定义端点。
每个 provider 的 API key 仅作用于其自身的 base URL:
OPENROUTER_API_KEY仅发送至openrouter.ai端点OPENAI_API_KEY用于自定义端点及作为回退
Hermes 还区分以下两种情况:
- 用户主动选择的真实自定义端点
- 未配置自定义端点时使用的 OpenRouter 回退路径
这种区分对以下场景尤为重要:
- 本地模型服务器
- 非 OpenRouter 的 OpenAI 兼容 API
- 无需重新运行 setup 即可切换 provider
- 通过 config 保存的自定义端点,即使当前 shell 中未导出
OPENAI_BASE_URL也应正常工作
原生 Anthropic 路径
Anthropic 不再仅限于"通过 OpenRouter"访问。
当 provider 解析选择 anthropic 时,Hermes 使用:
api_mode = anthropic_messages- 原生 Anthropic Messages API
agent/anthropic_adapter.py进行转换
原生 Anthropic 的凭据解析现在在两者同时存在时,优先使用可刷新的 Claude Code 凭据,而非复制的环境变量 token。实际效果为:
- 包含可刷新认证的 Claude Code 凭据文件被视为首选来源
- 手动设置的
ANTHROPIC_TOKEN/CLAUDE_CODE_OAUTH_TOKEN值仍可作为显式覆盖 - Hermes 在调用原生 Messages API 前会预检 Anthropic 凭据刷新
- Hermes 在重建 Anthropic 客户端后,仍会在收到 401 时重试一次,作为回退路径
OpenAI Codex 路径
Codex 使用独立的 Responses API 路径:
api_mode = codex_responses- 专用的凭据解析和认证存储支持
辅助模型路由
辅助任务包括:
- 视觉
- 网页提取摘要
- 上下文压缩摘要
- skills hub 操作
- MCP 辅助操作
- 记忆刷新
这些任务可以使用各自独立的 provider/模型路由,而非主对话模型。
当辅助任务配置的 provider 为 main 时,Hermes 通过与普通对话相同的共享运行时路径进行解析。实际效果为:
- 环境变量驱动的自定义端点仍然有效
- 通过
hermes model/config.yaml保存的自定义端点同样有效 - 辅助路由能够区分真实保存的自定义端点与 OpenRouter 回退
回退模型
Hermes 支持配置回退 provider 链——一个按顺序尝试的 (provider, model) 条目列表,当主模型遇到错误时依次尝试。旧版单对 fallback_model 字典仍被接受以保持向后兼容(并在首次写入时迁移)。
内部工作原理
-
存储:
AIAgent.__init__存储fallback_model字典并将_fallback_activated设为False。 -
触发点:
_try_activate_fallback()在run_agent.py主重试循环的三处被调用:- 在无效 API 响应(None choices、缺少 content)达到最大重试次数后
- 在不可重试的客户端错误(HTTP 401、403、404)时
- 在瞬时错误(HTTP 429、500、502、503)达到最大重试次数后
-
激活流程(
_try_activate_fallback):- 若已激活或未配置,立即返回
False - 调用
auxiliary_client.py中的resolve_provider_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 - 对于 anthropic 回退:构建原生 Anthropic 客户端而非 OpenAI 兼容客户端
- 重新评估 prompt 缓存(对 OpenRouter 上的 Claude 模型启用)
- 将
_fallback_activated设为True——防止再次触发 - 将重试计数重置为 0 并继续循环
- 若已激活或未配置,立即返回
-
配置流程:
- CLI:
cli.py读取CLI_CONFIG["fallback_model"]→ 传递给AIAgent(fallback_model=...) - Gateway:
gateway/run.py._load_fallback_model()读取config.yaml→ 传递给AIAgent - 验证:
provider和model键均须非空,否则回退被禁用
- CLI:
不支持回退的场景
- 子代理委托(
tools/delegate_tool.py):子代理继承父代理的 provider,但不继承回退配置 - 辅助任务:使用各自独立的 provider 自动检测链(见上方辅助模型路由)
Cron 任务支持回退:run_job() 从 config.yaml 读取 fallback_providers(或旧版 fallback_model)并传递给 AIAgent(fallback_model=...),与 gateway 的 _load_fallback_model() 模式一致。参见 Cron 内部机制。
测试覆盖
参见 tests/test_fallback_model.py,其中包含覆盖所有支持 provider、单次触发语义及边界情况的完整测试。