0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
27 small wins to finish your pathNext lesson →

How the agent runs a tool then answers

The agent loop is the cycle the SDK runs: the model asks for a tool, the SDK runs that tool and feeds the result back, and the model turns it into a final answer.

Last updated: 28 Sep, 2026 · openai-agents 0.22.3

Lesson 5 built a tool and ran it by hand. Here the model decides to call it. You give the tool to the agent, ask about an order, and the SDK does the round trip: tool call, tool result, final message. Reading new_items from lesson 4 shows all three steps.

Giving the agent a tool

The loop needs three things: a tool, an agent that holds it, and a message that makes the model want it.

python
agent = Agent(name="Shop", instructions="Help with orders.",
              tools=[lookup_order], model=ShopModel())
result = Runner.run_sync(agent, "where is my order?")  # triggers the loop

Defining the order tool

The tool returns a fixed order status. When the SDK runs it, this string is what goes back to the model.

python
@function_tool
def lookup_order(order_id: str) -> str:
    """Return the status of an order by its id."""
    return "Order A17: shipped on 3 March."

Handing the tool to the agent

Put the tool in the agent's tools list. Now the model may request it during a run.

python
agent = Agent(name="Shop", instructions="Help with orders.",
              tools=[lookup_order], model=ShopModel())  # tool attached

Asking about an order

The message mentions an order, so ShopModel returns a call to lookup_order. The SDK runs it, sends the result back, and the model answers with it.

python
result = Runner.run_sync(agent, "where is my order?")
print(result.final_output)  # the status the tool returned

One tool call, then the answer

This imports ShopModel from lesson 3. The model asks for the tool, the SDK runs it, and the final answer is the order status. The three items show the whole loop.

Example
from agents import Agent, Runner, function_tool, set_tracing_disabled
from shop_model import ShopModel

set_tracing_disabled(True)

@function_tool
def lookup_order(order_id: str) -> str:
    """Return the status of an order by its id."""
    return "Order A17: shipped on 3 March."

agent = Agent(name="Shop", instructions="Help with orders.",
              tools=[lookup_order], model=ShopModel())
result = Runner.run_sync(agent, "where is my order?")
print("answer:", result.final_output)
for item in result.new_items:
    print("-", type(item).__name__)

What the three new_items are

  • ToolCallItem is the model's request to run lookup_order with the order id.
  • ToolCallOutputItem is what the tool returned, fed back to the model.
  • MessageOutputItem is the final answer the model wrote from that output.

A tool run vs a plain reply

Plain reply (lesson 4)Tool run (this lesson)
Model outputA messageA tool call, then a message
new_items count13
Loop passesOneTwo: call, then answer

Where the loop repeats

  • Answering a question that needs a lookup before the model can reply.
  • Chaining several tool calls, each result feeding the next request.
  • Any run where the model gathers facts with tools before it answers.
Watch out. The loop keeps calling tools until the model returns a message, so a model that always asks for a tool would run forever. The SDK caps this with max_turns, covered in its own lesson later.
Try it yourself
  • Send "hello" instead; the tool branch is skipped and only one item appears.
  • Add a print inside lookup_order and watch it fire mid-run.
  • Change the tool's return string and rerun; the final answer changes with it.

Little by little, you're building something great.