fix: close Chat Completions streams on early exit#3689
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ec5174fe5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| model=self.model, | ||
| strict_feature_validation=self._strict_feature_validation, | ||
| ): | ||
| yield chunk |
There was a problem hiding this comment.
Set terminal state before yielding completed events
When a consumer breaks or closes the async generator immediately after receiving response.completed, execution is still suspended at this yield, so the bookkeeping on lines 348-350 never runs. In that common early-exit-after-terminal scenario, yielded_terminal_event remains false and any provider-stream close error is re-raised instead of being ignored for an already terminal stream; move the completed-event bookkeeping before yielding the chunk.
Useful? React with 👍 / 👎.
seratch
left a comment
There was a problem hiding this comment.
Thanks for the contribution. The implementation aligns with the existing Responses cleanup behavior and looks sound.
Before merging, please update the regression test to exercise asynchronous close(), which is the method exposed by the actual OpenAI AsyncStream, rather than only testing aclose(). The broader cancellation behavior is already covered by the equivalent Responses tests and does not need to be duplicated here.
Once that focused test change is made, this should be ready to merge.
Summary
stream_response()when iteration ends early or normally.Why
The Chat Completions streaming path previously yielded converted events from the provider stream without closing the underlying HTTP/SSE stream if the caller stopped early. That can leave provider resources open longer than intended.
Tests
uv run pytest tests/models/test_openai_chatcompletions_stream.py::test_stream_response_close_closes_provider_streamuv run pytest tests/models/test_openai_chatcompletions_stream.pyuv run ruff check src/agents/models/openai_chatcompletions.py tests/models/test_openai_chatcompletions_stream.py