diff --git a/agent/transports/codex.py b/agent/transports/codex.py index 6738ed3220cf..ccc36005be9b 100644 --- a/agent/transports/codex.py +++ b/agent/transports/codex.py @@ -5,12 +5,31 @@ streaming, or the _run_codex_stream() call path. """ +import hashlib from typing import Any, Dict, List, Optional from agent.transports.base import ProviderTransport from agent.transports.types import NormalizedResponse, ToolCall +_PROMPT_CACHE_KEY_MAX_LENGTH = 64 + + +def _safe_prompt_cache_key(value: str) -> str: + """Return a Codex-compatible prompt_cache_key. + + The Codex backend rejects prompt_cache_key values longer than 64 + characters. Hermes session IDs can exceed that when gateway/platform + routing embeds long external identifiers. Preserve short IDs for + debuggability and hash only oversized values into a stable 64-character + scope key. + """ + raw = str(value or "").strip() + if len(raw) <= _PROMPT_CACHE_KEY_MAX_LENGTH: + return raw + return hashlib.sha256(raw.encode("utf-8")).hexdigest() + + class ResponsesApiTransport(ProviderTransport): """Transport for api_mode='codex_responses'. @@ -101,7 +120,7 @@ def build_kwargs( session_id = params.get("session_id") if not is_github_responses and session_id: - kwargs["prompt_cache_key"] = session_id + kwargs["prompt_cache_key"] = _safe_prompt_cache_key(str(session_id)) if reasoning_enabled and is_xai_responses: from agent.model_metadata import grok_supports_reasoning_effort diff --git a/tests/agent/transports/test_codex_transport.py b/tests/agent/transports/test_codex_transport.py index 6a4cda173ad4..25a98196a59b 100644 --- a/tests/agent/transports/test_codex_transport.py +++ b/tests/agent/transports/test_codex_transport.py @@ -91,6 +91,16 @@ def test_session_id_sets_cache_key(self, transport): ) assert kw.get("prompt_cache_key") == "test-session-123" + def test_long_session_id_cache_key_is_hashed_to_backend_limit(self, transport): + messages = [{"role": "user", "content": "Hi"}] + long_session_id = "atlas:4CGVtvUxCQrizW2tuRbqNa25nLnClXPm:494fd2fb-ca04-431b-a26d-f6c255d0804e" + kw = transport.build_kwargs( + model="gpt-5.4", messages=messages, tools=[], + session_id=long_session_id, + ) + assert len(kw.get("prompt_cache_key")) == 64 + assert kw.get("prompt_cache_key") != long_session_id + def test_github_responses_no_cache_key(self, transport): messages = [{"role": "user", "content": "Hi"}] kw = transport.build_kwargs(