Chapter Three · Tools
Tools
Six topics turn an agent that can only read into one that can change the world. What a tool is on each side of the split between your code and the model, schemas the model can actually choose between, what a result should contain, errors written for a reader who must act, why nine tools beat twenty-two — and the twelve seconds in which a timed-out refund was paid twice.
Vera's forty-line agent could look things up and nothing else. On the cracked shelving ticket it searched the orders, read the record, retrieved the damage procedure, and then wrote the buyer a paragraph promising a refund it had no ability to perform. Every capability in Chapter 1 was real; the reply was a draft that a person still had to act on. This chapter gives the agent the four tools that act — returns, replacements, refunds, messages to sellers — and everything that has to be true before any of them is safe to attach.
A tool is two halves that live in different places: a function in your code, and a declaration the model reads on every turn. The model never executes anything — it emits a structured request and stops, and your dispatcher decides whether to run it. That split is where the whole permission model comes from, and the declaration half turns out to be measurable rather than a matter of style: rewriting one description at Sundry, with no code change at all, moved correct tool selection from 71% to 93% on a labelled set of 200 tickets.
The last topic is the one to read twice. issue_refund timed out after the payment provider had already accepted it, the tool reported a failure, the model asked again in good faith, and a buyer was paid $118.00 twice while a marketplace seller's balance went to minus $47 — discovered three days later by finance, on tickets the eval set had scored as resolved. Idempotency keys derived from intent close that wound here; Chapter 8 generalizes it into partial failure and compensation.
Topics in This Chapter
get_order costs a token where a wrong issue_refund costs a phone call.get_order goes from 6 KB of upstream JSON to 340 tokens of the fourteen fields anyone reads, with identical resolution on the eval set.