OpenAI Agents SDKopenai-agents 0.22 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
25 small wins to finish your pathNext lesson

Reading the run result

Runner.run gives back one object, and almost everything you will want to know about a run is on it.

The four you will use

python
print("final_output:", result.final_output)
print("last_agent:  ", result.last_agent.name)
print("turns used:  ", len(result.raw_responses))

What it cost

The same object carries the token count, one level down, on the context wrapper.

python
usage = result.context_wrapper.usage

print("requests:", usage.requests)
print("tokens:  ", usage.total_tokens)

requests is how many times a model was called, input_tokens and output_tokens split the cost, and total_tokens adds them up. This is the number that grows quietly as a conversation gets long, which is what lesson 20 is about.

Two requests here and zero tokens, because our stand-in never tokenised anything. Against a real model the requests stay the same and the tokens do not.

Usage is per run
Lesson 19 turns several runs into one conversation. Even then each run reports only its own usage, so adding them up across a conversation is your job.
FieldWhat it holds
final_outputThe answer. A string, unless you asked for a shape in lesson 10.
new_itemsEverything that happened, in order. Tool calls, tool answers, messages.
last_agentWhich agent finished the run. It is not always the one you started, as lesson 13 shows.
raw_responsesOne entry per trip to the model, so its length is the number of turns.

Walking the items

Every item has a type, and ItemHelpers pulls the text out of a message without you reaching into the raw shapes.

python
for item in result.new_items:
    if item.type == "message_output_item":
        print(ItemHelpers.text_message_output(item))
Example
print("final_output:", result.final_output)
print("last_agent:  ", result.last_agent.name)
print("turns used:  ", len(result.raw_responses))
print()
for item in result.new_items:
    print(f"{type(item).__name__:<20} {ItemHelpers.text_message_output(item) if item.type == 'message_output_item' else ''}")

Two turns for a three item run. The first turn produced the tool request, the tool ran without going near the model, and the second turn produced the words. Turns and items are not the same count, and that is worth holding on to when you start reading traces.

Which one to reach for
final_output is a convenience. It is the text of the last message, and it is the field you reach for ninety per cent of the time. new_items is the field you reach for when something went wrong.
Try it yourself
  • Print result.to_input_list() and see the conversation the next run would start from.
  • Ask a question with no order id and compare the item count.
  • Print item.raw_item for the tool call and read the arguments.

Little by little, you're building something great.