Skip to content

Update the default HTTP client to httpx-aiohttp (httpx with aiohttp transport) insted of httpx.AsyncClient for better concurrency#746

Open
samuel-cahyawijaya wants to merge 3 commits intomainfrom
samuel/httpx-aiohttp
Open

Update the default HTTP client to httpx-aiohttp (httpx with aiohttp transport) insted of httpx.AsyncClient for better concurrency#746
samuel-cahyawijaya wants to merge 3 commits intomainfrom
samuel/httpx-aiohttp

Conversation

@samuel-cahyawijaya
Copy link
Copy Markdown

@samuel-cahyawijaya samuel-cahyawijaya commented Mar 29, 2026

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

  • Fully backward compatible for callers who still want the previous behavior: pass your own httpx.AsyncClient via httpx_client=.... It is used verbatim (not wrapped or replaced).
    • HttpxAiohttpClient is a subclass of httpx.AsyncClient, so existing type hints and code that expect an httpx.AsyncClient remain valid for the default client.
  • Sync cohere.Client continues to use httpx.Client unchanged.

Dependencies

  • Add httpx-aiohttp.
  • Bump httpx to >=0.27.0 to satisfy httpx-aiohttp.

Tests

Test: tests/test_async_client.py — asserts a custom httpx.AsyncClient is the same object wired into the wrapper for both AsyncClient and AsyncClientV2.
Demo: scripts/demo_async_client_httpx.py — runs chat with the default client vs an explicit httpx.AsyncClient.


Note

Medium Risk
Changes the default async HTTP transport from httpx.AsyncClient to httpx_aiohttp.HttpxAiohttpClient, which can alter runtime networking behavior (connection handling, timeouts, redirects) under load. Risk is mitigated by preserving the ability to pass a custom httpx.AsyncClient verbatim and adding coverage for that path.

Overview
Switches AsyncClient/AsyncBaseCohere to use httpx_aiohttp.HttpxAiohttpClient (aiohttp-backed) as the default async HTTP client to improve concurrency, while still accepting a caller-provided httpx.AsyncClient unchanged.

Updates dependencies to support this (httpx>=0.27.0, adds httpx-aiohttp) and regenerates poetry.lock accordingly. Adds a small async demo script and new tests asserting custom httpx.AsyncClient instances are wired through for both AsyncClient and AsyncClientV2.

Written by Cursor Bugbot for commit df83506. This will update automatically on new commits. Configure here.

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
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

@samuel-cahyawijaya samuel-cahyawijaya changed the title [Update default async HTTP client] use httpx-aiohttp (httpx with aiohttp transport) for better concurrency Update the default HTTP client to httpx-aiohttp (httpx with aiohttp transport) insted of httpx.AsyncClient for better concurrency Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant