Skip to content

[feat] support extra headers#3526

Open
jneeee wants to merge 4 commits intoNousResearch:mainfrom
jneeee:support_extra_headers
Open

[feat] support extra headers#3526
jneeee wants to merge 4 commits intoNousResearch:mainfrom
jneeee:support_extra_headers

Conversation

@jneeee
Copy link
Copy Markdown
Contributor

@jneeee jneeee commented Mar 28, 2026

Summary

 Custom providers in hermes-agent can now specify custom HTTP headers for authentication, routing, or client identification.

 ## Changes

 ### Core Implementation

 - **`hermes_cli/runtime_provider.py`**:
   - Added `extra_headers` reading in `_get_named_custom_provider()` (line 170-172)
   - Added `extra_headers` passing through in `_resolve_named_custom_runtime()` (line 211)

 - **`run_agent.py`**:
   - Added `extra_headers: Dict[str, str] = None` parameter to `AIAgent.__init__()` (line 432)
   - Stored as instance variable `self.extra_headers` (line 500)
   - Applied to `client_kwargs["default_headers"]` when provider is "custom" (lines 753-755)

 - **`gateway/run.py`**:
   - Added `extra_headers` to `_resolve_runtime_agent_kwargs()` return dict (line 257)

 ### Documentation

 - **`website/docs/user-guide/configuration.md`**:
   - Added `extra_headers` example in custom provider YAML config
   - Added "Custom HTTP Headers" subsection explaining usage and common headers

 ## Config Format

 Users can add custom providers with `extra_headers` in `config.yaml`:

 ```yaml
 custom_providers:
   - name: "my-custom"
     base_url: "https://my-inference-server.com/v1"
     api_key: "${MY_API_KEY}"
     api_mode: "chat_completions"
     extra_headers:
       X-Custom-Auth: "my-token"
       X-Client-Name: "hermes-agent"
 ```

 ## Test Plan

 - [x] `test_named_custom_provider_with_extra_headers` - verifies extra_headers are passed through runtime resolution
 - [x] `test_named_custom_provider_extra_headers_not_set_when_missing` - verifies behavior when extra_headers is absent
 - [x] `test_extra_headers_passed_to_openai_client_for_custom_provider` - verifies headers reach the OpenAI client
 - [x] `test_extra_headers_not_set_for_non_custom_provider` - verifies OpenRouter headers take precedence
 - [x] `test_no_default_headers_when_no_extra_headers_and_custom_provider` - verifies no headers set when none provided

 ## Files Changed

 ```
 gateway/run.py                            |  1 +
 hermes_cli/runtime_provider.py            |  4 ++
 run_agent.py                              |  7 +++
 tests/test_run_agent.py                   | 95 +++++++++++++++++++++++++++++++
 tests/test_runtime_provider_resolution.py | 46 +++++++++++++++++++
 website/docs/user-guide/configuration.md   | 30 +++++++++++++
 6 files changed, 183 insertions(+)
 ```

jneeee and others added 3 commits March 28, 2026 10:34
…rn_agent_config

The TUI side correctly passed extra_headers through the runtime kwargs
to resolve_turn_route, but the Gateway's _resolve_turn_agent_config was
missing it in the primary dict, causing custom provider headers (like
x-host-head) to not be applied for Gateway requests.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- Test that named custom providers with extra_headers are resolved correctly
- Test that empty extra_headers dict is ignored
- Test that non-dict extra_headers is ignored
- Test that _resolve_named_custom_runtime includes extra_headers
- Test that resolve_turn_route preserves extra_headers from primary runtime
- Test that resolve_turn_route uses routed runtime's extra_headers when routing

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The _resolve_named_custom_runtime always includes extra_headers key
in its return dict (with None value when not configured), but the
tests were asserting the key should be absent. Also add missing
extra_headers attribute to CLI test fixtures.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant