fix(cli,auth): resolve base_url_env_var from ~/.hermes/.env - #20656
fix(cli,auth): resolve base_url_env_var from ~/.hermes/.env#20656haosenwang1018 wants to merge 1 commit into
Conversation
Closes NousResearch#18757 Provider base URLs declared via ``base_url_env_var`` were resolved through ``os.getenv`` only — bypassing ``~/.hermes/.env``. API keys already used ``get_env_value`` (which reads ``.env``), so users with a base URL set only in ``.env`` (not exported in the shell) ended up with a working API key but the registry default base URL. The original report describes Xiaomi's ``token-plan-cn`` endpoint silently regressing to the public ``api.xiaomimimo.com`` default, producing 401s on auxiliary tasks. The same inconsistency affects every API-key provider with a ``base_url_env_var``. Four call sites were inconsistent and now use the ``get_env_value(...) or os.getenv(...)`` fallback (matching the existing API-key resolution pattern): - ``auth.get_api_key_provider_status`` (status / ``hermes doctor``) - ``auth.resolve_api_key_provider_credentials`` (the original report) - ``auth.resolve_external_process_provider_credentials`` (Copilot ACP) - ``runtime_provider._build_runtime_for_api_key_provider`` (auxiliary client base URL plumbing) Tests cover the regression (``.env``-only base URL is now picked up) and pin the existing shell-env behavior so we don't regress in the other direction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Duplicate of #18948 — both fix |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the API-key and external-process resolver paths. The underlying dotenv-only base-URL defect is still present on current main: hermes_cli/auth.py:6204, :6236, :6391, and :6449 use os.getenv() directly.
Problems
- The
runtime_provider.pyhunk is stale. Currenthermes_cli/runtime_provider.py:1464uses_getenv(), which routes through the profile secret scope athermes_cli/runtime_provider.py:43/agent/secret_scope.py:123; a directget_env_value()replacement would bypass that newer isolation mechanism. - The PR does not cover current sibling reads in
hermes_cli/auth.py:6236orhermes_cli/model_switch.py:1560. tests/hermes_cli/test_provider_base_url_dotenv.pymocksget_env_value; use a temporaryHERMES_HOME/.envinstead so the regression verifies real dotenv loading and profile scoping.
Suggested changes
- Rebase the auth-path fix onto the current functions, preserve secret-scope semantics in runtime resolution, and add the missing status/model-switch paths if they remain intended behavior.
- Add an end-to-end temporary-home regression test rather than mocking the dotenv accessor.
Automated hermes-sweeper review.
| if pconfig.base_url_env_var: | ||
| env_url = os.getenv(pconfig.base_url_env_var, "").strip().rstrip("/") | ||
| from hermes_cli.config import get_env_value | ||
| env_url = ( |
There was a problem hiding this comment.
Current main routes this read through _getenv() so multiplexed gateway turns use agent.secret_scope.get_secret() rather than raw process/environment access. Please rework this hunk against the current resolver instead of importing get_env_value() directly.
| """``resolve_api_key_provider_credentials()`` must consult ``.env`` for | ||
| the base URL — not only the shell environment.""" | ||
|
|
||
| def test_dotenv_base_url_used_when_shell_env_unset(self, monkeypatch): |
There was a problem hiding this comment.
This mocks the accessor being validated, so it cannot verify real HERMES_HOME/.env loading or profile-path behavior. Please use a temporary Hermes home with an actual .env file and clear the shell variable.
Issue
Closes #18757
Root cause
Provider base URLs declared via
base_url_env_var(e.g.XIAOMI_BASE_URL,ARCEE_BASE_URL) resolved only throughos.getenv— they didn't see~/.hermes/.env. API keys already usedget_env_value(which reads.env), so the function had two halves with inconsistent semantics: API key found, base URL silently fell back to the registry default.The original report describes Xiaomi's
token-plan-cn-cn.xiaomimimo.comendpoint silently regressing to the publicapi.xiaomimimo.comdefault → 401s on auxiliary tasks. The same inconsistency affected every API-key provider with abase_url_env_var(Arcee, GLM, Kimi, GMI, MiniMax, Stepfun, GMI, AI Gateway, OpenCode, Kilocode, HF, TokenHub, Ollama, Bedrock, Azure Foundry, etc.).Fix
Four call sites needed the same
.env-aware lookup. The bug report named the first one; the rest were grep'd from the same access pattern:hermes_cli/auth.pyresolve_api_key_provider_credentialshermes_cli/auth.pyget_api_key_provider_statushermes doctorstatus outputhermes_cli/auth.pyresolve_external_process_provider_credentialshermes_cli/runtime_provider.py_build_runtime_for_api_key_provider(around the existingpconfig.base_url_env_varblock)All four now use the same fallback pattern that API-key resolution already uses elsewhere in the file:
Behavior when the value is set in the shell environment is unchanged.
Tests
tests/hermes_cli/test_provider_base_url_dotenv.py(new) covers:.env-only base URL is now picked up byresolve_api_key_provider_credentialsget_api_key_provider_status(sohermes doctorno longer lies when a.envbase URL is set)Existing
test_arcee_provider.pyandtest_runtime_provider_resolution.pyalso pass unchanged (139 tests in this scope, all green).