6  Tools, Actions, and Environments

Every remedy Chapter 5 proposed — checking the plan, grounding the reflection, verifying the answer — ran on credit, borrowing against a power that chapter never examined: the agent’s power to act, to reach past its own deliberation and touch the world. This chapter is about that power. Left to itself, the foundation model only produces text about a world it cannot affect (Section 3.3). An agent acts; and the difference between the two is tools — the apparatus through which the model’s words become deeds and the world’s reply becomes the model’s next perception. This chapter is about how an agent reaches out of the closed world of text and lays hands on the world, and what it costs to let it.

None of this is new either. The frame is the oldest in the study of agents: a thing coupled to an environment through sensors and actuators, perceiving and acting in a loop. Reinforcement learning calls the set of available moves an action space; classical planning models each action by its preconditions and effects, as we saw in Section 5.2; robotics calls the acting parts effectors; and the situated-agent tradition of Section 4.2 insisted that intelligence lives in the coupling of agent and world rather than in the head alone. Into this frame the foundation model arrives with a peculiar profile — a magnificent capacity to decide what to do and no native ability to do any of it — and tools are what close the gap. The modern vocabulary of function calling, tool use, and computer use is, in large part, the classical perception–action loop wearing an API.

Action wears two faces, and the chapter attends to both. The first is grounding. The substrate’s deepest limitation, we said, was that it inhabited a closed world of symbols — knowing the word stove, and ten thousand sentences in which stoves appear, and never once having been burned; tools are how those symbols get fastened, however imperfectly, to the things they are about, how an agent comes to check whether the test passes, the file exists, or the price is right, rather than merely assert it. Action is the substrate’s one route to reality. The second face is danger. To act is to change the world, and some changes cannot be changed back. A wrong thought is cheap; a wrong deed need not be. The engineering of action is, in no small part, the engineering of letting an agent do enough to be useful and not so much that a single confident mistake is unrecoverable.

The chapter moves from the frame to the mechanism to the consequences. We begin with the perception–action loop, the classical skeleton on which all the rest hangs. We take up the modern mechanism — tools and function calling — and then the design of the agent’s action space, the menu of what it is permitted to do. We look at the most general action surfaces the field has reached for, executable code and the computer screen, and at what their generality costs in reliability. We turn to grounding and environments, asking what it means for action to fasten an agent to a world and what that world hands back. And we close on the question the preface promised and the book keeps circling: what it means to grant an agent the power to do something it cannot undo.

6.1 The Perception–Action Loop

Start with the most general picture of an agent there is, and one older than artificial intelligence: a thing embedded in an environment, taking in something of its surroundings and doing something back. In Russell and Norvig’s standard framing, an agent perceives its environment through sensors and affects it through actuators, and what joins the two is an agent function mapping the history of what it has perceived to what it does next (2021). The two ends close into a loop — perceive, decide, act; the world changes, by the agent’s doing or of its own accord; perceive again — the perception–action loop around which this chapter, and in truth the whole study of agents, is built. It is a picture the field shares with control theory, cybernetics, and biology, which is a reassuring sign: frames that several disciplines arrive at independently tend, as the old phrase has it, to carve nature near a joint.

Where does a foundation-model agent sit in this picture? Its sensors are not cameras and its actuators are not motors, but the structure is exact. Its perception is the context it is handed — the text in its window: the task, the history of the conversation so far, the results of whatever it last did. Its action is the text it emits that the harness is built to read as a move upon the world: a tool call, a message to another agent, a fragment of code to run. The agent function is split across the two layers we named in Section 4.6 — the model decides, the harness perceives and acts — and the observe–reason–act cycle we drew there in the abstract is just this classical loop seen close to. What Section 4.6 left as an arrow labelled act is exactly what the rest of this chapter is about: the machinery by which a string of tokens becomes a change in the world, and the world’s response becomes the next string of tokens.

One difference from the classical robot is worth drawing out, because it shapes everything downstream. A robot’s perception is raw: photons strike a sensor, and the numbers are what they are. A language-model agent’s perception is composed. Nothing reaches the model except as text the harness chose to assemble — which tool results to include, in what form, trimmed or summarised to fit the window. The agent does not see the world; it reads a report of the world that something else wrote, and its grip on reality is only ever as good as that report. A misleading observation — a truncated error message, a stale file listing, a result phrased to imply more certainty than it holds — is to an agent what a faulty sensor is to a robot, and a good deal easier to produce by accident. Deciding what an agent gets to perceive is itself a discipline, the context engineering we take up in Chapter 7; here it is enough to register that for these agents perception is not given but built.

The frame teaches one more lesson, the one the modern practitioner is likeliest to skip: the line between agent and environment is drawn, not found. Is the file system part of the agent or part of its world? The Python interpreter it runs code in? The database it queries, the colleague agent it delegates to? Nothing in nature settles these; the boundary is a modelling choice, and where it is placed fixes what counts as perception and what as action. Draw the interpreter inside the agent and running code is private deliberation; draw it outside and the very same act becomes an action upon an environment, with all the consequence that word will have acquired by the end of this chapter. For multi-agent systems the choice turns sharp, because one agent’s action is another’s perception, and the environment of the first agent contains the second — which is why a boundary that is an afterthought for a lone agent becomes a central design question the instant there are two. We return to it in earnest in Part III.

This loop is the skeleton on which the chapter hangs, and each section to come is a bone of it. Tools are the actuators; the action space is the set of moves the agent function may emit; computer use is an actuator stretched as wide as it will go; grounding is the question of whether perception faithfully reflects the environment; irreversibility concerns actions whose mark on the environment cannot afterwards be wiped away. What the loop does not yet explain is its own most mysterious step — how, concretely, the model’s text becomes a deed at all. That mechanism is tools and function calling, and we turn to it now.

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#E8ECFF", "primaryBorderColor": "#4054B2", "primaryTextColor": "#16171B", "lineColor": "#3B4351", "edgeLabelBackground": "#FAF7F0", "clusterBkg": "#EFE9DC", "clusterBorder": "#766F65"}}}%%
flowchart TB
    subgraph AG["Agent"]
        direction TB
        M["Model<br/>decides"]
        H["Harness<br/>perceives and acts"]
    end
    E["Environment"]
    M -->|"tool call: proposes"| H
    H -->|"composed perception"| M
    H -->|"action: disposes"| E
    E -->|"result / world state"| H
    classDef world fill:#EFE9DC,stroke:#766F65,color:#16171B
    class E world
Figure 6.1: The perception–action loop instantiated for a language-model agent. The harness is the single hinge between a model that only ever proposes and an environment that only ever replies: it composes every perception the model reads and executes every action the model emits, so the drawn agent–environment boundary and the chokepoint through which all action passes are one and the same line.

6.2 Tools and Function Calling

How does a string of tokens become a deed? The answer is disarmingly plain: the model does not act; it asks. Trained and prompted to do so, it emits, in place of prose, a structured request — the name of a tool and a set of arguments — and stops. The harness reads that request, performs the corresponding operation (runs the function, calls the API, executes the code), and feeds the result back into the context as the next observation. The model proposes; the harness disposes. This is function calling, or tool use: the agent’s actuator is its own output, taken at its word.

The separation is the whole point. The model never touches the file system, the network, or the database; it produces only text that requests such a touch, and a deterministic layer outside the model decides whether and how to carry it out. This is what makes the substrate’s closed world of text safe to wire to a consequential world: every action the agent takes passes through a single chokepoint that the engineer, not the model, controls. It is also what makes tools the agent’s actuators in the exact sense of Section 6.1 — the model decides, the harness acts — and it is the reason, as Section 6.6 will press, that an agent’s permissions and safeguards live in the harness and never in the model’s good intentions.

The mechanism arrived by stages. At first models were merely coaxed into it, prompted to interleave a thought with an action in the manner of the ReAct loop of Section 4.6. Then Toolformer showed that a model could be taught, in self-supervised fashion, to decide for itself which interface to call, when, and with what arguments (Schick et al., 2023) — tool use learned rather than hand-prompted. The laboratories productised the idea as function calling: declare your tools in a schema, and a post-trained model will emit calls that conform to it. And because every integration was at first bespoke, the interfaces were standardised — most consequentially by the Model Context Protocol (Anthropic, 2024b), which gives tools a common wire format so that a tool written once can be offered to any compliant agent, and which we take up properly among the protocols of Chapter 22. The arc runs from coaxing, to teaching, to a standard.

Standardisation eventually moved the executing as well. At first your harness ran every tool the model asked for; before long the platforms began to offer hosted tools — web search, file retrieval, code execution, even computer use — that the platform runs on the model’s behalf and hands back as results, so that the layer disposing of the model’s request may now be the vendor’s machinery rather than your own.1 The separation of proposing from disposing survives this intact; what changes is only whose machinery does the disposing, and a tool the platform runs for you is one fewer thing to build and one fewer thing you can see inside — the same control trade-off, filed under convenience this time.

Standardisation is not, however, the only tool surface, nor the oldest. Long before any protocol there was the Command Line Interface (CLI), which already gave every program a uniform way to be invoked — arguments in, text out — so that a single run-a-shell-command tool puts the whole command-line ecosystem, grep and git and curl among thousands, at an agent’s disposal with no integration written for any of them. The Model Context Protocol and the command line answer the same need from opposite ends: the protocol gives newly built tools a typed, discoverable interface, while the shell offers the accumulated inheritance of decades. Which to prefer is a real engineering choice — the protocol is safer and more legible, the shell incomparably richer and cheaper to reach — and why the command line makes so apt an action surface for an agent in particular is a matter we take up in Section 6.3.

There is a classical antecedent hiding in the JSON, and it is worth surfacing. A tool is declared to a model by a schema: a name, a description in plain language of what the tool does and when it should be used, and a typed list of the arguments it accepts. That is, very nearly, a STRIPS operator of Section 5.2 — a name, the conditions under which it applies (the description’s when to use it, the parameter types it will accept), and an effect upon the world (what it does). The classical planner read such operators in order to search for a plan; the modern model reads them in order to choose its next action. The representation the field devised for automated planning is, almost unchanged, the representation it now uses to tell a model what it is able to do — shorn only of the guarantees (Section 5.4), since the model’s checking of a tool’s preconditions is just more fallible reasoning rather than a proof.

The correspondence is not merely notional: a tool is just data, and the layer that reads it a few lines of ordinary code. Declared as a name, a plain-language description, and a JSON-Schema list of typed parameters, a single run-a-test-suite tool — with the dispatcher that stands between model and world — comes to this:

from collections.abc import Callable

run_tests_tool = {
    "name": "run_tests",
    "description": "Run the suite at a path; use to check the code.",
    "parameters": {"type": "object", "required": ["path"],
                   "properties": {"path": {"type": "string"}}}}
suite = {"tests/test_auth.py": {"passed": 5, "failed": 0}}
types = {"string": str, "integer": int, "boolean": bool}

def run_tests(path: str) -> dict:
    return suite[path]  # a real runner would shell out here

def dispatch(tool: dict, fn: Callable[..., dict], args: dict) -> dict:
    for field, spec in tool["parameters"]["properties"].items():
        if field in tool["parameters"]["required"] and field not in args:
            return {"error": f"missing field: {field}"}
        if field in args and not isinstance(args[field], types[spec["type"]]):
            return {"error": f"{field} must be {spec['type']}"}
    return fn(**args)

dispatch(run_tests_tool, run_tests, {"path": "tests/test_auth.py"})
# -> {'passed': 5, 'failed': 0}
dispatch(run_tests_tool, run_tests, {"path": 42})
# -> {'error': 'path must be string'}

The two demonstrations trace the branches a dispatcher must cover: a well-formed call runs and returns an observation, and a malformed one — here a path of the wrong type — comes back as an observation too, an error dictionary rather than a raised exception, because the model’s next perception has to be something it can read and retry against, not a stack trace. It is deliberately a toy — run_tests fakes its suite, the schema check is a handful of lines — where the harness of Part VI will do the disposing at industrial scale; but the skeleton is already all here, the model proposing a name and arguments and a deterministic layer validating, executing, and handing back what the world said.

A closing word on what counts as a tool, because the category is deliberately broad. A tool is any operation the harness can perform on the model’s request: read a file, run a shell command, query a database, call a weather service, search the web, hand a subtask to another agent, or — the case the next chapter takes up — fetch from a store of memory. Retrieval-Augmented Generation (RAG) (Lewis et al., 2020), the usual way of giving a model access to a corpus it was not trained on, is from this chapter’s vantage simply a tool that returns relevant text. The breadth is the point: anything you can wrap in a function, you can hand an agent as an action. Which raises at once the question the next section exists to answer — not what a single tool is, but which tools, and how many, an agent ought to be given.

6.3 Action Spaces

Which tools should an agent be given, and how many? The set of moves available to it is its action space: in a Markov Decision Process (MDP) — Bellman’s model of sequential decision-making (1957) — it is the set of actions selectable in each state, in classical planning the set of operators, and for a language-model agent it is precisely the set of tools you elect to give it. The name is worth importing because it imports the lessons that come with it. An action space is never incidental. It bounds outright what the agent can achieve — there is no completing a task for which the agent has no action — and it sets the difficulty of the agent’s decision problem, since every additional move widens the branching factor it must choose through. Designing the action space is among the most consequential decisions in building an agent, and among the least examined.

The tension at its heart is one of granularity and number. Make the tools too coarse or too few and the agent simply cannot express what the task demands; it has no move that does the thing. Make them too fine or too many and the agent drowns — with several dozen tools it reaches for the wrong one, squanders its reasoning deciding among near-duplicates, or strings ten calls together where one would have served. This is an expressiveness-against-controllability trade-off, and Section 6.4 will meet it again at the extreme. Our running coder agent sits near the sensible middle: a handful of well-chosen tools — read a file, edit a file, run the tests, run a shell command — each doing one legible thing, works far better than either a single do-everything tool or a hundred fiddly micro-tools. It is also why the frameworks fuss so over tool descriptions: a tool the model cannot tell when to use is, to the agent, no tool at all.

The choice of action space is, in the exact sense of Section 4.1, an architectural decision — a structural commitment taken early, awkward to revise late, that the rest of the design hangs from. It fixes the agent’s reach (what is possible at all), its reliability (how readily it picks the right move), its safety (an action you never grant is one the agent cannot take — the cheapest safeguard there is, as Section 6.6 will urge), and its legibility (a space of named, typed tools is far easier to audit than an open-ended one). Engineers who would never ship a class with a hundred public methods will cheerfully hand an agent a hundred tools; the discipline of a small, coherent interface applies to an agent’s actions exactly as it applies to code.

