Update the default HTTP client to httpx-aiohttp (httpx with aiohttp transport) insted of httpx.AsyncClient for better concurrency#746
Conversation
Default AsyncBaseCohere now uses HttpxAiohttpClient (subclass of httpx.AsyncClient with aiohttp transport) for better scalability under high parallelism. Callers may still pass a custom httpx.AsyncClient. Add httpx-aiohttp and require httpx>=0.27.0. Sync httpx.Client paths, types (Response, Headers, Request, etc.), and AWS/Bedrock clients are unchanged. Made-with: Cursor
Regression coverage for AsyncClient and AsyncClientV2 when callers supply their own AsyncClient instead of the default aiohttp-backed client. Made-with: Cursor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
| from .types.tokenize_response import TokenizeResponse | ||
| from .types.tool import Tool | ||
| from .types.tool_result import ToolResult | ||
| from httpx_aiohttp import HttpxAiohttpClient |
There was a problem hiding this comment.
Top-level import forces aiohttp for sync-only users
Medium Severity
The from httpx_aiohttp import HttpxAiohttpClient import is at the module top level, unconditionally executed when base_client.py is loaded. Since client.py imports BaseCohere and AsyncBaseCohere from this module, and cohere.__init__ imports from client.py, any import cohere — even for purely sync usage via cohere.Client — triggers loading of httpx_aiohttp and transitively all of aiohttp (including its C extensions). HttpxAiohttpClient is only used inside AsyncBaseCohere.__init__, so the import could be deferred there or placed behind typing.TYPE_CHECKING with a lazy import at the call site.
httpx-aiohttp (httpx with aiohttp transport) insted of httpx.AsyncClient for better concurrency


Summary
This change switches the default async HTTP stack for cohere.AsyncClient (and anything built on AsyncBaseCohere) from a plain httpx.AsyncClient to httpx_aiohttp.HttpxAiohttpClient, which subclasses httpx.AsyncClient but uses aiohttp under the hood for the actual I/O.
That matches the kind of problem discussed for other Python SDKs that rely on httpx for highly concurrent async workloads: the default httpx async path can lag behind aiohttp when many requests run in parallel (see openai-python#1596 and the discussion there, including this comment). We keep httpx’s request/response surface (types, retries, cookies, auth patterns, etc.) while improving scalability for parallel async calls.
Backward compatibility
httpx.AsyncClientviahttpx_client=.... It is used verbatim (not wrapped or replaced).HttpxAiohttpClientis a subclass ofhttpx.AsyncClient, so existing type hints and code that expect anhttpx.AsyncClientremain valid for the default client.Dependencies
httpx-aiohttp.httpxto>=0.27.0to satisfyhttpx-aiohttp.Tests
Test: tests/test_async_client.py — asserts a custom
httpx.AsyncClientis the same object wired into the wrapper for bothAsyncClientandAsyncClientV2.Demo:
scripts/demo_async_client_httpx.py— runs chat with the default client vs an explicithttpx.AsyncClient.Note
Medium Risk
Changes the default async HTTP transport from
httpx.AsyncClienttohttpx_aiohttp.HttpxAiohttpClient, which can alter runtime networking behavior (connection handling, timeouts, redirects) under load. Risk is mitigated by preserving the ability to pass a customhttpx.AsyncClientverbatim and adding coverage for that path.Overview
Switches
AsyncClient/AsyncBaseCohereto usehttpx_aiohttp.HttpxAiohttpClient(aiohttp-backed) as the default async HTTP client to improve concurrency, while still accepting a caller-providedhttpx.AsyncClientunchanged.Updates dependencies to support this (
httpx>=0.27.0, addshttpx-aiohttp) and regeneratespoetry.lockaccordingly. Adds a small async demo script and new tests asserting customhttpx.AsyncClientinstances are wired through for bothAsyncClientandAsyncClientV2.Written by Cursor Bugbot for commit df83506. This will update automatically on new commits. Configure here.