fix(codex): stop draining interrupted streams

Signed-off-by: Alex Fournier <afournier@nvidia.com>
This commit is contained in:
Alex Fournier 2026-07-23 13:26:49 -07:00
parent 9dfe690125
commit f370af6816
2 changed files with 52 additions and 2 deletions

View File

@ -1350,8 +1350,9 @@ def run_codex_stream(agent, api_kwargs: dict, client: Any = None, on_first_delta
# The terminal SSE frame is contractually last. Request the
# end-of-stream marker so Relay can run its response finalizer
# and close the physical attempt scope before Hermes returns.
for _ignored in event_stream:
pass
if not agent._interrupt_requested:
for _ignored in event_stream:
pass
except (_httpx.RemoteProtocolError, _httpx.ReadTimeout, _httpx.ConnectError, ConnectionError) as exc:
if attempt < max_stream_retries:
logger.debug(

View File

@ -208,6 +208,55 @@ class TestCodexSingleWriter:
assert "".join(delivered) == "hello world"
def test_codex_interrupt_closes_stream_without_draining_provider(self):
from agent.codex_runtime import run_codex_stream
agent = _make_agent()
agent.api_mode = "codex_responses"
produced = []
stream_closed = threading.Event()
def interrupt_after_first_delta(_text):
agent._interrupt_requested = True
agent.stream_delta_callback = interrupt_after_first_delta
agent._stream_callback = None
def event_gen():
try:
produced.append("first")
yield self._codex_event(
"response.output_text.delta",
delta="first",
item_id="i1",
)
produced.append("lookahead")
yield self._codex_event(
"response.output_text.delta",
delta="-unused",
item_id="i1",
)
produced.append("terminal")
yield self._codex_event(
"response.completed",
response=SimpleNamespace(
id="r1",
status="completed",
output=[],
usage=None,
),
)
finally:
stream_closed.set()
mock_client = MagicMock()
mock_client.responses.create.return_value = event_gen()
run_codex_stream(agent, {"model": "gpt-5.3-codex"}, client=mock_client)
assert produced == ["first", "lookahead"]
assert stream_closed.is_set()
if __name__ == "__main__":
raise SystemExit(pytest.main([__file__, "-q"]))