// The agent loop. This is the whole idea behind an AI agent: call the model, // run whatever tools it asks for, send the results back, repeat until it // stops asking. The `on` hook lets the page animate each step; take it out // and this is a complete, working loop. import { SYSTEM_PROMPT, TOOLS, TASK, runTool } from "./world.js"; export async function agentLoop({ callModel, lake, maxTurns = 30, on = async () => {} }) { const messages = [{ role: "user", content: TASK }]; await on("start", { messages }); for (let turn = 1; turn <= maxTurns; turn++) { await on("request", { turn, messages }); const response = await callModel({ system: SYSTEM_PROMPT, tools: TOOLS, messages }); messages.push({ role: "assistant", content: response.content }); await on("response", { turn, response, messages }); // A long server-side turn can pause; sending the history back resumes it. if (response.stop_reason === "pause_turn") continue; // end_turn, max_tokens or refusal: the model is not asking for tools. if (response.stop_reason !== "tool_use") { await on("done", { stop: response.stop_reason, messages }); return { stop: response.stop_reason, messages }; } // Run every tool it asked for. All results go back in ONE user message. const results = []; for (const block of response.content) { if (block.type !== "tool_use") continue; const out = runTool(lake, block.name, block.input); results.push({ type: "tool_result", tool_use_id: block.id, content: out.text, ...(out.isError ? { is_error: true } : {}), }); await on("tool", { turn, block, out }); } messages.push({ role: "user", content: results }); await on("results", { turn, results, messages }); } await on("done", { stop: "max_turns", messages }); return { stop: "max_turns", messages }; }