Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion run_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -4364,7 +4364,9 @@ def _create_openai_client(self, client_kwargs: dict, *, reason: str, shared: boo
# wrapped a closed transport and raised "Cannot send a request, as the client
# has been closed" on every retry. The revert resolved that specific path; this
# copy locks the contract so future transport/keepalive work can't reintroduce
# the same class of bug.
# the same class of bug. (#11249: the same in-place mutation also caused all
# per-request clients to share the primary's httpx.Client — closing any request
# client silently closed the primary too, breaking all subsequent calls.)
client_kwargs = dict(client_kwargs)
_validate_proxy_env_urls()
_validate_base_url(client_kwargs.get("base_url"))
Expand Down
10 changes: 10 additions & 0 deletions tests/run_agent/test_create_openai_client_kwargs_isolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@
(#10324, connections hanging in CLOSE-WAIT) is still open, so another transport
tweak inside this function is likely. This test pins the contract that the
function must treat its input dict as read-only.

#11249 reported the same class of bug: without the shallow-copy guard,
``_create_openai_client()`` wrote ``http_client`` back into the caller's dict,
so every subsequent ``dict(self._client_kwargs)`` shallow-copy shared the
*same* ``httpx.Client`` instance that was created for the primary client.
Closing any request-scoped OpenAI client would therefore also close the
primary's underlying transport, causing ``RuntimeError: Cannot send a request,
as the client has been closed`` on all calls after the first. The fix —
``client_kwargs = dict(client_kwargs)`` at the top of the method — ensures
each invocation operates on an independent local copy.
"""
from unittest.mock import MagicMock, patch

Expand Down