That discipline has a distinguished pedigree. The UNIX philosophy — make each program do one thing well, expect the output of one to become the input of the next, and handle everything as text, “because that is a universal interface” — is the classical statement of exactly this principle (McIlroy et al., 1978), and the command line of Section 6.2 is the original well-designed action space: a few hundred small tools, each with a legible job, composing through pipes into behaviour none of them holds alone. McIlroy’s closing clause is the uncanny one. Text as the universal interface — the very property Section 3.2 found in language — is exactly what fits the command line to an agent that thinks in text: the agent emits a command as text and reads the result as text, precisely as a UNIX tool passes its output down a pipe. The field had designed the agent’s ideal action space half a century before there was an agent to use it, and called it the shell.

The shell points the way to a more radical answer still: to stop enumerating moves at all, and make the action space a programming language. Rather than a fixed menu of tools, let the agent write and run code, which can call any available function, compose operations, loop, branch, and feed the result of one step into the next — a whole procedure in a single action. On agentic benchmarks, the CodeAct study found agents given code as their interface outperformed those confined to a fixed list of JSON tool calls (Wang et al., 2024) — for the plain reason that code is the universal action space: anything computable lies one action away, and composition comes free. The model is, besides, unusually good at writing code (Section 3.2), so handing it code as its actuator plays directly to the substrate’s strength.

The universal action space, though, buys its generality at the standard rate. Code that can do anything can do anything wrong: one emitted snippet can delete the wrong files, drain the budget in a runaway loop, or reach out across the network in ways a fixed menu of tools never could. The wider the action space, the harder it is to bound, to sandbox, to predict, and to trust — which is this section’s trade-off filed to a point, and precisely the subject of the next. For executable code is only the first of two bids for a genuinely universal action surface; the second is to let the agent operate a computer as a person does, and there we turn.

6.4 Computer Use and the Universal Action Surface

If executable code is one bid for a universal action surface, the second is more literal still: give the agent the surface a person already uses. A human at a computer needs no API and no schema — only a screen to read, a pointer to move, and keys to press. An agent equipped the same way — vision to perceive a screenshot, the means to emit clicks and keystrokes — can in principle do anything a person can do at a computer, including drive software that exposes no programmatic interface whatsoever. This is computer use, or the GUI agent: the agent perceives the screen as pixels and acts through synthetic mouse and keyboard events. Anthropic shipped an early version to developers in late 2024 (Anthropic, 2024a), and several of the major laboratories have since followed. It is the universal action surface in its most literal form — not “anything computable”, as code offers, but “anything a human can do at a screen”.

The aspiration is not new. The established practice of Robotic Process Automation (RPA) has automated exactly this surface for years (van der Aalst et al., 2018), driving enterprise software through scripted clicks and keystrokes; van der Aalst and colleagues define it almost word for word as we have just defined computer use — software that operates the user interface of other systems the way a person would. What computer use changes is the how: where an RPA bot follows brittle rules pinned to particular coordinates and field names, and breaks the instant a layout shifts, a computer-use agent reads the screen afresh and works out what to do, exchanging one kind of brittleness for another.

The appeal is generality without integration. Code needs a library to call; a tool needs a schema to be declared; computer use needs neither, because it meets an application exactly where the human meets it, at the visible surface. No integration work, no cooperation from the target software, no schema to maintain: if a person can accomplish the task by pointing and clicking, then so, in principle, can the agent. This is the dream of the fully general assistant — point it at any computer task at all and it simply does it, the way you would.

In practice it remains the hardest action surface to make reliable, because it stacks every hard problem at once. The agent must read a noisy, high-dimensional screen accurately, where vision is fallible; it must locate small targets exactly, where a misplaced click does nothing useful or something unintended; and it must chain dozens of such brittle steps without a misstep, where errors compound. It is slow — a screenshot and a model call for every click — expensive in vision tokens and turns, and easily derailed by a shifted layout, a popup, or a page that loads a beat too late. Benchmarks such as OSWorld and WebArena — batteries of real tasks on a real operating system and a live web — were built to measure exactly this difficulty (Xie et al., 2024; Zhou et al., 2024), and the trajectory they record is itself the lesson: agent success has climbed steeply, in OSWorld’s case from roughly a tenth of tasks to a clear majority inside about a year, drawing level with and then past the human baseline. Any particular figure will be stale by the time you read it — treat it as a waypoint, not a verdict.

What has not moved is the shape of the difficulty, and most of the gains have come precisely from refusing to take it head-on: the better agents lean on accessibility trees and page structure where they can get them rather than working from raw pixels, and split perception, planning, and execution across specialised steps rather than asking one model to do everything at a glance. Driving a human interface pixel by pixel remains the slowest, costliest, and least predictable way for an agent to act — which is the durable reason to reach for it last.

So the two bids for universality trade against each other along the axis this chapter keeps returning to. Code (Section 6.3) is general within the world of things that have an interface to call — fast, composable, exact — but blind to software that offers no programmatic handle. Computer use is general across all software, the API-less included, and pays for that reach in speed and reliability. The working rule writes itself: prefer the narrowest action surface that still reaches the task. Use a specific tool where one exists; drop to code when you need to compose; reach for computer use only when nothing narrower can touch the target, because every step towards generality is a step away from reliability. It is the expressiveness-against-controllability trade-off of Section 6.3, enlarged to the scale of the whole machine.

