test(codex): pin the retention drop to real endpoints

The salvaged compatibility test stubs `_is_codex_backend=lambda: False` on a
SimpleNamespace, so it proves the helper honors its own boolean but not that
the boolean is right for any real endpoint. A predicate change that widened
the drop onto retention-supporting hosts would keep it green.

Adds a parametrized test that builds a real AIAgent per base URL and asserts
the drop only fires for chatgpt.com/backend-api/codex, while api.meta.ai,
bedrock-mantle.*.api.aws, api.openai.com and a same-host/different-path
backend keep their supported 24h value. Also asserts prompt_cache_key
survives untouched on every endpoint, since retention and cache-key routing
are independent and the guard must not disturb caching.

Verified non-vacuous: relaxing the guard's condition to drop on every
endpoint fails 4 of the 6 cases (Meta, Bedrock, OpenAI, non-codex path).

Drive-by on the guard itself: drop the dead `None` default on the `pop` that
is already gated by an `in` check, and record why the predicate is resolved
via getattr -- run_codex_stream is driven with lightweight stand-in agents
that lack `_is_codex_backend`, so a bare call would raise AttributeError.
This commit is contained in:
kshitijk4poor
2026-08-20 01:25:23 +05:30
committed by kshitij
parent c7b6854ba1
commit ba4bc39afd
2 changed files with 62 additions and 1 deletions
+5 -1
View File
@@ -1322,12 +1322,16 @@ def _sanitize_consumer_codex_request(
rejected by the provider.
"""
sanitized = dict(request)
# Resolved defensively on purpose: run_codex_stream is also driven with
# lightweight stand-in agents that carry only the attributes a given path
# needs (see tests/agent/test_codex_request_transport_diagnostics.py), so a
# bare agent._is_codex_backend() here would raise AttributeError on them.
backend_predicate = getattr(agent, "_is_codex_backend", None)
is_consumer_codex = (
bool(backend_predicate()) if callable(backend_predicate) else False
)
if is_consumer_codex and "prompt_cache_retention" in sanitized:
sanitized.pop("prompt_cache_retention", None)
sanitized.pop("prompt_cache_retention")
logger.warning(
"Dropped unsupported prompt_cache_retention at consumer Codex "
"wire boundary (model=%s).",
@@ -602,6 +602,63 @@ def test_consumer_codex_wire_guard_preserves_compatible_endpoint_retention():
assert sanitized is not request
@pytest.mark.parametrize(
"base_url,model,expect_dropped",
[
# Consumer ChatGPT Codex: the endpoint rejects retention outright.
("https://chatgpt.com/backend-api/codex", "gpt-5.6-sol", True),
("https://chatgpt.com/backend-api/codex", "gpt-5-codex", True),
# Hosts that support 24h retention must keep it (#70083, #88601).
("https://api.meta.ai/v1", "gpt-5.6-sol", False),
("https://bedrock-mantle.us-east-1.api.aws/v1", "openai.gpt-5.5", False),
# Non-Codex OpenAI and a same-host/different-path backend are both
# outside the consumer-Codex contract the guard enforces.
("https://api.openai.com/v1", "gpt-5.6-sol", False),
("https://chatgpt.com/backend-api/other", "gpt-5.6-sol", False),
],
)
def test_wire_guard_scopes_retention_drop_by_real_endpoint(
monkeypatch,
base_url,
model,
expect_dropped,
):
"""The drop is scoped by the real endpoint, not by a stubbed predicate.
The sibling test above pins the helper's contract against an explicit
boolean. This one drives ``_is_codex_backend()`` off a real ``AIAgent``
built on each base URL, so a change to the hostname/path predicate that
widened the drop onto retention-supporting hosts would fail here.
"""
from agent.codex_runtime import _sanitize_consumer_codex_request
_patch_agent_bootstrap(monkeypatch)
agent = run_agent.AIAgent(
model=model,
api_mode="codex_responses",
base_url=base_url,
api_key="codex-token",
quiet_mode=True,
max_iterations=4,
skip_context_files=True,
skip_memory=True,
)
request = {
"model": model,
"prompt_cache_key": "cache-key-sentinel",
"prompt_cache_retention": "24h",
"input": [{"role": "user", "content": "hi"}],
}
sanitized = _sanitize_consumer_codex_request(agent, request)
assert ("prompt_cache_retention" not in sanitized) is expect_dropped
# Cache-key routing is independent of retention: the guard must never
# disturb the prompt-cache key, on any endpoint.
assert sanitized["prompt_cache_key"] == "cache-key-sentinel"
assert request["prompt_cache_retention"] == "24h"
def test_run_codex_stream_returns_collected_items_when_stream_ends_without_terminal(monkeypatch):
"""The event-driven path tolerates streams that end without a terminal frame.