Skip to content

feat: add custom header support for provider requests - #14314

Open
tevenfeng wants to merge 69 commits into
NousResearch:mainfrom
tevenfeng:main
Open

feat: add custom header support for provider requests#14314
tevenfeng wants to merge 69 commits into
NousResearch:mainfrom
tevenfeng:main

Conversation

@tevenfeng

@tevenfeng tevenfeng commented Apr 23, 2026

Copy link
Copy Markdown

Summary

  • Add model.custom_headers config option to attach arbitrary HTTP headers to provider requests
  • Add custom_providers[].custom_headers / providers.<name>.custom_headers for provider-specific headers; this is the only provider-level field, while headers is intentionally not supported to avoid ambiguity
  • New agent/client_headers.py module with get_model_custom_headers() and merge_default_headers() helpers for header sanitization and ordered merging
  • Propagate default_headers through the request chain: run_agentauxiliary_clientanthropic_adapter → SDK client, including subagents via delegate_tool
  • Preserve provider-level custom headers through CLI, oneshot, TUI/gateway/cron runtime paths, named custom providers, credential-pool resolution, direct-alias/bare-custom resolution, and Anthropic-compatible endpoints

Config Example

Global headers for all provider requests:

model:
  custom_headers:
    X-Source: "hermes-agent"
    X-Cost-Center: "team-ai-infra"

Provider-specific headers:

custom_providers:
  - name: "my-relay"
    base_url: "https://relay.example.com/v1"
    api_key: "sk-example"
    custom_headers:
      X-Relay-Key: "relay-secret"
      X-Cost-Center: "team-ai-infra"

The same field is supported after migration in the providers: map:

providers:
  my-relay:
    api: "https://relay.example.com/v1"
    api_key: "sk-example"
    custom_headers:
      X-Relay-Key: "relay-secret"

Closes #9398

Test Plan

  • scripts/run_tests.sh tests/hermes_cli/test_runtime_provider_resolution.py tests/hermes_cli/test_config.py tests/cli/test_cli_provider_resolution.py tests/hermes_cli/test_tui_resume_flow.py tests/agent/test_auxiliary_named_custom_providers.py
  • New tests/agent/test_client_headers.py — sanitization, merge semantics, empty/None inputs
  • New tests in tests/agent/test_anthropic_adapter.py — header merge with Anthropic defaults, provider-override-wins-on-conflict
  • New tests in tests/agent/test_auxiliary_client.py_normalize_main_runtime header handling, _try_anthropic header propagation, explicit vs context priority
  • Runtime/provider tests cover custom_providers[].custom_headers, providers.<name>.custom_headers, credential-pool propagation, bare-custom/direct-alias lookup, and migration preservation

tevenfeng and others added 3 commits April 21, 2026 14:55
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolved conflicts in:
- agent/auxiliary_client.py: adopt upstream's get_nous_recommended_aux_model
  while preserving _headers_with_config() propagation; update Kimi User-Agent
- tools/delegate_tool.py: keep both override_default_headers and role params
- tui_gateway/server.py: adopt upstream's runtime-based AIAgent construction
  while preserving default_headers resolution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery area/config Config system, migrations, profiles tool/delegate Subagent delegation labels Apr 23, 2026
tevenfeng and others added 2 commits April 23, 2026 14:08
…und 2)

Resolved conflicts in:
- agent/auxiliary_client.py: adopt upstream's _extract_url_query_params while
  preserving _headers_with_config() propagation; use _clean_base for URL params
- cron/scheduler.py: keep default_headers + adopt upstream's skip_context_files logic
- run_agent.py: adopt upstream's _rebuild_anthropic_client() refactoring,
  add default_headers param to that method; keep default_headers in __init__
- tests/agent/test_auxiliary_client.py: keep both custom header tests and
  upstream's new auth refresh retry tests
- tui_gateway/server.py: adopt upstream's _resolve_startup_runtime() while
  preserving default_headers resolution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@shailensobhee

Copy link
Copy Markdown

Nice! Tested it - this PR works :) Thanks..

@shailensobhee

Copy link
Copy Markdown