Table 6.1: The three action surfaces, ordered from narrowest to most general. Read across the last two columns and the chapter’s single trade-off appears in miniature: each step towards generality widens reach and costs speed, predictability, and control — the surface is never a free choice, only a priced one.
Action surface What it requires Reach Speed and reliability When to use it
Specific tool A schema declaring it (name, description, typed parameters) Only the operation it was built for — the narrowest surface Most reliable and auditable; each does one legible thing Where one already exists
Executable code A library or interface to call Anything computable with an interface to call; blind to software with no programmatic handle Fast, composable, exact; but harder to bound, sandbox, and trust When you need to compose operations
Computer use (GUI agent) Only a screen, pointer, and keys — no integration, schema, or cooperation from the target All software, the API-less included — anything a human can do at a screen Slowest, costliest, least predictable Only when nothing narrower can touch the target

There is a deeper reason computer use is so hard, and it carries us back to the chapter’s frame. The screen is an interface designed for human perception and action — built for eyes that parse a layout at a glance and hands that hit their targets — and the agent reaches it through a channel, screenshots in and synthetic events out, that is a thin imitation of the human one. The agent is acting in an environment fitted to somebody else’s body. Which sharpens the question the next section exists to ask: what does it actually mean for an agent’s action to connect to the world — for the symbols it manipulates to be fastened to the things they act upon — and what does the world hand back when they are? That is grounding, the next section’s concern.

6.5 Grounding, Environments, and Feedback

Recall the symbol grounding problem of Section 3.3: Harnad’s observation that symbols manipulated only in relation to other symbols are never quite fastened to the things they are about (1990) — the model fluent about a stove it has never lit. Tools are the practical answer to that worry, incomplete but real. Through a tool the claim “the tests pass” can be checked against the world by running them, rather than merely asserted; the agent does not say the file exists, it reads it; it does not guess the price, it queries it. Action is how an agent’s symbols come into contact with their referents, and grounding, in the working sense an engineer cares about, is simply the loop between symbol and world that tools keep turning.

The philosophical gap, mind you, does not close; it relocates. A tool’s result is itself a symbol — a line of text — which the model must in turn interpret, so the distance between sign and thing reappears one storey up. The agent reads “tests passed” and must still grasp what that means; a misread or misleading observation re-opens exactly the disconnect the tool was meant to close. Tools do not endow the model’s symbols with intrinsic meaning — in Bender and Koller’s sense they remain form in want of it (2020) — they give the agent a channel by which to check its symbols against an authority outside itself. That is plenty for engineering, where what matters is that the world can correct the agent; it is not nearly enough for philosophy, where what is wanted is that the symbols be genuinely about something. Grounding, honestly described, is managed — kept in tolerable register with reality by repeated contact — rather than solved.

The thing an agent acts upon and perceives is its environment, and the environment does for the agent what the agent cannot do for itself: it furnishes a source of truth. The lesson of Section 5.4 returns in its most general form — the cheapest verifier is the world. An environment does not argue, does not hallucinate, and does not flatter; it simply does what it does and reports the result. This is the whole reason grounded reflection succeeds where ungrounded self-assessment fails (Section 5.5): the environment is an authority independent of the model’s own convictions, and an agent embedded in a responsive one has access to something no quantity of internal reasoning can manufacture — a reality check, in the most literal reading of the phrase.

Environments differ, and the classical theory of agents supplies the axes along which they do (Russell & Norvig, 2021) — a vocabulary worth owning, because every hard case in this book is a position on it. An environment is fully or partially observable, according to whether perception reveals the whole relevant state or a fragment (the repository can be listed; the user’s intent cannot); deterministic or stochastic, according to whether an action’s outcome is fixed or a draw; episodic or sequential, according to whether today’s choice constrains tomorrow’s; static or dynamic, according to whether the world holds still while the agent deliberates; discrete or continuous in its states and actions; and — the axis this book exists to take seriously — single-agent or multi-agent, the latter dividing again into the cooperative and the competitive. The running team’s world scores awkwardly on nearly every axis: partially observable, stochastic wherever a model or a flaky test sits, resolutely sequential, dynamic — CI runs finish, colleagues commit — and multi-agent by construction, which is the honest reason so much of this book is about coping rather than optimising. Each hard setting will earn its own machinery in time: partial observability the beliefs of Chapter 9 and their formal completion in Chapter 17, dynamism and co-adaptation the moving targets of the same chapter, plurality very nearly everything else.

The difference most consequential day to day, though, is one the classical axes do not headline: whether the feedback is real. A real environment — the production database, the live repository, the open web — returns true feedback at true risk: the agent’s mistakes are actual mistakes, with actual costs. A sandbox — a copy, a test harness, a simulated world — returns feedback at reduced risk, paid for in fidelity, since the agent is now learning to act in a world that may not match the one that matters. Choosing between them is the action-shaped version of safe exploration, the reinforcement-learning problem of letting an agent learn from real consequences without suffering the worst of them. Dry-runs, staging environments, read-only modes, reversible sandboxes — all are ways of buying feedback while deferring or bounding the risk, and their engineering is a thread we pick up in Chapter 23. Note, too, that the boundary-drawing of the perception–action loop returns here in practical dress: what counts as the environment, and how faithfully it stands in for reality, is itself something the designer chooses.

