Skip to content

[Bug]: run_agent.py uses _default_headers instead of default_headers, dropping routed client headers and breaking Kimi API #8779

@andrewhosf

Description

@andrewhosf

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

  1. Set provider: kimi-coding and model: kimi-k2.5 in config.yaml
  2. Ensure KIMI_API_KEY is set in the environment
  3. Run any Hermes command that triggers the main agent loop, e.g. hermes chat
  4. The agent initializes the LLM client via run_agent.py_build_openai_client()
  5. Because no explicit base URL/key is in config.yaml, the code hits the fallback branch at line ~880
  6. resolve_provider_client returns an OpenAI client with default_headers={"User-Agent": "KimiCLI/1.30.0"}
  7. run_agent.py line 889 checks for _routed_client._default_headers (does not exist)
  8. The User-Agent header is dropped from client_kwargs
  9. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/agentCore agent loop, run_agent.py, prompt builderprovider/kimiKimi / Moonshottype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions