Skip to content
Your first agent loop · Lesson 4 of 10

The loop

bits~/first-agent-looplesson 4/10 · 0% →

You: why does the loop check stop_reason?

◆ tutor
Every reply comes with a reason the model stopped talking. If it’s "tool_use", it wants you to run a tool and hand back the result. Anything else means it’s finished.
↳ highlighted agent.ts lines 12–32

You: run it

npx tsx agent.ts "Weather in Chicago?"

→ tool_use get_weather({ city: "Chicago" })
← tool_result { temp_f: 41, sky: "overcast" }
→ end_turn "41°F and overcast in Chicago."
✓ 2 turns · 1 tool call · 1.8s
◆ tutor
Two turns: one to ask for the weather, one to answer. Now break it on purpose. Delete line 31 and run it again. Predict first — does it loop forever, or crash?
import Anthropic from "@anthropic-ai/sdk";
import { tools, runTool } from "./tools";
const client = new Anthropic();
type Msg = Anthropic.MessageParam;
export async function agent(task: string) {
const messages: Msg[] = [{ role: "user", content: task }];
// the loop: think → act → observe → repeat
while (true) {
const res = await client.messages.create({
model: "claude-sonnet-5-5",
max_tokens: 1024,
tools,
messages,
});
messages.push({ role: "assistant", content: res.content });
if (res.stop_reason !== "tool_use") {
return res; // the model is done talking
}
const results = await Promise.all(
res.content
.filter((b) => b.type === "tool_use")
.map(runTool),
);
messages.push({ role: "user", content: results });
}
}
TypeScriptUTF-8● lines 12–32: the loop
OUTPUT
npx tsx agent.ts "Weather in Chicago?"
turn 1 stop_reason="tool_use" → get_weather
turn 2 stop_reason="end_turn"
41°F and overcast in Chicago.