Whatever the environment, what it returns is an observation, and that observation is the perception that closes the loop — the agent acts, the world changes, the world reports, the agent perceives the report and acts once more. There, at last, is the perception–action loop complete, reaching past text into the world and back again. But mind the assumption that has quietly underwritten the whole chapter: that an action, once taken, can be checked, corrected, and retried, that a wrong move is recoverable because the world will report it and let the agent try again. For a large and comfortable class of actions this holds. For another class it does not hold at all: some actions, once taken, can never be checked-and-retried, because they cannot be undone. The environment will confirm that the email was sent; it will not let the agent unsend it. That class — the irreversible — is where the weight of action comes down hardest, and it is the last thing this chapter must weigh.

6.6 Irreversibility and the Weight of Action

The chapter has leaned throughout on an assumption it can now name and qualify: that an action, once taken, can be checked and retried. Where it holds, action is forgiving, and the unreliability of everything upstream — the brittle reasoning of Section 5.3, the unverified plan of Section 5.4 — is absorbed by the loop, which simply tries again. Where it fails, none of that forgiveness is available, and the whole weight of the agent’s fallibility comes to rest on a single move. The reason action earns a chapter, and a wariness that reasoning does not, is a deep asymmetry: a reasoning error costs a handful of tokens and is corrected on the next turn, while an action error can cost the data, the money, or the trust — and, for an action that cannot be undone, there is no next turn in which to correct it. The model may be wrong cheaply; the agent acting on it may not.

The irreversible actions are a category apart. Send the email, drop the table, execute the trade, merge the branch, delete the backups, wire the funds: once done, the world offers no path back. This is exactly where the grounding loop of Section 6.5 quietly fails — the environment will faithfully report what happened, but reporting is not reversing. For a reversible action the loop is merciful: act, observe, correct. For an irreversible one the agent has a single attempt, backed by reasoning two chapters have taught us not to trust, and no retry behind it. It is the loaded foot-gun of Section 4.2 made literal: an impulse, reflexive or confidently deliberated, wired straight to an effect that cannot be taken back, with nothing interposed between the deciding and the doing.

The classical literature saw the difficulty coming from two directions. Planning had the qualification problem — McCarthy’s name for the impossibility of stating in advance every condition under which an action might fail or misfire, a close cousin of the frame problem of Section 4.3 — which says, in effect, that an action model is always incomplete and the world always holds one more way to surprise it. And the safety literature had the practical hazards of an agent loosed upon the world: Amodei and colleagues’ catalogue of concrete problems — avoiding negative side effects, and the safe exploration of Section 6.5 in its sharpest form — speaks directly to the case at hand (2016). The modern agent inherits both worries in sharpened form, because it wields real tools on real systems, quickly, and on the strength of judgement we have already learned to distrust.

The engineering of action is, in consequence, largely the engineering of containing it — of keeping an agent’s reach short of the irreparable — and the apparatus is mostly unglamorous and mostly borrowed. Least privilege, from security: grant the agent only the actions the task actually requires, since an action never granted is one it cannot botch (the cheapest safeguard there is). Sandboxing and dry-runs: let the agent act first against a copy or a simulation (Section 6.5), and against the real world only once the result has been checked. Human-in-the-loop approval: route the irreversible and the high-stakes through a person who confirms before execution — the agent proposes, a human disposes, for the moves that matter most. And reversibility by construction: prefer designs in which actions can be undone — soft deletes, transactions, staged commits — so that the irreversible class is kept as small as it can be. No one of these makes an agent safe; together they make a confident mistake recoverable more often than not, which is the realistic goal.

Beneath the techniques lies a fact worth stating without ornament, because it is the hinge between this part of the book and the parts to come. To give an agent tools is to give it the power to act, and the power to act is, inseparably, the power to do harm: there is no useful agent that cannot, in principle, also do damage, because usefulness and danger enter through the same door — the action interface this chapter has spent itself building.

How to make what passes through that door dependable, secure, and accountable is too large a question for one chapter, and it is parcelled out to three later ones: dependability, the engineering of acting reliably, in Chapter 23; safety and security, the engineering of acting without harm even when the agent is attacked or suborned, in Chapter 25; and accountability — who authorised an action, who could have stopped it, and who must answer for it — in Chapter 26. With perception, reasoning, and action now in hand, Part II has assembled very nearly a whole agent. One faculty is still missing — the memory that lets it persist, recall, and carry a thread across the turns of the loop — and that is the last of the anatomy, and the subject of Chapter 7.

