Maintainer-owned vNext proposal. Community contributors: please do not pick up or start implementing this issue. This is a breaking public-API change for the Agent Framework core team to design and schedule.
Problem
The public Agent.run, RawAgent.run, BaseChatClient.get_response, and workflow run APIs are regular methods that return an awaitable final response when stream=False, but return a ResponseStream immediately when stream=True. The entry-point calling convention changes based on stream.
Do not flatten the two return values or remove stream. Underlying model/provider APIs support a streaming parameter and genuinely execute differently based on it. The earlier idea of forcing both modes into one result handle is not the proposed solution.
vNext direction
Make the whole public method asynchronous in both modes: async def run(...) / async def get_response(...). Callers always await the method to obtain its mode-specific result; the result remains a final response for non-streaming and a ResponseStream for streaming. For example:
response = await agent.run(prompt)
stream = await agent.run(prompt, stream=True)
async for update in stream:
...
The underlying backend and provider calls can continue to pass stream and use their different execution paths. Apply the public contract consistently across SupportsAgentRun / SupportsChatGetResponse, agent and chat-client layers, and graph/functional workflows where appropriate.
Breaking behavior and acceptance criteria
- Existing
async for update in agent.run(..., stream=True) code must first await run; document this migration and update examples and typing.
- Preserve distinct final/stream result types, provider-specific streaming behavior, response finalization, middleware hooks, telemetry, cancellation/cleanup, and session persistence.
- Preserve the active-run/concurrency safeguards in workflows even though validation and stream creation now happen when the coroutine is awaited rather than synchronously at invocation.
- Avoid changing
ResponseStream.__await__ merely to simulate one return interface; this proposal is about making the public method itself async.
Ownership: Core maintainers only; not available for community pickup.
Problem
The public
Agent.run,RawAgent.run,BaseChatClient.get_response, and workflowrunAPIs are regular methods that return an awaitable final response whenstream=False, but return aResponseStreamimmediately whenstream=True. The entry-point calling convention changes based onstream.Do not flatten the two return values or remove
stream. Underlying model/provider APIs support a streaming parameter and genuinely execute differently based on it. The earlier idea of forcing both modes into one result handle is not the proposed solution.vNext direction
Make the whole public method asynchronous in both modes:
async def run(...)/async def get_response(...). Callers alwaysawaitthe method to obtain its mode-specific result; the result remains a final response for non-streaming and aResponseStreamfor streaming. For example:The underlying backend and provider calls can continue to pass
streamand use their different execution paths. Apply the public contract consistently acrossSupportsAgentRun/SupportsChatGetResponse, agent and chat-client layers, and graph/functional workflows where appropriate.Breaking behavior and acceptance criteria
async for update in agent.run(..., stream=True)code must first awaitrun; document this migration and update examples and typing.ResponseStream.__await__merely to simulate one return interface; this proposal is about making the public method itself async.Ownership: Core maintainers only; not available for community pickup.