fix(codex): clamp prompt_cache_key to 64 chars for Codex/ChatGPT backend - #62266
JoaoMarcos44 wants to merge 1 commit into
Conversation
The OpenAI Responses / ChatGPT-Codex backend rejects prompt_cache_key values over 64 chars with HTTP 400. The key falls back to raw session_id when there's no static content to hash, and session_id is caller-supplied and unbounded (e.g. control-plane session keys like agent:<uuid>:issue:<uuid> can run ~140 chars), so a long session_id broke every call. prompt_cache_key is a routing hint only, never a correctness boundary, so truncating it is safe. Fixes NousResearch#62063 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Duplicate of #24273 (earliest open PR, created 2026-05-12) — same code site and mechanism (bounding |
|
Verified this against current main and the PR branch:
Prior art note for maintainers: #24273 (May) proposed the same clamp idea ( Optional: plain LGTM — small, well-tested, and correctly scoped. |
|
This is an automated hermes-sweeper review. Current
The raw fallback expression remains in the source, but current instruction resolution makes it unreachable for the reported API/gateway flow. |
Summary
prompt_cache_keyat 64 chars and returns HTTP 400 ("string too long") past that.agent/transports/codex.py::build_kwargsfalls back to the rawsession_idfor the cache key when there's no static content to hash.session_idis caller-supplied and unbounded (e.g. control-plane session keys likeagent:<uuid>:issue:<uuid>run ~140 chars), so any session_id over 64 chars broke every call on this backend.cache_keyto 64 chars right after it's computed, before it's used askwargs["prompt_cache_key"](Codex path) orextra_body["prompt_cache_key"](xAI path). Per the existing docstring, the key is a routing hint only — never a correctness boundary — so truncation is safe.Root cause detail
_content_cache_key()returns a boundedpck_<hash>(28 chars) wheneverinstructionsortoolsis non-empty. In today's call pathinstructionsalways falls back toDEFAULT_AGENT_IDENTITYwhen unset, so in practice the raw-session_idfallback is rarely hit — but it's still reachable (e.g. if that fallback logic changes, or the caller passes tools=None/instructions="" through a path that skips the identity fallback), and when it is hit, the value is completely unbounded. The clamp closes this at the single point of consumption so it can never regress regardless of what feedscache_key.Test plan
tests/agent/transports/test_codex_transport.py::test_cache_key_session_id_fallback_clamped_to_64_chars— forces the fallback (monkeypatches_content_cache_keyto returnNone) with a 146-char session_id and asserts the resultingprompt_cache_keyis exactly 64 chars.tests/agent/transports/test_codex_transport.py::test_content_cache_key_is_none_only_when_both_empty— pins down the exact trigger condition for the fallback.tests/agent/transports/test_codex_transport.py::test_realistic_call_never_leaks_raw_long_session_id_today— production-shaped call (no explicitinstructions, matchingagent/chat_completion_helpers.py) with a 146-char session_id; confirms the emitted key is always the bounded content hash.