Client Management
Client management helpers for persistent HTTP clients.
ClientManager()
Explicit, caller-owned tracker for clients created within one asyncio run.
Examples:
async with ClientManager() as manager:
client_config = ClientConfig(http_client=http_client, manager=manager)
invoker = AnthropicLMInvoker(..., client_config=client_config)
...
get_or_create() also works without the async with block -- construct a ClientManager()
directly and call release_resources() explicitly when done:
manager = ClientManager()
client_config = ClientConfig(http_client=http_client, manager=manager)
invoker = AnthropicLMInvoker(..., client_config=client_config)
...
await manager.release_resources()
Every client returned by get_or_create() is closed by release_resources() regardless of
whether the caller keeps its ClientConfig alive -- the manager tracks each client
independent of that config's lifetime.
Initializes a new, empty ClientManager.
is_closed
property
Return whether the manager has completed closing tracked clients.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the manager has completed closing tracked clients. |
is_closing
property
Return whether the manager is currently closing tracked clients.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
True if the manager is currently closing tracked clients. |
__aenter__()
async
Enters the async context manager.
Returns:
| Name | Type | Description |
|---|---|---|
ClientManager |
ClientManager
|
This manager instance. |
__aexit__(*exc_info)
async
Closes every tracked client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*exc_info
|
object
|
Exception info passed by the |
()
|
get_or_create(config, factory, identity, model_id_log, *, provider=None)
Return the tracked client for config's identity if one exists, else build and track one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
ClientConfig
|
The caller's client configuration. |
required |
factory
|
Callable[[], ManagedClient]
|
Builds a fresh client from
|
required |
identity
|
dict[str, Any]
|
The calling invoker's own connection parameters (api_key, base_url, organization, headers, timeout, ...). |
required |
model_id_log
|
str
|
Log identifier for the calling invoker. |
required |
provider
|
str | None
|
Provider identifier (e.g. 'cohere', 'twelvelabs').
If not provided, inferred from |
None
|
Returns:
| Type | Description |
|---|---|
ManagedClient
|
tuple[ManagedClient, bool]: The live client and whether it is manager-tracked |
bool
|
( |
Raises:
| Type | Description |
|---|---|
InferenceValueError
|
If |
release_resources()
async
Closes every tracked client and marks this manager closed.
This includes clients built around a caller-supplied config.http_client: opting a
ClientConfig into a manager transfers close-ownership of its client to that manager,
even for an injected transport.
Concurrent calls are serialized so each tracked client is closed exactly once.
If closing any client raises an exception, the failure is surfaced and the manager
retains the failed entries so that release_resources() can be retried.
HookedClient(raw_client, teardown=None)
Bases: Generic[T]
Managed-client wrapper for SDK clients with custom async teardown.
The wrapper implements close() and synchronous is_closed() for the existing client manager protocol.
It delegates SDK attributes and methods to raw_client and forwards async context management when available.
Callers provide the teardown hook that matches their SDK's cleanup API, or let HookedClient resolve it.
Attributes:
| Name | Type | Description |
|---|---|---|
raw_client |
T
|
The wrapped provider SDK client. |
Wrap a provider client with its teardown hook.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_client
|
T
|
SDK client to wrap. |
required |
teardown
|
TeardownHook | None
|
Callback that closes |
None
|
__aenter__()
async
Enter the wrapped SDK context when it provides one and return this wrapper.
Returns:
| Type | Description |
|---|---|
HookedClient[T]
|
HookedClient[T]: |
__aexit__(exc_type, exc_val, exc_tb)
async
Forward async context exit or use the configured teardown hook.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc_type
|
type[BaseException] | None
|
Exception type from the managed block. |
required |
exc_val
|
BaseException | None
|
Exception raised by the managed block. |
required |
exc_tb
|
Any
|
Traceback for the managed-block exception. |
required |
Returns:
| Type | Description |
|---|---|
bool | None
|
bool | None: The raw client's exception-suppression result, or None when cleanup is performed through the teardown hook. |
__getattr__(name)
Delegate public SDK attributes to the wrapped client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Attribute or provider operation to retrieve. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Any |
Any
|
The matching attribute on |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If the attribute does not exist or is private. |
close()
async
Run the teardown hook once, serializing concurrent close requests.
is_closed()
Check whether the client is closed.
Returns:
| Name | Type | Description |
|---|---|---|
bool |
bool
|
|
ManagedClient
Bases: Protocol
Structural shape a client tracker needs: something it can close and check.
close()
async
Closes the client and releases its connections.
is_closed()
Returns whether the client is closed.
PersistentClientMixin
Mixin for invokers that own a closable provider client, ephemeral or persistent.
Provides double-checked locking for safe client reacquisition after release_resources() in
persistent mode. Subclasses must call _register_client() in __init__ and implement _create_client().
Attributes:
| Name | Type | Description |
|---|---|---|
client_config |
Any
|
The client configuration specifying lifecycle and optional ClientManager. |
client_kwargs |
dict[str, Any]
|
Connection and configuration kwargs used to build the client. |
_model_id |
Any
|
Identifier for the model/invoker, used for logging and provider resolution. |
client
property
writable
The underlying client instance (persistent mode only).
Returns:
| Name | Type | Description |
|---|---|---|
Any |
Any
|
The persistent client instance. If wrapped in a HookedClient, the unwrapped raw_client is returned for direct SDK access. |
Raises:
| Type | Description |
|---|---|
InferenceRuntimeError
|
If accessed in ephemeral mode. |
release_resources()
async
Close the underlying persistent client, if any, and release its connections.
A safe no-op in ephemeral mode, since no ambient client is kept. In persistent mode, only
closes a client this invoker actually owns: manager-tracked clients are left for the
ClientManager to close, and caller-supplied client_config.http_client transports are
left for the caller to close.
async_aclose_hook(client)
async
Invoke the async SDK client's aclose() method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
SDK client to close. |
required |
async_close_hook(client)
async
Invoke the async SDK client's coroutine close() method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
SDK client to close. |
required |
noop_hook(client)
Explicit no-op teardown for caller-owned or stateless clients.
Must be passed explicitly when a client has no standard close method. Using this hook signals an intentional choice rather than an oversight.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
The client instance (ignored). |
required |
resolve_default_teardown_hook(client)
Inspect client and return the appropriate standard teardown hook.
Resolution priority:
1. aclose() present and callable -> async_aclose_hook
2. Coroutine close() present -> async_close_hook
3. Synchronous close() present -> sync_close_hook
4. None of the above -> raises InferenceValueError
Use noop_hook explicitly for clients with no close API.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
The raw provider SDK client to inspect. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
TeardownHook |
TeardownHook
|
The selected teardown hook callable. |
Raises:
| Type | Description |
|---|---|
InferenceValueError
|
If |
resolve_sdk_httpx_client(client)
Return the underlying httpx client of a Fern-style SDK client, if there is one.
Fern-generated SDK clients (such as Cohere and TwelveLabs) expose no close method of their own. They keep their
HTTP transport at client._client_wrapper.httpx_client, which is either the httpx client itself or a wrapper
holding it at .httpx_client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
The SDK client to inspect. |
required |
Returns:
| Type | Description |
|---|---|
Any | None
|
Any | None: The underlying httpx client, or None if the SDK client has no HTTP client. |
sync_close_hook(client)
async
Teardown hook for clients exposing a synchronous close().
Executes the blocking call on a thread-pool worker via asyncio.to_thread
to avoid stalling the event loop during release_resources(). If close()
returns an awaitable (such as a sync wrapper returning a coroutine), it is awaited.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
Any
|
The client instance exposing a synchronous |
required |