A language model reads text and writes text. It cannot look up an order, charge a card or send an email. Tool calling is how an application lets it ask for those things: the request lists the tools the application offers, each with a name, a description and a JSON schema for its arguments, and the model may answer with a request to call one instead of with prose.
Every exchange in the film is a real recording. The questions were sent to `google/gemini-3.8-flash` through OpenRouter at temperature 0 on 11 September 2026, with a system prompt for an online shop and two tools, `get_order_status` and `cancel_order`. The application on the right of the counter is the real code that ran: a regular expression that checks the order id, a one-row order table, and a guard that refuses to cancel anything that is not still being processed.
The traced request is the whole mechanism. The customer asks where order A-1042 is. The model's first turn contains no text at all, only a tool call naming `get_order_status` with the argument `{"order_id": "A-1042"}`. Your code checks the id, reads the table, and returns the row: shipped with DPD on 9 September, arriving 14 September. That result is sent back to the model as a tool message, in a second request that repeats the conversation, and only then does the model write the answer the customer sees.
The part people miss is where the model's role ends. It writes a request, and nothing more. Everything that happens to that request happens in your code: whether the arguments parse, whether the id is well formed, whether this customer may touch this order, and whether the action runs at all. When the model asked to cancel A-1042, the order had already shipped, so the application refused and said why, and the model passed the refusal on. Validation and permissions belong on your side of the counter, because the model cannot enforce them.
The failure mode is forgetting that the trip has two legs. Stop after the first turn and the customer receives an empty message, because the text of a tool-calling turn is usually empty. Worse, send the result back empty, as a bug in the plumbing might, and the model does not say that something went wrong. In three runs of three it told the customer it could not find order A-1042, an order that had shipped two days earlier. A missing result reads to the model like a negative result.
Errors should travel the same road as data. When the customer typed A-1402, the lookup failed, and the application returned a structured error rather than nothing. The model turned it into a polite request to double-check the order number, which is the right answer, because the error said exactly what happened.
The takeaway is a division of labour. The model proposes a call and phrases the reply. Your code decides whether the call is valid and allowed, runs it, and always sends a result back, including when the result is an error.
The maths
- One tool call is two model calls
The first call returns a tool call and no text: in all four recordings the model sent an empty reply alongside the request. The answer only exists after a second call that carries the call and its result r back in the messages.
- Your code sits in the middle
The model picks f and writes the arguments a as JSON. It never runs f. Your application parses a, checks it, decides whether the call is allowed, runs the function, and chooses what r says. The cancel request here was refused by one line of application code.
- An empty result is still an answer
When the tool message came back empty, the model told the customer it could not find an order that had shipped two days earlier, in three runs of three. It reads a missing result as a negative result, so a bug in the plumbing becomes a confident wrong answer.
- Errors are data
Returning a structured error, rather than throwing or returning nothing, lets the model explain the failure in terms the customer understands. The typo exchange is exactly that: A-1402 does not exist, your code said so, and the reply asks the customer to check the number.
Related terms
- ToolA tool is a named action, with a typed input schema, that a model is allowed to call. Tools are how a model that can only produce text gets to actually do things: read a file, run a command, search the web.
- Tool callA tool call is the model’s request to use a tool: it names the tool and supplies the arguments, then pauses. It has not run anything. Your harness is what actually executes the action.
- Tool resultA tool result is the output of running a tool, fed back into the conversation so the model can use it. It is tied to the tool call that requested it, and it is how the model sees the consequences of its own actions.
- HarnessThe harness is the code wrapped around a model that builds requests, runs tools, manages context, and enforces permissions. It is the agent minus the model, and it is where most of the real engineering lives.
- TurnA turn is one round of the agent loop: your input, the model doing its work (possibly several tool calls), and its response. A single turn can span many provider requests.