fix(auth): resolve API keys from ~/.hermes/.env and credential_pool#16101
Merged
Conversation
_resolve_api_key_provider_secret() and _seed_from_env() only checked os.environ for provider API keys. When keys exist in ~/.hermes/.env but are not loaded into the process environment (e.g. ACP adapter entry point, post-session-start .env edits, or non-CLI entry points), the resolution returns an empty string, causing HTTP 401 failures. Changes: - credential_pool._seed_from_env: use get_env_value() which checks both os.environ and ~/.hermes/.env file, preventing _prune_stale_seeded_entries from removing valid entries whose env var isn't in os.environ - credential_pool._seed_from_env: same fix for openrouter and base_url_env_var resolution - auth._resolve_api_key_provider_secret: use get_env_value() instead of os.getenv(), and add credential_pool fallback when env resolution fails Fixes #15914
Follow-up to cherry-picked PR #15920: - agent/credential_pool.py: hoist 'from hermes_cli.config import get_env_value' to module top instead of inline try/except in each seed site (3 sites). No import cycle — hermes_cli/config.py doesn't depend on agent.credential_pool. - hermes_cli/auth.py: same hoist for the _resolve_api_key_provider_secret loop. - tests/tools/test_credential_pool_env_fallback.py: replace smoke-only tests with real .env file I/O. Each test writes a temp ~/.hermes/.env, verifies _seed_from_env / _resolve_api_key_provider_secret read from it, and asserts the full priority chain: os.environ > .env > credential_pool. Uses 'deepseek' as the test provider since 'openai' isn't in PROVIDER_REGISTRY and _seed_from_env's generic path requires a real pconfig lookup.
This was referenced Apr 26, 2026
3 tasks
This was referenced May 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Salvage of #15920 (@zons-zhaozhy / @zzy-git) onto current main, with strengthened tests and hoisted imports.
Summary
_resolve_api_key_provider_secretandcredential_pool._seed_from_envnow consult~/.hermes/.envviaget_env_value(), and_resolve_api_key_provider_secretfalls back to the credential pool when env + .env are empty. Closes the fallback-provider 401 loop described in #15914 / dup #15932.Note: during normal CLI/ACP startup,
load_hermes_dotenv()already loads.envintoos.environ, so this fix is load-bearing specifically for: (a) post-session-start.envedits, (b) non-standard entry points that don't call the env loader, (c) fallback-provider resolution where the pool holds valid keys that_resolvepreviously ignored.Changes
agent/credential_pool.py:_seed_from_envusesget_env_value()at all 3 sites (openrouter branch, base_url env, generic loop). Import hoisted to module top (no cycle).hermes_cli/auth.py:_resolve_api_key_provider_secretusesget_env_value()and falls back tocredential_pool.load_pool(provider_id)when env resolution fails. Import hoisted above the loop.tests/tools/test_credential_pool_env_fallback.py: replaced smoke-only tests with real.envfile I/O. Each test writes a temp~/.hermes/.env, verifies the seed/resolve paths pick it up, and asserts the full priority chain (os.environ>.env>credential_pool). 9 tests, all real assertions.Validation
Credit
Original work by @zons-zhaozhy (commits authored by @zzy-git). Cherry-picked with authorship preserved. Closes #15914, closes #15920, closes #15932.