Runner and the RunResult object
Runner is the class that runs an agent, and RunResult is the object it returns, holding the final answer and every step the run took.
Last updated: 28 Sep, 2026 · openai-agents 0.22.3
Lesson 3 built a model; the Runner is what drives it. You hand the Runner an agent and a message, it runs the agent loop, and it gives back a RunResult. That result carries the final answer and a list of each step, which is your window into what happened.
The Runner methods
There are three ways to start a run. run_sync blocks until the run finishes; run is the async version; run_streamed returns events as they happen.
from agents import Runner
result = Runner.run_sync(agent, "hello") # blocks until done
# await Runner.run(agent, "hello") -> async version
# Runner.run_streamed(agent, "hello") -> events as they happen
print(result.final_output) # the last message textChoosing run_sync, run or run_streamed
Use run_sync in a plain script. Inside async code, await Runner.run(...). Use run_streamed when you want to watch the reply arrive; the streaming lesson covers it.
result = Runner.run_sync(agent, "hello") # in a normal scriptReading final_output
final_output is the text of the last message the model produced. For a plain reply, that is the whole answer.
print(result.final_output) # -> the model's final message textListing the steps with new_items
new_items is the list of items the run created, in order: tool calls, tool outputs and messages. It is the inspection tool you use for the rest of the course.
print(len(result.new_items)) # how many steps
for item in result.new_items:
print(type(item).__name__) # the kind of each stepRunning the agent and counting its steps
This imports ShopModel from lesson 3, runs one message, and prints the answer and the steps. A plain greeting produces a single step.
from agents import Agent, Runner, set_tracing_disabled
from shop_model import ShopModel
set_tracing_disabled(True)
agent = Agent(name="Shop", instructions="Help with orders.", model=ShopModel())
result = Runner.run_sync(agent, "hello")
print("final_output:", result.final_output)
print("new_items:", len(result.new_items))
for item in result.new_items:
print("-", type(item).__name__)What final_output and new_items showed
- final_output is the greeting, the text of the last message.
- new_items had one entry, because the model replied once and called no tool.
- MessageOutputItem is the item type for a message; tool runs add other types, seen in lesson 6.
run_sync vs run vs run_streamed
| run_sync | run | run_streamed | |
|---|---|---|---|
| Call style | Blocking | await | await, then read events |
| Returns | RunResult | RunResult | RunResultStreaming |
| Use in | Plain scripts | Async code | Live output |
Where new_items helps
- Confirming a tool ran, not only that an answer came back.
- Debugging a run by reading each step in order.
- Counting how many turns a run took before it settled.
run_sync starts its own event loop, so calling it inside code that already runs one (an async function, some notebooks) raises a runtime error. Use await Runner.run(agent, message) there instead.Related
- Previous: Model: a stand-in you can run without a key
- Next: function_tool: a function the model can call
- See also: Running agents
- Reference: Results
- Print
result.final_outputon its own and read the type. - Loop over
result.new_itemsand print each item'stype().__name__. - Send a longer message and check
new_itemsstill has one entry.
This is what real progress feels like.