6.7 Summary

  • Action is how an agent reaches out of the closed world of text — the apparatus by which the model’s words become deeds and the world’s reply becomes its next perception. The substrate decides what to do; tools are what let it do anything at all.
  • The perception–action loop is the classical skeleton. An agent coupled to an environment through sensors and actuators, turning in a loop, is the oldest frame in the field; the modern agent is that loop with the model in the deciding seat and tools as its actuators.
  • Tools and function calling are the mechanism. The model emits a structured request; the harness executes it and hands back the result. A tool’s schema is an action model in the STRIPS sense — preconditions and effects in JSON — which is why the classical account of actions still describes it.
  • The action space is a design decision. The set of moves an agent is given trades expressiveness against controllability: too few and it cannot do the job, too many and it loses its way — and the discipline of the small, coherent interface applies to an agent’s tools exactly as it applies to code.
  • Prefer the narrowest action surface that still reaches the task. Code and the computer screen are the field’s two bids for a universal surface, and both buy generality with reliability: use a specific tool where one exists, drop to code when you need to compose, and reach for the screen only when nothing narrower can touch the target.
  • Tools are the substrate’s route to reality. They are the practical, partial answer to the symbol-grounding problem of Chapter 3 — an agent can check the world rather than merely assert it — but grounding is managed, not solved: the gap between symbol and referent persists, and acting on it gives it consequences.
  • Action’s second face is danger. A reasoning error costs tokens; an action error can cost the data, the money, or the trust, and some actions cannot be undone. The engineering of action is, in large part, the engineering of containing that asymmetry — approval, sandboxing, least privilege, and a wary eye on the irreversible.
  • Acting is at once the agent’s grip on the world and its capacity to harm it. To hand an agent tools is to grant both in the same gesture; the book’s later treatment of dependability, safety, and accountability begins from this fact.

6.8 Exercises

Exercise 1. One turn of the running team’s coder agent produces five events: (1) at the model’s request, the harness reads src/parser.py from the repository; (2) the harness appends the file’s contents to the context; (3) at the model’s request, an interpreter runs a ten-line snippet that computes a statistic over those contents and prints one number, writing nothing; (4) the harness appends the interpreter’s output to the context; (5) the harness appends a message from the reviewer agent: “the empty-input case is wrong”. Section 6.1 holds that the agent–environment boundary is drawn, not found; draw it twice. Under drawing A the file system and the interpreter sit inside the agent and the reviewer outside; under drawing B only the model and the harness are the agent, and everything else is environment. (a) Classify each of the five events, under each drawing, as internal to the agent, an action upon the environment, or a perception of it — ten classifications, each with a phrase of justification. (b) The snippet in event 3 is later replaced by one that deletes a stale cache directory. Say what that act is under each drawing, name one safeguard from Section 6.6 whose applicability the classification decides, and state the failure that drawing A invites. (c) The snippet is instead changed to write profile.json into the repository tree, and the tester agent reads that file on its own next turn. Show, with a two-step trace in the loop’s vocabulary, why drawing A misdescribes this exchange, and redraw the boundary so that one agent’s action becomes the other’s perception.

Exercise 2. The dispatcher printed in Section 6.2 — reproduced in the companion repository as foundations/algorithms/tool_schema.py — promises that a malformed call comes back as an observation, an error dictionary, not a stack trace. It does not keep the promise. (a) Exhibit two calls, each a well-formed argument dictionary for run_tests_tool, that make the printed dispatch raise an exception instead of returning: one that slips through a gap in the validation loop, and one that fails inside the tool function itself. Name the exception each raises, and say where the gap in the validation loop lies. (b) Repair the dispatcher — fifteen lines suffice — so that both calls, and any like them, come back as error dictionaries: undeclared arguments must be rejected, and a tool that raises must have its failure reported as an observation. Show your dispatcher’s output on both calls from (a). (c) In the vocabulary of the perception–action loop, state what the agent loses when an exception escapes instead: what happens to its next perception, and why an error observation lets the loop continue where a crash cannot.

Exercise 3. Three of the coder agent’s tools are declared with these descriptions: read_file(path) — “read a file into the context; call this before editing a file”; apply_patch(path, diff) — “apply a unified diff to a file; only call this once the file has been read”; run_tests() — “run the suite; use it to check the tree after a change”. Work over the propositions \mathrm{read}(f), \mathrm{patched}(f), and \mathrm{tested}. (a) Write each tool as a STRIPS operator in the sense of Section 5.2: preconditions, add list, delete list. Exactly one operator warrants a non-empty delete list; identify it and justify the deletion. (b) From the empty initial state, give the plan a classical planner returns for the goal \mathrm{patched}(f) \wedge \mathrm{tested}, where f is src/auth.py, showing at each step the state before, the precondition check, and the state after. Point to the entry in your operators that forces run_tests to come last. (c) At run time the model emits apply_patch on a file it has never read, and the dispatcher of Section 6.2 duly executes it. State precisely which classical guarantee has been lost, then restore it in the harness: write a wrapper around dispatch, a dozen lines, that records which paths read_file has returned and answers any premature apply_patch with an error observation — enforcement moved from the model’s judgement into deterministic code.

