Skip to content

Commit 64ccd26

Browse files
committed
fix(client-sdks): guard call_api patch for stainless SDK fallback compatibility
The call_api patch in OGXAsLibraryClient.__init__ unconditionally accessed self.api_client.call_api, but the stainless SDK OgxClient does not have an api_client attribute. Guard with hasattr checks so the fallback to the stainless SDK (which uses the request() override instead) still works. Also add try/except fallback for the ogx_open_client.rest import in _async_in_process_call to avoid ModuleNotFoundError when only the stainless SDK is installed. Signed-off-by: E Geiger <egeiger@redhat.com>
1 parent 4a20fca commit 64ccd26

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

src/ogx/core/library_client.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,10 @@ def __init__(
219219
# Patch api_client.call_api to route requests in-process instead of over HTTP.
220220
# The generated SDK's call chain is: API method → api_client.call_api() → rest.request() → httpx.
221221
# We intercept at call_api so the request never reaches httpx/network.
222-
self._original_call_api = self.api_client.call_api
223-
self.api_client.call_api = self._in_process_call_api # type: ignore[method-assign]
222+
# Only applies to ogx_open_client; the stainless SDK uses a request() override instead.
223+
if hasattr(self, "api_client") and hasattr(self.api_client, "call_api"):
224+
self._original_call_api = self.api_client.call_api
225+
self.api_client.call_api = self._in_process_call_api # type: ignore[method-assign]
224226

225227
def _run_event_loop(self) -> None:
226228
"""Runs forever in the background thread."""
@@ -412,7 +414,11 @@ async def _async_in_process_call(
412414
from urllib.parse import urlparse
413415

414416
from fastapi.responses import StreamingResponse
415-
from ogx_open_client.rest import RESTResponse
417+
418+
try:
419+
from ogx_open_client.rest import RESTResponse
420+
except ImportError:
421+
from ogx_client.rest import RESTResponse # type: ignore[assignment]
416422

417423
async_client = self.async_client
418424
assert async_client.route_impls is not None, "Client not initialized"
@@ -493,7 +499,12 @@ async def _async_in_process_call(
493499

494500
# Build the response
495501
if isinstance(result, StreamingResponse):
496-
# Streaming response — collect SSE chunks into a sync-iterable response
502+
# Streaming response — collect SSE chunks into a sync-iterable response.
503+
# TODO: This buffers the entire stream before returning, losing time-to-first-token
504+
# benefits. For true incremental streaming, we'd need a SyncByteStream adapter that
505+
# bridges the async generator to sync iter_bytes() via a queue (similar to
506+
# _stream_request). Acceptable for now since in-process library mode is primarily
507+
# used for testing, not latency-sensitive production streaming.
497508
content_type = result.media_type or "text/event-stream"
498509

499510
# Collect all chunks from the async generator

0 commit comments

Comments
 (0)