test(agent): cover the codex iteration-summary retry path
Iteration-limit summaries retry once when the first attempt comes back empty. Both attempts share one builder closure, so assert the retry body is as tool-free as the first: forces an empty summary, then checks every captured codex request for tools / tool_choice / parallel_tool_calls. Addresses the retry-coverage request on #32777.
This commit is contained in:
@@ -2947,6 +2947,58 @@ class TestHandleMaxIterations:
|
||||
assert "tool_choice" not in captured
|
||||
assert "parallel_tool_calls" not in captured
|
||||
|
||||
def test_codex_summary_retry_also_strips_tool_controls(self, agent):
|
||||
"""The retry attempt must be as toolless as the first one.
|
||||
|
||||
Iteration-limit summaries retry once when the first summary comes back empty; both
|
||||
attempts build their body through the same codex path, so both must drop the tool-control
|
||||
block the transport emits alongside ``tools`` (agent/transports/codex.py).
|
||||
"""
|
||||
agent.api_mode = "codex_responses"
|
||||
agent.provider = "openai-codex"
|
||||
agent.base_url = "https://chatgpt.com/backend-api/codex"
|
||||
agent._base_url_lower = agent.base_url.lower()
|
||||
agent._base_url_hostname = "chatgpt.com"
|
||||
agent.model = "gpt-5.5"
|
||||
agent._cached_system_prompt = "You are helpful."
|
||||
|
||||
bodies = []
|
||||
tool_laden = {
|
||||
"model": "gpt-5.5",
|
||||
"input": [{"role": "user", "content": "do stuff"}],
|
||||
"tools": [{"type": "function", "name": "web_search"}],
|
||||
"tool_choice": "auto",
|
||||
"parallel_tool_calls": True,
|
||||
}
|
||||
|
||||
def fake_run_codex_stream(kwargs):
|
||||
bodies.append(dict(kwargs))
|
||||
# First attempt returns an empty summary so the caller takes the retry path.
|
||||
text = "" if len(bodies) == 1 else "Summary"
|
||||
return SimpleNamespace(
|
||||
status="completed",
|
||||
output=[
|
||||
SimpleNamespace(
|
||||
type="message",
|
||||
status="completed",
|
||||
content=[SimpleNamespace(type="output_text", text=text)],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
with (
|
||||
patch.object(agent, "_build_api_kwargs", return_value=tool_laden.copy()),
|
||||
patch.object(agent, "_run_codex_stream", side_effect=fake_run_codex_stream),
|
||||
):
|
||||
result = agent._handle_max_iterations([{"role": "user", "content": "do stuff"}], 90)
|
||||
|
||||
assert result == "Summary"
|
||||
assert len(bodies) == 2, f"expected one retry after the empty summary, got {len(bodies)} attempts"
|
||||
for attempt_index, sent in enumerate(bodies):
|
||||
assert "tools" not in sent, f"attempt {attempt_index}: tools leaked into the summary call"
|
||||
assert "tool_choice" not in sent, f"attempt {attempt_index}: tool_choice leaked"
|
||||
assert "parallel_tool_calls" not in sent, f"attempt {attempt_index}: parallel_tool_calls leaked"
|
||||
|
||||
def test_api_sanitizer_matches_responses_call_id_when_id_differs(self, agent):
|
||||
messages = [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user