Module 2 · Tools, Knowledge, Memory & Research Design · scripted

What Comes Back: Designing Tool Results

30 minoutcomes: tool-design, context-engineering

The other half of the tool

We pour attention into the naming of a tool, its description, its parameters, its implementation. But equally powerful — and almost always an afterthought — is the other half: what comes back. How the result of using a tool is represented to the agent shapes everything that happens next.

Start from the key fact, which you already know:

The key fact

A tool result is a user message.

The moment it returns, it is part of the conversation — part of the
context — conditioning every turn that follows, and billed by the
recurrence on every iteration after.

The agent cannot see its own wall

The simplest thing a result can do is provide information: read this file — here are the contents. But there is a problem hiding in that simplicity. When the agent calls the tool, it may not know — may not even be able to estimate — how much of its own window remains, or what dumping the whole file will do to it. The prisoner cannot measure the wall. So the tool must respect the window on the agent's behalf:

Example 1 · The naive dump
user

You have the following tools available for use:


  1. read_document( name )

Task: What are the rules for night deliveries at the harbor?

assistant
⟨tool_use⟩
read_document(name = "harbor-regulations.pdf")
user
⟨tool_result⟩
[187 pages: definitions, port authority structure, vessel classes,
mooring fees, environmental provisions, appendices A–J …]
NoteOne call, and 187 pages sit on the wall forever — billed on every later iteration, burying the goal, and the night-delivery rules are somewhere in section 142. The agent didn't know this would happen. The tool's designer did.

So we don't naively dump. Below are the standard patterns — and notice that they form a ladder, each fixing the one before it.

Pattern 1 · Truncate — but return a handle

The most basic move: cap the result. First 1,000 characters, a summary line, a row limit. But whatever we cut may be exactly what the agent needs — so never truncate without returning a handle to what was left out:

Example 2 · Truncation with introspection
assistant
⟨tool_use⟩
read_document(name = "harbor-regulations.pdf")
user
⟨tool_result⟩
[doc-77 · 187 pages · showing page 1 of 187]
"Chapter 1: Definitions. In these regulations, 'vessel' means…"
→ read_pages(doc, from, to) is available for the remainder.
NoteThe result carries three things: a sample, an identity (doc-77, 187 pages), and the next move (read_pages). Nothing is lost — it is merely not loaded.
assistant
⟨tool_use⟩
read_pages(doc = "doc-77", from = 2, to = 3)
user
⟨tool_result⟩
[pages 2–3: more definitions …]
NoteBut watch the failure mode: the night-delivery rules are on page 142. Sequential paging will spend 70 tool calls — and 140 pages of wall — getting there. Indexed reading protects the window per call and wastes it across calls.

Pattern 2 · Let the agent search

Instead of scanning, give the agent a generic text search — a grep. We cannot enumerate everything it might need to find, so per the coverage law, the search pattern is the agent's to write:

Example 3 · Search — power and blind spots
assistant
⟨tool_use⟩
search_document(doc = "doc-77", pattern = "night deliver")
user
⟨tool_result⟩
0 matches.
assistant
⟨tool_use⟩
search_document(doc = "doc-77", pattern = "night")
user
⟨tool_result⟩
2 matches: p. 12 "overnight mooring"; p. 98 "night watch staffing".
NoteThe rules exist — but the document calls them "deliveries outside ordinary working hours (23:00–06:00)". Text search finds strings, not meanings: a synonym, a paraphrase, or a defined term the agent didn't guess, and the information is invisible. The search language has the limits of its patterns.

Pattern 3 · Let the agent ask

The strongest standard pattern uses what we just learned: self- dialogue. Give the agent a tool that sends the document off in a prompt and asks for what's relevant:

Example 4 · Ask the document
assistant
⟨tool_use⟩
ask_document(doc = "doc-77", question = "What rules govern deliveries
at night? Include exact section numbers and any defined terms.")
user
⟨tool_result⟩
Relevant provisions: §142 "Deliveries outside ordinary working hours
(23:00–06:00)" — permitted only at Quay 3, max sound level 55 dB,
advance notice to the port authority by 16:00. Defined term: 'quiet
period' (§8). Excerpts: "…deliveries during the quiet period shall
use the eastern access road…"
NoteBehind the tool, an LLM read all 187 pages inside a disposable conversation and returned three sentences. Meaning-level access to the whole document — a synonym problem can't hide from it — and the loop paid for excerpts, not pages. As if the document were in context, without paying for it on every iteration.

The retrieval ladder

page through itprotects each call, wastes the trajectory
search itfinds strings — fast, cheap, literal-minded
ask itfinds meaning — one thought inside the tool

(There are more sophisticated techniques — they come later — but these three cover most of what agents need.)

The Goldilocks problem

Every result design is aiming at the same narrow target:

Too little · too much · just enough

Too littlethe agent lacks the context to reason — and burns extra tool calls and loop iterations hunting for it
Too muchthe wall fills with noise, the trajectory drifts, and the recurrence bills the waste every iteration
Just enoughwhat the agent needs for its NEXT DECISION — plus handles to everything else

That last line is the design question to ask of every tool you build: what does the agent need on the wall to make its next decision — and what can stay behind a handle?

Results are grammar

One more responsibility, and it ties back to the language of action: results are where chaining happens. If a result names things in the form another tool accepts — an id, a section number, a typed value — we have built an association into the grammar: the result invites the next move. If it comes back as loose prose, the chain breaks.

The same result, chainable and not

Dead end:"The night rules are in the section about working hours, somewhere in the last third of the document."
Chainable:[§142 · "Deliveries outside ordinary working hours"] → read_section(doc, "142") · cite(doc, "142")

The second result speaks the input language of two other tools. The first speaks to no tool at all.

Design what comes back with the same care as what goes in: it is half of every tool, the half that becomes conversation.

Your turn

Take your agent's biggest information source — a document set, a database, an instrument's output. Design its read tool four times: naive dump, truncate-with-handle, search, and ask. For each, write the exact result for the same realistic query, then trace one full task: how many calls, how much lands on the wall, and where does each design strand the agent?