SIGN IN SIGN UP

feat(client): Add experimental runtime support for HTTPX2 clients (#3524)

Refs https://github.com/openai/openai-python/issues/3375.

## Summary

Adds experimental runtime support for using an HTTPX2 client with the
2.x SDK:

```sh
pip install 'openai[httpx2]'
```

```python
from openai import OpenAI, AsyncOpenAI, DefaultHttpx2Client, DefaultAsyncHttpx2Client

client = OpenAI(http_client=DefaultHttpx2Client())
async_client = AsyncOpenAI(http_client=DefaultAsyncHttpx2Client())
```

HTTPX remains installed, imported, and authoritative for the SDK's
public transport types. Existing HTTPX clients and helpers continue to
work unchanged. This is an explicit runtime opt-in, not a
default-transport or typing migration: generated/parsed API models
remain accurately typed, while _raw requests, responses, streams, and
transport exceptions can be HTTPX2 objects even where annotations still
describe HTTPX_.

The implementation keeps the compatibility boundary small:

- accepts sync, async, and module-level HTTPX2 clients and preserves
their native request/response/exception family;
- supplies `DefaultHttpx2Client` and `DefaultAsyncHttpx2Client` with the
SDK defaults, while retaining the existing HTTPX and aiohttp helpers;
- handles the concrete request, timeout, URL, response-casting, retry,
streaming, auth, and provider differences needed at runtime;
- makes workload-identity token exchange follow an explicitly selected
HTTPX2 client (including async clients, whose exchange still runs
synchronously in the existing worker-thread path), without changing
behavior merely because HTTPX2 happens to be installed.

The `httpx2` extra is available on Python 3.10+ and scopes its resolver
requirements to the opt-in path (`httpx>=0.25.1,<1`, `httpx2>=2.7,<3`,
and `anyio>=4.10,<5`). Base installations retain the existing Python,
HTTPX, and AnyIO floors. On Python 3.9 the extra is marker-skipped and
invoking an HTTPX2 helper produces an actionable error. Intentionally
mixed HTTPX/HTTPX2 transports or auth implementations are out of scope.

## Gaps
- This pr does not address `aiohttp`+ `httpx2`; that can be a future
addition if there is interest. This would require a separate addon and
for us to vendor in some of the implementation; so avoiding in this PR.
- Types stay on `httpx`, and `httpx` is still required to be an
installed package.
- reasoning: we considered `httpx | httpx2` as a migration shim, or
returning `httpx2` type annotations. Will continue to evaluate the
ecosystem, although `httpx2` types will unfortunately likely require
many updates from downstream packages. Saving those considerations for
potential future major versions.
- For now, we do not address `httpx.timeout` annotations in generated
code as well

## Testing

The HTTPX2 CI lane runs the normal suite with native HTTPX2 sync/async
clients in both Pydantic modes. Existing RESPX-backed cases are
exercised through a small, test-only bridge: HTTPX2 uses a native
`MockTransport`, the bridge translates only at the RESPX
matching/callback boundary, and the SDK still builds and receives native
HTTPX2 requests/responses. This keeps generated binary/raw/streaming,
retry, auth, Azure, Bedrock, and snapshot coverage shared instead of
maintaining duplicate tests; aiohttp remains a separate HTTPX-family
path.

Focused native tests also cover client defaults, direct injection,
raw/SSE/multipart, retries and exception families, hooks/mounts/proxies,
provider auth, workload-identity exchange/cache/401 refresh, and
base-only/extra resolver behavior. Local full-suite runs pass with
HTTPX2/Pydantic 2 and the HTTPX2 floor/Pydantic 1; the ordinary HTTPX
suite and lint/type checks remain clean.
A
Alex Chang committed
e1925e9804aa1bbd33359d91ed3fee105cac103f
Parent: 7f4edb6
Committed by stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> on 7/22/2026, 5:46:08 PM