Models that do things
Models can't check today's weather or do exact currency maths — but they can ask *you* to. With tool use, the model replies with a tool name and arguments; your code runs the tool and sends the result back; the model continues until it can answer. That loop is an agent. Your job is to keep it safe: unknown tools, errors and endless loops.
The agent loop
async function runAgent({ model, tools, question, maxSteps = 5 }) {
const messages = [{ role: "user", content: question }];
for (let step = 0; step < maxSteps; step++) {
const reply = await model(messages); // either { answer } or { tool, args }
if (reply.answer !== undefined) return { answer: reply.answer, toolCalls: step, messages };
messages.push({ role: "assistant", tool: reply.tool, args: reply.args });
let result;
if (!tools[reply.tool]) result = { error: `Unknown tool: ${reply.tool}` };
else {
try {
result = { ok: await tools[reply.tool](reply.args) };
} catch (e) {
result = { error: e.message }; // errors go back to the model, not up the stack
}
}
messages.push({ role: "tool", tool: reply.tool, result });
}
throw new Error("Too many steps");
}const tools = {
convert: ({ amount, from, to }) => {
const NPR = { NPR: 1, USD: 133, INR: 1.6 };
if (!NPR[from] || !NPR[to]) throw new Error(`Unknown currency`);
return Math.round(((amount * NPR[from]) / NPR[to]) * 100) / 100;
},
weather: ({ city }) => ({ pokhara: "rain", kathmandu: "sunny" })[city.toLowerCase()] ?? "unknown",
};