Codex backend extra_headers handling fixes
NousResearch/hermes-agent · cluster 26599 · agent
Data as of
Nothing open on GitHub. Fix merged in #45633. Check it covers your case.
The short answer
- Known?
- Yes. 5 related items grouped here, 1 issue already closed.
- Fix event
- A fix was merged to main in PR #45633. Check it covers your case. No release data is tracked.
- Tracker
- The maintainers' tracker marks this
resolved, deciding PR #45633. That is separate from the fix event. - Still open
- Nothing open on GitHub.
These issues and PRs address problems with extra_headers being incorrectly sent to the Codex/chatgpt.com backend, causing HTTP 400 errors, alongside related work on session and cache-routing headers.
Open issues0
Open PRs0
Fixes on record
-
#45633 fix(codex): drop extra_headers for chatgpt.com backend
files:
agent/transports/codex.py,tests/agent/transports/test_codex_transport.py -
#47836 fix(codex): restore session_id/x-client-request-id HTTP headers for cache routing (#47335)
files:
agent/transports/codex.py,tests/agent/transports/test_codex_transport.pyShow the diff
-
agent/transports/codex.py@@ -218,10 +218,28 @@ def build_kwargs( kwargs.pop("timeout", None) if is_codex_backend: - # chatgpt.com/backend-api/codex rejects body-level - # ``extra_headers`` with HTTP 400. Correlation/cache routing for - # this backend must not be sent through the Responses payload. - kwargs.pop("extra_headers", None) + # The Codex backend rejects body-level ``extra_headers`` with + # HTTP 400, but the OpenAI SDK's ``extra_headers`` kwarg maps + # to actual HTTP request headers (not body fields). We need + # these headers for cache-scope routing so prompt cache hits + # remain high. Send session_id / x-client-request-id as HTTP + # headers while keeping ``prompt_cache_key`` in the body for + # standard OpenAI routing as a belt-and-braces fallback. + cache_scope_id = str(session_id or "").strip() + if cache_scope_id: + existing_extra_headers = kwargs.get("extra_headers") + merged_extra_headers: Dict[str, str] = {} + if isinstance(existing_extra_headers, dict): + merged_extra_headers.update( + { + str(key): str(value) + for key, value in existing_extra_headers.items() + if key and value is not None + } + ) + merged_extra_headers["session_id"] = cache_scope_id + merged_extra_headers["x-client-request-id"] = cache_scope_id + kwargs["extra_headers"] = merged_extra_headers max_tokens = [redacted:secret-assignment]"max_tokens") if max_tokens is not None and not is_codex_backend: -
tests/agent/transports/test_codex_transport.py@@ -155,7 +155,9 @@ def test_codex_backend_no_max_output_tokens(self, transport): ) assert "max_output_tokens" not in kw - def test_codex_backend_does_not_set_extra_headers(self, transport): + def test_codex_backend_sets_cache_routing_headers(self, transport): + """Codex backend sends session_id / x-client-request-id as HTTP + headers (via extra_headers) for cache-scope routing.""" messages = [{"role": "user", "content": "Hi"}] kw = transport.build_kwargs( @@ -166,9 +168,23 @@ def test_codex_backend_does_not_set_extra_headers(self, transport): is_codex_backend=True, ) + headers = kw.get("extra_headers", {}) + assert headers.get("session_id") == "conv-codex-1" + assert headers.get("x-client-request-id") == "conv-codex-1" + + def test_codex_backend_no_headers_without_session_id(self, transport): + messages = [{"role": "user", "content": "Hi"}] + + kw = transport.build_kwargs( + model="gpt-5.4", + messages=messages, + tools=[], + is_codex_backend=True, + ) + assert "extra_headers" not in kw - def test_codex_backend_strips_caller_extra_headers(self, transport): + def test_codex_backend_preserves_caller_extra_headers(self, transport): messages = [{"role": "user", "content": "Hi"}] kw = transport.build_kwargs( @@ -180,7 +196,10 @@ def test_codex_backend_strips_caller_extra_headers(self, transport): request_overrides={"extra_headers": {"x-test": "1"}}, ) - assert "extra_headers" not in kw + headers = kw.get("extra_headers", {}) + assert headers.get("x-test") == "1" + assert headers.get("session_id") == "conv-codex-1" + assert headers.get("x-client-request-id") == "conv-codex-1" def test_non_codex_responses_preserves_caller_extra_headers(self, transport): messages = [{"role": "user", "content": "Hi"}]
-
2 PRs closed without merging
From the close comments: done elsewhere 1 · merged via another change 1
Closed issues · 1
- Closed#26599[Bug]: Codex backend rejects 'extra_headers' field in Responses payload (HTTP 400)
How this cluster was grouped
-
Link evidence (
structural links throughout): every member is connected by structural evidence: shared changed files, or a closing/superseded reference. -
Pairwise link density
0.40: 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 Lab