Streaming a run with run_streamed
Streaming is a way to read a run's events as they happen, so you can print the model's text piece by piece instead of waiting for the whole answer.
Last updated: 28 Sep, 2026 · openai-agents 0.22.3
Runner.run_streamed starts a run and returns at once. Its stream_events() is an async generator of events. A raw_response_event wraps the model's own events, and the text pieces arrive as ResponseTextDeltaEvent objects.
The run_streamed and stream_events calls
result = Runner.run_streamed(agent, "hello") # returns immediately
async for event in result.stream_events(): # consume the events
... # each event is one thing that happened
print(result.final_output) # ready once the stream endsFiltering for text delta events
Most events are not text. Keep the raw model events whose data is a ResponseTextDeltaEvent, and print each delta as it comes.
from openai.types.responses import ResponseTextDeltaEvent
async for event in result.stream_events():
if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
print(event.data.delta, end="", flush=True)Running the stream inside asyncio
Streaming is async, so the loop lives in an async def and is started with asyncio.run.
import asyncio
async def main():
agent = Agent(name="Shop", instructions="Help with orders.", model=ShopModel())
result = Runner.run_streamed(agent, "hello")
async for event in result.stream_events():
...
asyncio.run(main())Word by word from the stand-in
The whole program in one file. The stand-in yields one word at a time, then the run reports the final text.
import asyncio
from agents import Agent, Runner, set_tracing_disabled
from openai.types.responses import ResponseTextDeltaEvent
from shop_model import ShopModel
set_tracing_disabled(True)
async def main():
agent = Agent(name="Shop", instructions="Help with orders.", model=ShopModel())
result = Runner.run_streamed(agent, "hello")
async for event in result.stream_events():
if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
print(event.data.delta, end="", flush=True)
print()
print("FINAL:", result.final_output)
asyncio.run(main())What the event loop printed
- Each delta is one word from the stand-in's
stream_response, printed the moment it arrives, so the line builds up across the loop. - The filter keeps only
raw_response_eventevents whose data is aResponseTextDeltaEvent, skipping the other event types. - final_output is the same full text, available once the stream has ended.
run_sync vs run_streamed
| Call | Returns | You read the text |
|---|---|---|
Runner.run_sync | The finished RunResult | All at once from final_output |
Runner.run_streamed | A streaming result at once | Piece by piece from stream_events() |
When to stream a run
- Showing a reply as it is typed, so a user sees words appear instead of a blank wait.
- Reacting to tool calls or handoffs the moment the SDK emits them.
- Stopping a long answer early once you have read enough.
run_streamed returns before the work is done, and the run advances only while you consume stream_events(). If you never iterate it, no text prints and final_output is not ready.Related
- Previous: Sessions: memory across runs with SQLiteSession
- Next: Tracing a run with spans
- Reference: Streaming
- Add an
elsebranch that printsevent.typeto see the other events. - Collect the deltas into a list and print the list after the loop.
- Change the stand-in's text and confirm the deltas follow.
Little by little, you're building something great.