The two-round shape
A tool call is at minimum two round-trips: (1) you send tools + user message; the model returns stop_reason='tool_use' with a tool_use block; (2) you execute the tool locally and append a tool_result back into the conversation; the model produces the final answer. Real loops continue until the model returns stop_reason='end_turn'.
One handler per tool, dispatched by name
The clean pattern is a registry of {tool_name: callable}. When you see a tool_use block, look up the callable, call it with the arguments, and append the result. Resist the urge to put tool dispatch inline in a single big function — it grows fast as tools accumulate.
Loop budget
Some tasks legitimately want 10+ tool rounds. Some indicate a stuck model and should be cut off. Always carry a max-iteration budget (start with 10) and surface the abort to the user so they understand why the agent stopped.