Skip to content

Python: [Feature]: Document and test Python ChatClient concurrent-use contract #7654

Description

Description

Please define and document whether Python ChatClient instances are safe to reuse across concurrent async calls, including mixed streaming and non-streaming calls.

Long-lived hosts such as Azure Functions need to reuse SDK clients and their HTTP connection pools across invocations to avoid connection churn and SNAT exhaustion. That means one OpenAIChatClient or FoundryChatClient wrapper may serve multiple fresh Agent/AgentSession instances concurrently. Today, the Python API documentation does not state whether this is supported or which objects must remain request-scoped.

The expected contract would clarify:

  • whether one OpenAIChatClient / FoundryChatClient can be shared by simultaneous Agent.run() calls;
  • whether streaming + streaming, non-streaming + non-streaming, and mixed streaming/non-streaming use are supported;
  • that messages, function-call IDs/arguments, middleware state, sessions, and stream events remain isolated per call;
  • whether the guarantee is limited to async tasks on one event loop or also covers OS threads/event loops;
  • which mutable extensions (for example middleware) are excluded from the guarantee.

A framework-level concurrency regression test for the supported combinations would make this contract durable.

In Azure/azure-functions-agents-runtime#158 we inspected Agent Framework Python 1.3 and added deterministic characterization tests using the real wrappers over a mock OpenAI Responses transport. Those tests show overlapping calls remain isolated for both wrappers across all three combinations, including distinct streamed function-call IDs. This gives us confidence in the pinned version, but it is not a substitute for an upstream compatibility guarantee.

Alternative considered: create a fresh ChatClient wrapper per invocation while sharing only the underlying HTTP transport. That avoids relying on wrapper concurrency but couples hosts to private transport ownership and defeats some of the intended SDK-client reuse model.

Code Sample

client = OpenAIChatClient(async_client=shared_async_openai, model="model")

# Each request gets fresh mutable Agent/session state while sharing the ChatClient.
first = Agent(client)
second = Agent(client)
await asyncio.gather(
    first.run("first", session=first.create_session()),
    second.run("second", stream=True, session=second.create_session()).get_final_response(),
)

Language/SDK

Python

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonUsage: [Issues, PRs], Target: PythontriageUsage: [Issues], Target: All issues that still need to be triaged

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions