Skip to content
Back to the lab

Turn Microsoft Agent Framework’s shared-client concurrency contract into a host-level test grid

Test shared chat clients against event-loop, thread, session, and streaming boundaries before approving a Python agent-host topology.

Super Genius Labs Editorial · 6 min read

Microsoft Agent Framework 1.17.0 documents shared-chat-client concurrency within a single event loop. That wording is a boundary, not evidence that one client can safely cross every thread or loop in a Python host (Microsoft Agent Framework release).

Python’s asyncio documentation supplies the adjacent runtime constraint: each thread should have its own event loop, and tasks or futures created in one thread should not be awaited or manipulated from another. It directs cross-thread interaction toward thread-safe APIs including run_coroutine_threadsafe() and call_soon_threadsafe() (Python 3.14.7 asyncio documentation).

Together, those documents leave an operator with a concrete verification problem. Same-loop sharing is documented by the framework release; behavior across loops or threads is not established by that announcement. The host therefore needs evidence matched to its actual topology.

Draw the boundary before running load

Start by recording where the shared client is created, which event loop owns it, which threads can reach it, and whether requests stream responses. This inventory is an SGL testing prescription, derived from the two documented boundaries rather than specified by either source.

The smallest useful topology record contains:

  • client instance identity;
  • creation thread and event loop;
  • calling thread and event loop for each request;
  • session or conversation identity;
  • streaming or non-streaming mode;
  • concurrency level and start coordination;
  • completion, exception, cancellation, and timeout observations.

Without that record, a successful run can conceal the important distinction between concurrent work on one loop and access that crossed an ownership boundary.

A host-level test grid

The following grid is a proposed verification design. Its expected classifications interpret the documented contracts; they are not reported Microsoft Agent Framework test results. Run every case in an isolated, non-production environment with synthetic data, non-production credentials, no access to live workloads, and a reliable way to terminate the run. Do not exercise cross-loop, cross-thread, cancellation, or in-flight shutdown cases against production systems.

CaseClient placementCallsSessionsResponse modeInitial classificationEvidence to retain
AOne client, one thread, one event loopConcurrentSeparateNon-streamingInside the release’s documented same-loop boundaryLoop and thread IDs, request timing, results, exceptions
BOne client, one thread, one event loopConcurrentSeparateStreamingSame-loop placement, with streaming behavior still to verifyStream ownership, chunk ordering by request, completion and cancellation records
COne client, one thread, one event loopConcurrentSame sessionMixedSame-loop placement; session-level safety is not established by the supplied excerptsSession ID, invocation order, stream events, resulting history
DOne client created on one loop, called from another loop in the same threadConcurrent or sequentialSeparateNon-streamingOutside the explicitly documented same-loop contractLoop IDs, call path, exception and timeout records
EOne client shared by multiple threads, each with its own loopConcurrentSeparateMixedOutside the framework excerpt’s stated boundary and subject to asyncio thread ownership constraintsThread and loop IDs, coordination mechanism, failures and cancellations
FOne client owned by one loop; other threads submit work through a thread-safe asyncio APIConcurrentSeparateMixedCross-thread coordination path to evaluate, not proof that the client itself is cross-thread safeSubmission API, owner loop, result handoff, cancellation and shutdown behavior
GOne client per thread and event loopConcurrentSeparateMixedAvoids sharing the client across loop ownership boundaries; operational behavior remains to be testedClient-to-loop mapping, resource use, startup and shutdown records

Cases A and B test the most direct reading of the framework’s documented same-event-loop contract. Case C isolates a different variable: a client may accept concurrent calls while the application still has unresolved ordering rules for a shared session. The supplied evidence does not define session semantics, so the result belongs to the tested framework version, provider configuration, and host implementation.

Cases D and E deliberately cross the stated boundary. A failure would show that the topology did not work under the tested conditions. A success would remain only an observation from that run; it would not broaden Microsoft’s documented contract.

Cases F and G test host designs that respect asyncio’s documented thread-bound model. Python documents thread-safe mechanisms for cross-thread interaction, but that does not by itself establish how a particular shared chat client behaves when work is submitted through them (Python 3.14.7 asyncio documentation).

Make streaming and shutdown visible

Within the same isolated, non-production test environment, a unary success result is too narrow for hosts that stream. For each applicable row, vary which request finishes first, cancel one request while another continues, and initiate test-host shutdown with work in flight. These are proposed test mutations intended to expose coupling; the supplied sources do not report outcomes for them. Keep these mutations disconnected from live sessions, production services, and production data.

Retain per-request stream events rather than one merged log line. The evidence should make it possible to determine whether chunks stayed attached to the correct request, whether one cancellation affected another call, and whether shutdown left unresolved tasks or futures. Those are acceptance questions, not claims about the framework’s current behavior.

Run each case at least once with separate sessions. If the product permits concurrent operations against one session, add that combination as its own row instead of treating it as equivalent. Client sharing, session sharing, and streaming are separate variables even when they occur on the same loop.

Define the claim each result earns

A passing Case A can support a narrow statement: the tested client and configuration completed the tested concurrent calls on one event loop. It cannot establish cross-loop safety, cross-thread safety, every streaming combination, or behavior under a different SDK version.

A passing Case F can establish that the tested host coordination path completed under its recorded conditions. It cannot establish that direct client access from multiple threads is supported. The distinction matters because asyncio documents thread-safe submission mechanisms while separately warning against awaiting or manipulating a task or future from another thread (Python 3.14.7 asyncio documentation).

Attach the result to the framework version, Python version, provider configuration, topology, concurrency level, and response mode. Re-run the affected rows when one of those dimensions changes. Microsoft’s 1.17.0 release is evidence of what that release documents, not a demonstration of every host arrangement (Microsoft Agent Framework release).

The practical decision is smaller than declaring a client “thread-safe.” Approve a specific client-sharing pattern for a specific host topology, then preserve the run that earned that approval. Teams designing the surrounding runtime can carry the same boundary-first approach into their broader agent infrastructure work.