From defdfa28bc4b54931b4c258732b90cf5a90fbfb5 Mon Sep 17 00:00:00 2001 From: AlexFucuson9 Date: Fri, 17 Jul 2026 17:42:17 +0700 Subject: [PATCH 1/2] fix(codex): hash over-length prompt_cache_key to fit 64-char limit The Codex/OpenAI backend rejects prompt_cache_key > 64 chars with HTTP 400 BadRequestError. When _content_cache_key falls back to session_id (no static instructions+tools to hash), the key can be arbitrarily long (e.g. paperclip:company::agent: at 97 chars). The 400 is masked by the fallback chain, making the primary provider look unused. Fix: after computing cache_key, hash it to pck_ when it exceeds 64 chars. hashlib is already imported. The xAI extra_body path also benefits since it reads the same cache_key variable. Closes #66045 --- agent/transports/codex.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/agent/transports/codex.py b/agent/transports/codex.py index ef7ffbaffd245..227a4399edd77 100644 --- a/agent/transports/codex.py +++ b/agent/transports/codex.py @@ -265,6 +265,12 @@ def build_kwargs( # the cache-scope routing headers below. Falls back to session_id when # there is no static content to hash. cache_key = _content_cache_key(instructions, response_tools) or session_id + # The backend rejects prompt_cache_key > 64 chars with HTTP 400. + # When _content_cache_key falls back to session_id the key can be + # arbitrarily long (e.g. "paperclip:company::agent:" at + # 97 chars). Hash over-length keys so they always fit. + if cache_key and len(cache_key) > 64: + cache_key = f"pck_{hashlib.sha256(cache_key.encode('utf-8', 'replace')).hexdigest()[:24]}" # xAI Responses takes prompt_cache_key in extra_body (set further # down); GitHub Models opts out of cache-key routing entirely. if not is_github_responses and not is_xai_responses and cache_key: From 4fbf72da1aefb46af2f5d292cd434712849b33a8 Mon Sep 17 00:00:00 2001 From: AlexFucuson9 Date: Fri, 17 Jul 2026 17:50:33 +0700 Subject: [PATCH 2/2] fix(compression): respect user-configured threshold below 0.50 on small-ctx models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The small-context threshold floor (_SMALL_CTX_THRESHOLD_PERCENT = 0.75) raises any model under 512K context to at least 75% threshold. This is a safety net to prevent thrashing on 128K-262K models at the default 50% trigger. But when a user explicitly sets threshold: 0.3 (30%) to stay within TPM rate limits (e.g. 100K TPM on a 160K-ctx reasoning model), the floor overrides their config to 75% (120K tokens). Compression never fires, context grows to 55K+, and every API call exceeds the 100K TPM budget — cascading 429 errors. Fix: only apply the 75% floor when the configured threshold is at or above the default (0.50). A value below 0.50 signals deliberate user configuration — respect it. Closes #66177 --- agent/context_compressor.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/agent/context_compressor.py b/agent/context_compressor.py index 7c7b5ec330d69..d728bee078349 100644 --- a/agent/context_compressor.py +++ b/agent/context_compressor.py @@ -1181,9 +1181,20 @@ def _effective_threshold_percent( e.g. Codex gpt-5.5's 85%) always wins; only lower values are raised. Large-context models keep the configured value — at 512K+ the default 50% trigger already leaves ample post-compaction headroom. + + The floor is a safety net for the *default* threshold (0.50), not a + hard override of explicit user configuration. When a user sets + ``threshold: 0.3`` to stay within TPM rate limits (e.g. 100K TPM on + a 160K-ctx reasoning model), forcing 75% prevents compression from + ever firing and causes cascading 429s. Respect the user's value when + it is below the default — they chose it deliberately. """ if context_length and context_length < _SMALL_CTX_WINDOW_LIMIT: - return max(threshold_percent, _SMALL_CTX_THRESHOLD_PERCENT) + # Only apply the floor when the configured value looks like the + # default (>= 0.50). A value below 0.50 signals deliberate user + # configuration — raising it would defeat the purpose. + if threshold_percent >= 0.50: + return max(threshold_percent, _SMALL_CTX_THRESHOLD_PERCENT) return threshold_percent @staticmethod