What is an agent loop?
An agent loop repeats one cycle: the model picks an action, your code runs it, and the result goes back to the model until the task is done.
On Runtime the machine the loop acts on has limits of its own that the loop cannot lift: a lease, a spending cap and network rules enforced on the host. It also costs little while the loop waits on the model: a 2 vCPU, 4 GiB sandbox bills $0.03125 an hour when its CPUs are idle (pricing).
Where the term comes from
Anthropic's guide to building agents, published 19 December 2024, separates workflows, "systems where LLMs and tools are orchestrated through predefined code paths", from agents, where "LLMs dynamically direct their own processes and tool usage". It says agents "are typically just LLMs using tools based on environmental feedback in a loop", and that they commonly include stopping conditions "such as a maximum number of iterations". Each turn of the loop is one tool call and its result.
The parts of a loop
| Part | What it is | On Runtime |
|---|---|---|
| Environment | What the actions change and observe | One sandbox per task: a Linux machine with its own kernel |
| Actions | Commands, file edits, clicks | exec, files, spawn, the desktop, the code interpreter |
| Feedback | What goes back to the model | Exit code, output, truncation flags, screenshots |
| Step limit | A cap on iterations, in your code | Yours to set |
| Time limit | A wall-clock bound that survives a crash | The lease: timeoutSeconds, onLeaseEnd |
| Money limit | A ceiling the agent cannot raise | Daily limit per key; maxCostMicros per create |
| Safe retries | Repeating a step without doing it twice | An idempotency key on every write |
A minimal loop
The model is yours; the loop gives it a sandbox, runs each command it picks, and stops on "done", on the step limit, or when the lease ends.
TypeScriptimport { Sandbox } from "withruntime";type Step = { command: string[] } | { done: string };type Model = (history: string[]) => Promise<Step>; // your LLM callexport async function solve(model: Model, maxSteps = 20) { await using sbx = await Sandbox.create({ timeoutSeconds: 1200, onLeaseEnd: "stop" }); const history: string[] = []; for (let step = 0; step < maxSteps; step++) { const next = await model(history); if ("done" in next) return next.done; const run = await sbx.exec(next.command, { timeoutMs: 120_000 }); history.push(`$ ${next.command.join(" ")}\nexit ${run.exitCode}\n${run.stdout}${run.stderr}`); } return "step limit reached";}The array form of exec runs the program with no shell, so arguments the
model wrote cannot smuggle in a second command. await using stops the
sandbox when the function returns or throws.
Long and interrupted loops
A loop that spans hours or waits for a person can pause between turns.
idlePauseSeconds pauses the sandbox when no request arrives, keeping memory
and running processes, and the next exec wakes it, usually in about half a
second. Sandbox.getOrCreate(name) finds the same machine again from a new
process (sandboxes by name). To try
several next steps from one point, fork the sandbox
into up to ten running copies.
Related
- A sandbox for a coding agent
- What is tool calling?
- What is an agent sandbox?
- Agent evals and SWE-bench
Sources
- Anthropic, Building effective agents, 19 December 2024, checked 25 September 2026
Facts on this page were checked on 25 September 2026.