From fc441a01df33fc22c1b8ade3742118d37d5d1b59 Mon Sep 17 00:00:00 2001 From: Roland Tannous Date: Mon, 30 Mar 2026 18:50:24 +0000 Subject: [PATCH] fix: call response.aclose() before lines_gen.aclose() to prevent httpcore RuntimeError on Python 3.13 --- .../core/inference/external_provider.py | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/studio/backend/core/inference/external_provider.py b/studio/backend/core/inference/external_provider.py index c575b711c7..e1bdd0ca0c 100644 --- a/studio/backend/core/inference/external_provider.py +++ b/studio/backend/core/inference/external_provider.py @@ -117,13 +117,22 @@ class ExternalProviderClient: ) return - lines_iter = response.aiter_lines() + lines_gen = response.aiter_lines().__aiter__() try: - async for line in lines_iter: + while True: + try: + line = await lines_gen.__anext__() + except StopAsyncIteration: + break if line.strip(): yield line + except GeneratorExit: + await response.aclose() # set PoolByteStream._closed=True FIRST + await lines_gen.aclose() # now safe — aclose() is a no-op + raise finally: - await lines_iter.aclose() + await response.aclose() + await lines_gen.aclose() except httpx.ConnectError as exc: logger.error("Connection error to %s: %s", self.provider_type, exc) @@ -242,9 +251,13 @@ class ExternalProviderClient: yield _error_sse_line(response.status_code, error_text, self.provider_type) return - lines_iter = response.aiter_lines() + lines_gen = response.aiter_lines().__aiter__() try: - async for line in lines_iter: + while True: + try: + line = await lines_gen.__anext__() + except StopAsyncIteration: + break if not line or line.startswith("event:"): continue if not line.startswith("data:"): @@ -291,9 +304,15 @@ class ExternalProviderClient: elif event_type == "message_stop": yield "data: [DONE]" - return + await response.aclose() # set PoolByteStream._closed=True FIRST + break + except GeneratorExit: + await response.aclose() # set PoolByteStream._closed=True FIRST + await lines_gen.aclose() # now safe — aclose() is a no-op + raise finally: - await lines_iter.aclose() + await response.aclose() + await lines_gen.aclose() except httpx.ConnectError as exc: logger.error("Connection error to %s: %s", self.provider_type, exc)