# 20.4 Running the tools and sending back the results (/building-ai-workers/agent-loop-by-hand/running-the-tools-and-sending-back-the-results)

---
type: Document
title: "20.4 Running the tools and sending back the results"
description: "Running each tool the model asked for, and returning one result per call, matched by id, all together and first, failures included."
status: stable
order: 320.04
ksor:
  owner: team:panaversity
  audience: [ public ]
  approval:
    by: process:panaversity
    at: 2026-11-06T10:53:06Z
chapter: "20"
part: III
expert_status: builder-only
concepts: [ "20.4" ]
last_verified: 2026-11-05
generated:
  at: 2026-11-06T10:53:06Z
  by: process:panaversity
trust_tier: unverified
build_id: sha256:21db26ecbf7fc84b043f434d194e035ffe0481398b00a039c42d852801046bca
dirty: true
ksor_version: 0.0.60
---

**Where this fits.** These are steps 4 and 5, run and return: doing what the model asked for, and handing back each result in the form the model expects.

**In everyday life.** A dry cleaner gives you two tickets for two coats. When you come back, the counter hands each coat back with its ticket pinned on. If one coat was lost, you still get its ticket back, with a note saying so. Nobody leaves you guessing which coat was which, or whether the second one exists. In this concept, each ticket is a call id, and each coat with its ticket is a tool result.

**What you will learn.** How your program runs each tool the model asks for, and hands every answer back in the form the model expects, failed ones included.

**Why it matters.** A missing or misplaced answer gets the next request rejected, and a failure you drop leaves the model guessing about what happened.

**One request, start to finish.** Ana asks: "Is INV-8301 ready to pay, and does INV-8316 match its PO?" (A PO is a purchase order, the company's own record of what it agreed to buy.)

1. **The model asks for two tool calls in one response:** `get_purchase_order` for INV-8301, with call id B1, and `get_purchase_order` for INV-8316, with call id B2. These are **parallel calls**, several tool calls in one response.
2. **Your code runs both.** The first returns PO-7001. The second fails: INV-8316 has no purchase order.
3. **Your code builds one result for each call.** The first result carries id B1 and the purchase order. The second carries id B2, the error message, and a flag that says it is an error.
4. **Your code sends both results back together,** in one new entry in the conversation, before anything else in it.
5. **The model answers:** INV-8301 matches its PO. INV-8316 has no PO, and the error said such an invoice is held until the buyer raises one. It says it has not checked the policy line yet.

The failure was not thrown away. The model heard about it and said so.

### What makes the return step correct?

As [20.1](what-an-agent-is-in-code.md) said, a tool call is the model's request to run one tool, with a name, inputs and a call id, and a tool result is your answer to it, carrying the same id. Four rules make the return step correct. Breaking rule 1, 2 or 3 gets a 400 error from the first API (an error that means your request itself was wrong, [20.9](when-the-loop-goes-wrong.md)). Rule 4 is a reminder, because a dropped failure breaks rule 1:

1. **One result for every call.** If the model asked for two, return two. A call you decided not to run still gets a result, marked as an error, that says why.
2. **Matched by id.** Each result names the call id it answers. Order alone is not enough, because the model may refer to them by id.
3. **Results first, and right after the calls.** The results go in the very next entry of the conversation, before any other text you add.
4. **Failures are results.** When a tool fails or throws an exception (stops with an error), catch it, and send the failure back as an error result. The model can then say what failed, try another way, or ask the person. If you drop the failure, the model sees a call with no answer, and the request is rejected.

On the first API, a result carries an "is error" flag. The second API has no such flag, so the lab writes `ERROR:` at the start of the result's text. Either way, the model reads the failure in words.

![Two tool calls on the left, each a card with an id: id B1, get_purchase_order INV-8301, and id B2, get_purchase_order INV-8316. Two result cards on the right, each with the same id: B1, PO-7001, $4,825.00, and B2, error, no purchase order, with a red-orange border. A line joins each pair. Below, the next conversation entry drawn as one box holding both results, labeled results first, one per call, failures included.](img/chapter-20-matched-pair.png)

*Figure 20.7. Every call gets its result, matched by id, even when the tool failed.*

### Run calls one at a time, or together?

Parallel calls in one response are independent of each other, so your code may run them at the same time. The lab runs them one after another, which is simpler to read in a trace ([20.10](reading-a-trace.md)). Either way, all the results go back together, in one entry.

**At work.** In [Lab 20](lab.md), Task 4, your coding agent runs Ana's two-invoice question through the recorded tests first, then live. You ask the agent to explain Step 4 and Step 5 of the loop (lines 81 to 97 of the first API's loop file in TypeScript, 86 to 102 in Python) and predict how many results the second request will carry, and what the second one's error flag will be.

**The operating rule:** return exactly one result per tool call, matched by its id, all together and first. Catch every failure and return it as a result, never drop it.
