Skip to content

fix(auth): resolve API keys from ~/.hermes/.env and credential_pool#16101

Merged
teknium1 merged 3 commits into
mainfrom
hermes/hermes-06c091bf
Apr 26, 2026
Merged

fix(auth): resolve API keys from ~/.hermes/.env and credential_pool#16101
teknium1 merged 3 commits into
mainfrom
hermes/hermes-06c091bf

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Salvage of #15920 (@zons-zhaozhy / @zzy-git) onto current main, with strengthened tests and hoisted imports.

Summary

_resolve_api_key_provider_secret and credential_pool._seed_from_env now consult ~/.hermes/.env via get_env_value(), and _resolve_api_key_provider_secret falls 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 .env into os.environ, so this fix is load-bearing specifically for: (a) post-session-start .env edits, (b) non-standard entry points that don't call the env loader, (c) fallback-provider resolution where the pool holds valid keys that _resolve previously ignored.

Changes

  • agent/credential_pool.py: _seed_from_env uses get_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_secret uses get_env_value() and falls back to credential_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 .env file 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

tests/tools/test_credential_pool_env_fallback.py ......... 9 passed
tests/hermes_cli/ -k 'auth or credential'                320 passed
tests/tools/ -k credential                                74 passed

Credit

Original work by @zons-zhaozhy (commits authored by @zzy-git). Cherry-picked with authorship preserved. Closes #15914, closes #15920, closes #15932.

zzy-git and others added 3 commits April 26, 2026 08:27
_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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools comp/agent Core agent loop, run_agent.py, prompt builder P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

3 participants