Module 2 — The Agent Loop & Lifecycle
Module 2 — The Agent Loop & Lifecycle
A language model is a pure function from a prompt to a completion. It cannot call a tool, cannot remember yesterday, cannot be interrupted, and cannot resume. Everything an agent appears to do that a model cannot do is done by the loop that surrounds it. Module 1 established the thesis and built the spine — a ~150-line single-file harness whose whole control flow was a while (true) that appended messages, called the model, ran any tool calls, and pushed the results back. That spine works on a sunny day. This module is about every other day: the model streams a tool call in eleven fragments and the eleventh never arrives; the user hits Ctrl-C while a write_file is halfway through; the model calls grep with identical arguments nine times in a row; the provider returns a 429 with a Retry-After of four minutes; the process is killed and the user expects --resume to work. The question this module answers is the one the blueprint poses: what exactly happens between a user turn and a final answer? The answer is a loop with named phases, named exit conditions, a durable log, and a cancellation story that reaches all the way down into a running tool.
Learning objectives
- M2.1 — Describe the canonical loop: compose → sample → parse → dispatch → observe → repeat, and name the exit conditions.
- M2.2 — Handle streaming: incremental text, tool-call assembly across deltas, and why UI and control flow must be decoupled.
- M2.3 — Implement turn boundaries and cancellation — user interrupt, abort signals, cooperative teardown mid-tool.
- M2.4 — Apply loop-hygiene guards: repetition detection, tool-timeout policy, step caps, and no-progress detection.
- M2.5 — Classify and recover from failures: transport errors, rate limits, context-length errors, malformed tool calls, provider drift.
- M2.6 — Explain session persistence and resumption — event log vs projection, and why replay beats snapshotting.
- M2.7 — Instrument the loop with token metering and per-turn accounting.
Prerequisites and estimated time
Prerequisites: Module 1 (the harness thesis, the anatomy of a request, and the Module 1 spine you built in M1.7). You should be comfortable reading TypeScript with discriminated unions, and comfortable with async/await, async iterators, and AbortController. No dsh internals are assumed.
Estimated time: 5 hours — roughly 2.5 hours reading, 2.5 hours on the lab.
Repo anchors for this module: packages/core/agent-loop/src/agent.ts, packages/core/agent-loop/src/tool-calls.ts, docs/agent-lifecycle.md, docs/subsystems/llm-streaming.md, docs/subsystems/session.md, docs/subsystems/session-projection.md, packages/guard/, packages/llm/llm-retry/, packages/llm/token-meter/.
Sections
- M2.1The canonical loop and its exit conditions~8 min3 questions
- M2.2Streaming: incremental text and tool-call assembly~8 min3 questions
- M2.3Turn boundaries and cancellation~8 min2 questions
- M2.4Loop-hygiene guards~7 min4 questions
- M2.5Classifying and recovering from failures~7 min3 questions
- M2.6Persistence and resumption: event log vs projection~8 min4 questions
- M2.7Token metering and per-turn accounting~17 min3 questions