Skip to content

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

Closed
zons-zhaozhy wants to merge 2 commits into
NousResearch:mainfrom
zons-zhaozhy:fix/credential-pool-env-fallback
Closed

fix(auth): resolve API keys from ~/.hermes/.env and credential_pool#15920
zons-zhaozhy wants to merge 2 commits into
NousResearch:mainfrom
zons-zhaozhy:fix/credential-pool-env-fallback

Conversation

@zons-zhaozhy

@zons-zhaozhy zons-zhaozhy commented Apr 26, 2026

Copy link
Copy Markdown

Summary

Fixes #15914

API key provider resolution (_resolve_api_key_provider_secret) and credential pool seeding (_seed_from_env) only checked os.environ, ignoring keys stored in ~/.hermes/.env. When the .env file has keys but they are not loaded into the process environment (ACP adapter entry point, post-session-start edits, non-CLI entry points), resolution returns empty string → HTTP 401.

This also causes _prune_stale_seeded_entries to delete valid credential pool entries whose env var source is absent from os.environ.

Changes

agent/credential_pool.py_seed_from_env:

  • Replace os.getenv() with get_env_value() for env var and base_url resolution
  • get_env_value() checks both os.environ and ~/.hermes/.env file
  • Prevents valid entries from being pruned when .env is the storage source

hermes_cli/auth.py_resolve_api_key_provider_secret:

  • Replace os.getenv() with get_env_value() for provider key env vars
  • Add credential_pool fallback: when env resolution fails, attempt load_pool().peek() to retrieve a stored key

Testing

# get_env_value reads from .env file
get_env_value("GLM_API_KEY") → 49-char key ✓

# resolve_api_key_provider_secret finds zai key
_resolve_api_key_provider_secret("zai", pconfig) → (key, "GLM_API_KEY") ✓

# credential_pool seeds successfully
load_pool("zai").has_credentials() → True ✓

# E2E API call with resolved credentials
POST /chat/completions → 200 OK ✓

Related

Closes #15932

_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 NousResearch#15914
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent loop, run_agent.py, prompt builder area/auth Authentication, OAuth, credential pools labels Apr 26, 2026
teknium1 added a commit that referenced this pull request Apr 26, 2026
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.
@teknium1

Copy link
Copy Markdown
Contributor

Salvaged and merged via #16101 — your commits were cherry-picked with authorship preserved (@zzy-git visible in git log). Added a follow-up commit to hoist the get_env_value imports out of hot loops and rewrote the test file with real temp-.env file I/O so the fallback paths are actually exercised. Thanks for the fix!

#16101

ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
Follow-up to cherry-picked PR NousResearch#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.
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
Follow-up to cherry-picked PR NousResearch#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.
@zons-zhaozhy zons-zhaozhy deleted the fix/credential-pool-env-fallback branch May 4, 2026 16:34
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
Follow-up to cherry-picked PR NousResearch#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.
dannyJ848 pushed a commit to dannyJ848/hermes-agent that referenced this pull request May 17, 2026
Follow-up to cherry-picked PR NousResearch#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.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Follow-up to cherry-picked PR NousResearch#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.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
Follow-up to cherry-picked PR NousResearch#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

4 participants