Bug Description
When configuring a per-task auxiliary override (e.g. auxiliary.session_search) with an explicit base_url and model but leaving api_key empty, the auxiliary client fails to inherit the main model.api_key from config.yaml. Instead it falls through to the hardcoded "no-key-required" fallback, causing 401 auth errors.
This is a problem for users on custom/self-hosted endpoints who want to use a cheaper model for auxiliary tasks while sharing the same API gateway and credentials as their main model.
Steps to Reproduce
# ~/.hermes/config.yaml
model:
default: azure/anthropic/claude-opus-4-6
provider: custom
base_url: https://my-gateway.example.com/v1
api_key: sk-my-real-key
auxiliary:
session_search:
provider: custom
model: 'some/fast-model'
base_url: 'https://my-gateway.example.com/v1'
api_key: '' # empty — expect it to inherit from model.api_key
timeout: 30
- Configure as above (same
base_url as main provider, different model, empty api_key)
- Trigger a
session_search with a keyword query
- Observe 401 errors in
~/.hermes/logs/agent.log
Expected Behavior
When auxiliary.{task}.api_key is empty and auxiliary.{task}.base_url matches (or is the same gateway as) model.base_url, the auxiliary client should inherit model.api_key from config.yaml.
Actual Behavior
resolve_provider_client() receives explicit_api_key=None (empty string stripped). At line 1405-1408 of agent/auxiliary_client.py, the fallback chain is:
custom_key = (
(explicit_api_key or "").strip() # → empty
or os.getenv("OPENAI_API_KEY", "").strip() # → often unset
or "no-key-required" # ← wins
)
The main model.api_key from config.yaml is never consulted. The request goes out with Authorization: Bearer no-key-required and the gateway rejects it:
Authentication Error, LiteLLM Virtual Key expected.
Received=no-key-required, expected to start with 'sk-'
Affected Component
Auxiliary client (agent/auxiliary_client.py), specifically resolve_provider_client() custom provider path.
Proposed Fix
When provider=custom with an explicit base_url but no api_key, add model.api_key from config.yaml to the fallback chain before "no-key-required":
custom_key = (
(explicit_api_key or "").strip()
or os.getenv("OPENAI_API_KEY", "").strip()
or _read_main_api_key() # NEW: inherit from model.api_key in config
or "no-key-required"
)
Where _read_main_api_key() reads config.get("model", {}).get("api_key", "").
This is especially relevant for the provider: auto path as well — when auto-detection routes auxiliary tasks to the main custom endpoint but the env var is not set, the same fallback failure occurs.
Workaround
Duplicate the API key explicitly in every auxiliary.{task}.api_key field that uses a custom base_url.
Bug Description
When configuring a per-task auxiliary override (e.g.
auxiliary.session_search) with an explicitbase_urlandmodelbut leavingapi_keyempty, the auxiliary client fails to inherit the mainmodel.api_keyfrom config.yaml. Instead it falls through to the hardcoded"no-key-required"fallback, causing 401 auth errors.This is a problem for users on custom/self-hosted endpoints who want to use a cheaper model for auxiliary tasks while sharing the same API gateway and credentials as their main model.
Steps to Reproduce
base_urlas main provider, different model, emptyapi_key)session_searchwith a keyword query~/.hermes/logs/agent.logExpected Behavior
When
auxiliary.{task}.api_keyis empty andauxiliary.{task}.base_urlmatches (or is the same gateway as)model.base_url, the auxiliary client should inheritmodel.api_keyfrom config.yaml.Actual Behavior
resolve_provider_client()receivesexplicit_api_key=None(empty string stripped). At line 1405-1408 ofagent/auxiliary_client.py, the fallback chain is:The main
model.api_keyfrom config.yaml is never consulted. The request goes out withAuthorization: Bearer no-key-requiredand the gateway rejects it:Affected Component
Auxiliary client (
agent/auxiliary_client.py), specificallyresolve_provider_client()custom provider path.Proposed Fix
When
provider=customwith an explicitbase_urlbut noapi_key, addmodel.api_keyfrom config.yaml to the fallback chain before"no-key-required":Where
_read_main_api_key()readsconfig.get("model", {}).get("api_key", "").This is especially relevant for the
provider: autopath as well — when auto-detection routes auxiliary tasks to the main custom endpoint but the env var is not set, the same fallback failure occurs.Workaround
Duplicate the API key explicitly in every
auxiliary.{task}.api_keyfield that uses a custombase_url.