Btw, you seemed to have worked on 0.12. The code has conflicts with Hermes Agent v0.13.0 (2026.5.7) .

You may wish to make a new PR update?

Also, you check that verify: false is also treated such that config like this would work?

custom_providers:
    reject_unauthorized: false
      ss
  - id: "custom-model"
    name: "Some Endpoint"
    api_mode: "anthropic_messages"
    base_url: "https://custom-url"
    custom_headers:
      x-api-key: "somekey"
      Ocp-Apim-Subscription-Key: "somekey"
      Host: "custom-url.com"
    verify: false
    model: "Claude-Opus-4.6"
    context_length: 1000000

@tevenfeng

tevenfeng commented May 9, 2026

Copy link
Copy Markdown
Author

you check that verify: false is also treated such that config like this would work?

Well i'm pretty sure that we still don't support verify: false yet, let me dig into the code more deeply and fix that when i have the time.

Also I find out that the provider-level 'headers' config may not work, I'll fix that(meanwhile we should rename that config to 'custom_headers' to avoid confusion)

@alt-glitch alt-glitch added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 21, 2026
# Conflicts:
#	run_agent.py
#	tests/run_agent/test_switch_model_context.py
# Conflicts:
#	agent/context_compressor.py
# Conflicts:
#	agent/agent_init.py
#	agent/auxiliary_client.py
#	run_agent.py
#	tests/agent/test_turn_context.py
#	tools/delegate_tool.py
# Conflicts:
#	tools/delegate_tool.py
# Conflicts:
#	agent/anthropic_adapter.py
#	agent/auxiliary_client.py
# Conflicts:
#	tools/transcription_tools.py
@alt-glitch alt-glitch added needs-decision Awaiting maintainer decision before any implementation area/auth Authentication, OAuth, credential pools area/compression Context compression and continuation sessions provider/anthropic Anthropic native Messages API provider/kimi Kimi / Moonshot labels Jul 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related: #9518, #56244, and #50796 are the active custom-header cluster. Current #14314 carries both provider-level extra-header handling and backward-compatible model custom headers across more runtime paths, so it is related rather than a duplicate. A maintainer should select the canonical contract after the required rebase.

# Conflicts:
#	agent/background_review.py
#	tests/agent/test_auxiliary_named_custom_providers.py
#	tests/agent/test_context_compressor.py
#	tests/agent/test_context_engine.py
#	tests/agent/test_prompt_caching.py
#	tests/agent/test_turn_context.py
#	tests/cli/test_cli_provider_resolution.py
#	tests/hermes_cli/test_config.py
#	tests/hermes_cli/test_runtime_provider_resolution.py
#	tests/hermes_cli/test_tui_resume_flow.py
#	tests/tools/test_transcription_tools.py
@alt-glitch alt-glitch removed the area/compression Context compression and continuation sessions label Jul 31, 2026
# Conflicts:
#	agent/auxiliary_client.py
#	hermes_cli/runtime_provider.py
#	tests/agent/test_context_compressor.py
# Conflicts:
#	agent/auxiliary_client.py
#	agent/turn_context.py
@alt-glitch alt-glitch added P2 Medium — degraded but workaround exists provider/openai OpenAI / Codex Responses API and removed area/auth Authentication, OAuth, credential pools P3 Low — cosmetic, nice to have labels Aug 6, 2026
# Conflicts:
#	acp_adapter/server.py
#	agent/auxiliary_client.py
#	tests/agent/test_turn_context.py
#	tests/test_tui_gateway_server.py
#	tui_gateway/server.py
# Conflicts:
#	agent/auxiliary_client.py
# Conflicts:
#	agent/anthropic_adapter.py
# Conflicts:
#	agent/background_review.py
#	agent/context_compressor.py
#	hermes_cli/config.py
#	hermes_cli/model_switch.py
#	tools/delegate_tool.py
@alt-glitch alt-glitch removed the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/acp Agent Communication Protocol adapter comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists provider/anthropic Anthropic native Messages API provider/kimi Kimi / Moonshot provider/openai OpenAI / Codex Responses API sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/delegate Subagent delegation tool/tts Text-to-speech and transcription type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Support custom HTTP headers via config.yaml

5 participants