Header propagation bugs across routed providers and agents
NousResearch/hermes-agent · cluster 8779 · agent
Data as of
Nothing open on GitHub. Fix merged in #50298. Check it covers your case.
The short answer
- Known?
- Yes. 9 related items grouped here, 3 issues already closed.
- Fix event
- A fix was merged to main in PR #50298. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
partially resolved, deciding PR #50298. That is separate from the fix event. - Still open
- Nothing open on GitHub.
Multiple bugs and fixes around SDK client headers being read from wrong attributes (_default_headers vs _custom_headers vs public default_headers), causing custom or routed provider headers to be silently dropped before requests. Touches Copilot, Codex, NVIDIA NIM, Kimi, and agent transport layers.
Open issues0
Open PRs0
Fixes on record
-
#50298 fix(agent): Copilot Claude chat-completions — plain httpx transport + preserve routed headers (#12066)
files:
agent/agent_init.py,run_agent.py,tests/run_agent/test_create_openai_client_proxy_env.py,tests/run_agent/test_provider_attribution_headers.pyShow the diff
-
agent/agent_init.py@@ -808,6 +808,8 @@ def init_agent( # _custom_headers; older/mocked clients may expose # _default_headers instead. _routed_headers = getattr(_routed_client, "_custom_headers", None) + if not _routed_headers: + _routed_headers = getattr(_routed_client, "default_headers", None) if not _routed_headers: _routed_headers = getattr(_routed_client, "_default_headers", None) if _routed_headers: @@ -861,6 +863,8 @@ def init_agent( if _provider_timeout is not None: client_kwargs["timeout"] = _provider_timeout _fb_headers = getattr(_fb_client, "_custom_headers", None) + if not _fb_headers: + _fb_headers = getattr(_fb_client, "default_headers", None) if not _fb_headers: _fb_headers = getattr(_fb_client, "_default_headers", None) if _fb_headers: -
run_agent.py@@ -3557,6 +3557,9 @@ def _build_keepalive_http_client(base_url: str = "") -> Any: import httpx as _httpx import socket as _socket + if "api.githubcopilot.com" in str(base_url or "").lower(): + return _httpx.Client() + _sock_opts = [(_socket.SOL_SOCKET, _socket.SO_KEEPALIVE, 1)] if hasattr(_socket, "TCP_KEEPIDLE"): _sock_opts.append((_socket.IPPROTO_TCP, _socket.TCP_KEEPIDLE, 30)) -
tests/run_agent/test_create_openai_client_proxy_env.py@@ -145,6 +145,27 @@ def test_create_openai_client_no_proxy_when_env_unset(mock_openai, monkeypatch): http_client.close() +@patch("run_agent.OpenAI") +def test_create_openai_client_uses_plain_httpx_client_for_copilot(mock_openai, monkeypatch): + """Copilot Claude chat-completions rejects the custom socket-options transport.""" + for key in ("HTTPS_PROXY", "HTTP_PROXY", "ALL_PROXY", + "https_proxy", "http_proxy", "all_proxy"): + monkeypatch.delenv(key, raising=False) + + agent = _make_agent() + kwargs = { + "api_key": "test-key", + "base_url": "https://api.githubcopilot.com", + } + agent._create_openai_client(kwargs, reason="test", shared=False) + + forwarded = mock_openai.call_args.kwargs + http_client = _extract_http_client(forwarded) + assert isinstance(http_client, httpx.Client) + assert getattr(http_client._transport._pool, "_socket_options", None) is None + http_client.close() + + def test_get_proxy_for_base_url_returns_none_when_host_bypassed(monkeypatch): """NO_PROXY must suppress the proxy for matching base_urls. -
tests/run_agent/test_provider_attribution_headers.py@@ -109,6 +109,31 @@ def test_routed_client_preserves_openai_sdk_custom_headers(mock_openai): assert headers["X-BILLING-INVOKE-ORIGIN"] == "HermesAgent" +@patch("run_agent.OpenAI") +def test_routed_client_preserves_openai_sdk_default_headers(mock_openai): + mock_openai.return_value = MagicMock() + routed_client = SimpleNamespace( + api_key="[redacted:secret-assignment]", + base_url="https://api.githubcopilot.com", + default_headers={"copilot-integration-id": "vscode-chat"}, + ) + + with patch("agent.auxiliary_client.resolve_provider_client", return_value=( + routed_client, + "claude-opus-4.7", + )): + agent = AIAgent( + provider="copilot", + model="claude-opus-4.7", + quiet_mode=True, + skip_context_files=True, + skip_memory=True, + ) + + headers = agent._client_kwargs["default_headers"] + assert headers["copilot-integration-id"] == "vscode-chat" + + @patch("run_agent.OpenAI") def test_gmi_base_url_picks_up_profile_user_agent(mock_openai): """GMI declares User-Agent on its ProviderProfile.default_headers.
-
5 PRs closed without merging
From the close comments: done elsewhere 3 · merged via another change 2
-
#8784 Bugfix: preserve routed provider default headers · done elsewhere →
3e354b6,#8799 - #8799 fix(run_agent): use public default_headers attr when preserving routed client headers · done elsewhere
-
#15185 fix(copilot): honor SDK v2 _custom_headers + skip keepalive transport for Claude (#12066) · merged via another change →
3e354b6,#50298,#39159 -
#19985 fix(codex): copy headers from _custom_headers (SDK >= 1.x) not _default_headers · done elsewhere →
27df249 -
#39159 fix(agent): preserve copilot routed headers · merged via another change →
3e354b6,#50298,#10324
Closed issues · 3
- Closed#8779[Bug]: run_agent.py uses _default_headers instead of default_headers, dropping routed client headers and breaking Kimi API
- Closed#12066[Bug]: Copilot Claude chat-completions fails in Hermes with model_not_supported when direct requests succeed
- Closed#19981[Bug]: openai-codex headers from PR #12664 are read off wrong SDK attribute (_default_headers vs _custom_headers), silently dropped before request
How this cluster was grouped
-
Link evidence (
partly structural links): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text. - Members outside that structural core may belong to a different underlying problem.
-
Pairwise link density
0.20: the share of item pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36.1.00means every pair is linked.
Pick up a Lab task
Check whether a fix covers the open issues here, with your own agent. Bring back evidence for maintainers.
Open the LabAt a glance
- Subsystem
- agent
- Merged PRs
- #50298
- Closed issues
- 3
- Attempts
- 5 PRs closed without merging
- Fix link checked
- 21 Jun 2026