In run_agent.py, when no explicit credentials are provided and the code falls back to the centralized provider router (resolve_provider_client), it attempts to preserve the default_headers that the router may have set on the returned OpenAI client. However, it looks for the private attribute ._default_headers instead of the public .default_headers attribute exposed by the OpenAI Python SDK.
Because hasattr(_routed_client, '_default_headers') is always False on current versions of the openai package, the routed client's headers are silently dropped. This causes API requests to Kimi (and potentially other providers that rely on default_headers) to fail with an HTTP 403 because the required User-Agent: KimiCLI/1.30.0 header is missing.
Steps to Reproduce
- Set
provider: kimi-coding and model: kimi-k2.5 in config.yaml
- Ensure
KIMI_API_KEY is set in the environment
- Run any Hermes command that triggers the main agent loop, e.g.
hermes chat
- The agent initializes the LLM client via
run_agent.py → _build_openai_client()
- Because no explicit base URL/key is in
config.yaml, the code hits the fallback branch at line ~880
resolve_provider_client returns an OpenAI client with default_headers={"User-Agent": "KimiCLI/1.30.0"}
run_agent.py line 889 checks for _routed_client._default_headers (does not exist)
- The
User-Agent header is dropped from client_kwargs
- The subsequent API call returns 403 with the error:
"Kimi For Coding is currently only available for Coding Agents such as Kimi CLI, Claude Code, Roo Code, Kilo Code, etc."
Expected Behavior
run_agent.py should preserve the routed client's default_headers by reading the public default_headers attribute, so provider-specific headers (like Kimi's User-Agent) are correctly forwarded to the API.
Actual Behavior
run_agent.py checks hasattr(_routed_client, '_default_headers') which is False, so client_kwargs["default_headers"] is never set. The API request is sent without the required User-Agent header and Kimi rejects it with 403.
Affected Component
Agent Core (conversation loop, context compression, memory)
Operating System
Ubuntu 24.04, macOS 15.2
Python Version
3.11.9
Hermes Version
Latest main (commit a0cd2c5 and earlier)
Relevant Logs / Traceback
openai.PermissionDeniedError: Error code: 403 - {
'error': {
'message': 'Kimi For Coding is currently only available for Coding Agents such as Kimi CLI, Claude Code, Roo Code, Kilo Code, etc.'
}
}
Root Cause Analysis
The bug is in run_agent.py at line 889:
# Preserve any default_headers the router set
if hasattr(_routed_client, '_default_headers') and _routed_client._default_headers:
client_kwargs["default_headers"] = dict(_routed_client._default_headers)
The OpenAI Python SDK (v1.x) stores default headers on the public attribute default_headers, not the private ._default_headers. Elsewhere in the same file (line 5514), the codebase already correctly uses getattr(fb_client, "default_headers", None), confirming the fix.
Proposed Fix
Change line 889 of run_agent.py from:
if hasattr(_routed_client, '_default_headers') and _routed_client._default_headers:
client_kwargs["default_headers"] = dict(_routed_client._default_headers)
To:
if hasattr(_routed_client, 'default_headers') and _routed_client.default_headers:
client_kwargs["default_headers"] = dict(_routed_client.default_headers)
Or more defensively (matching line 5514):
_routed_headers = getattr(_routed_client, "default_headers", None)
if _routed_headers:
client_kwargs["default_headers"] = dict(_routed_headers)
In
run_agent.py, when no explicit credentials are provided and the code falls back to the centralized provider router (resolve_provider_client), it attempts to preserve thedefault_headersthat the router may have set on the returned OpenAI client. However, it looks for the private attribute._default_headersinstead of the public.default_headersattribute exposed by the OpenAI Python SDK.Because
hasattr(_routed_client, '_default_headers')is alwaysFalseon current versions of theopenaipackage, the routed client's headers are silently dropped. This causes API requests to Kimi (and potentially other providers that rely ondefault_headers) to fail with an HTTP 403 because the requiredUser-Agent: KimiCLI/1.30.0header is missing.Steps to Reproduce
provider: kimi-codingandmodel: kimi-k2.5inconfig.yamlKIMI_API_KEYis set in the environmenthermes chatrun_agent.py→_build_openai_client()config.yaml, the code hits the fallback branch at line ~880resolve_provider_clientreturns anOpenAIclient withdefault_headers={"User-Agent": "KimiCLI/1.30.0"}run_agent.pyline 889 checks for_routed_client._default_headers(does not exist)User-Agentheader is dropped fromclient_kwargsExpected Behavior
run_agent.pyshould preserve the routed client'sdefault_headersby reading the publicdefault_headersattribute, so provider-specific headers (like Kimi'sUser-Agent) are correctly forwarded to the API.Actual Behavior
run_agent.pycheckshasattr(_routed_client, '_default_headers')which isFalse, soclient_kwargs["default_headers"]is never set. The API request is sent without the requiredUser-Agentheader and Kimi rejects it with 403.Affected Component
Agent Core (conversation loop, context compression, memory)
Operating System
Ubuntu 24.04, macOS 15.2
Python Version
3.11.9
Hermes Version
Latest
main(commita0cd2c5and earlier)Relevant Logs / Traceback
Root Cause Analysis
The bug is in
run_agent.pyat line 889:The OpenAI Python SDK (v1.x) stores default headers on the public attribute
default_headers, not the private._default_headers. Elsewhere in the same file (line 5514), the codebase already correctly usesgetattr(fb_client, "default_headers", None), confirming the fix.Proposed Fix
Change line 889 of
run_agent.pyfrom:To:
Or more defensively (matching line 5514):