Exercise 4. The tester agent’s job takes four steps: set up a fixture, run the suite, parse the failures, file a report. Two action-space designs are proposed. Under the fine design each step is its own tool: a call costs c = 300 tokens and succeeds with probability q = 0.92, independently across attempts. Under the coarse design a single tool performs all four steps in one call costing 900 tokens, which succeeds with probability r = 0.7. In both designs the harness detects every failure, and the agent retries the failed call until it succeeds. (a) Compute the expected token cost of the whole job under each design. (b) Find the coarse-tool reliability r^* at which the two designs cost the same in expectation. (c) Both computations rest on an assumption that Section 6.6 spends itself qualifying. Name it, and explain which design the chapter’s reasoning favours when the report-filing step, once executed, cannot be retracted — and why expected token cost is then no longer the deciding criterion.

Exercise 5. The coder agent runs an edit–test loop on a broken module. After each edit the tree is actually correct with probability 0.6, independently across rounds. The harness truncates the test runner’s output to fit the window, and the truncation misreports a failing run as a pass with probability e = 0.1; a passing run is always reported as a pass. The agent stops at the first reported pass. (a) Compute the probability that, when the agent stops, the tree is in fact still broken. (b) Show that this probability does not depend on how many rounds the loop happens to run. (c) The budget stretches to exactly one improvement: a stronger model that raises per-edit correctness to 0.75, or a repaired truncation policy that cuts the misreport probability to 0.02. Compute the false-stop probability under each, say which wins, and connect the outcome to what Section 6.1 says about an agent’s perception being built rather than given.

Exercise 6. The team’s release agent proposes merges to the main branch. A proposed merge is wrong with probability w = 0.02, and a wrong merge that lands costs L = 5000 units to put right. An approval gate — a human confirming each merge before it executes — costs g = 8 units per merge and catches a wrong merge with probability d = 0.9; a caught merge is abandoned at no further cost. (a) Compute the expected cost per proposed merge with and without the gate. Does the gate pay? (b) Derive the break-even loss L^* below which the gate stops paying, and evaluate it. (c) Staged deployment now makes any landed merge recoverable at a cost of \rho = 40 units in place of L. Compute the expected cost per merge of all four designs — neither safeguard, gate only, staging only, both — rank them, and state what the ranking says about where safeguard effort should go first.

Exercise 7. Five tasks land on the running team’s desk: (i) bump the version string in pyproject.toml from 2.3.1 to 2.3.2; (ii) find every call site of a deprecated function across the repository and report a count per module; (iii) mark the team’s ticket as done in the company tracker, which humans drive through its web interface but which also publishes a documented REST API; (iv) enter month-end figures into a supplier’s invoicing portal that offers no API and no export and renders only in a browser; (v) restart a flaky CI runner through an internal web dashboard that has no API — though the infrastructure team ships a small command-line utility that performs the same restart. (a) Using the working rule of Section 6.4 and the columns of Table 6.1, assign each task the narrowest action surface that reaches it, with one sentence of justification apiece; two of the five are traps in which the superficially obvious surface is not the right answer — identify both. (b) For the one task that genuinely requires computer use, state what the choice pays in each of the last two columns of Table 6.1, and propose one change to the task’s environment — not to the agent — that would let a narrower surface reach it.

Exercise 8 (project). Build the dispatcher the chapter’s toy gestures at. Starting from foundations/algorithms/tool_schema.py in the companion repository (Appendix C) and the runtime dispatcher in foundations/tools.py, write a module — standard library only, in the style of the foundations layer — whose dispatch (a) validates arguments against a JSON-Schema subset covering the types string, integer, boolean, and number, arrays with typed items, nested objects carrying their own required and properties, and enum constraints; (b) rejects undeclared arguments at every nesting level, of which your repair in Exercise 2 is the flat case; (c) returns every failure, whether of validation or of execution, as an error observation and never raises; and (d) appends to a caller-supplied audit log one record per dispatch — tool name, arguments, outcome, wall-clock time — whether the call succeeded or not: the raw material of the accountability that Chapter 26 will demand. Ship a test battery with at least one test per failure class, including a boolean supplied where a string or an integer is declared (mind what Python’s bool is a subclass of).

Exercise 9 (lab). The chapter claims that a tool the model cannot tell when to use is, to the agent, no tool at all. Measure it. Fix five tools for the running team — read a file, edit a file, run the tests, search the code, run a shell command — and write twenty one-sentence requests, each with one intended tool. Using any function-calling model, present every request under three menus: menu A, the five tools crisply described (what each does, and when to use it); menu B, the same five schemas with vague, overlapping descriptions; menu C, menu A plus five plausible near-duplicates (search_files beside search_code, and so on). Score each menu by the fraction of requests whose first emitted call names the intended tool. Report the pattern across the three menus, say which mechanism from Section 6.3 each degradation isolates, and explain why the two degradations you have separated — description quality and menu width — are the two halves of the chapter’s expressiveness-against-controllability trade-off. Note the model and the date; the pattern, not the number, is the result.


  1. OpenAI’s Responses API shipped these as built-in tools, and emerging vendor-neutral descriptions of such hosted calls return them as typed items beside the model’s own output; a remote MCP server is reachable by the same route — which closes the loop with the protocol just described.↩︎