The core loop
A tool-calling agent is not one model call. It is a loop: ask the model, inspect the response, run any requested tool, send the tool result back, then ask again.
The model decides what tool to request from the tools you gave it. Your code executes the tool and controls what result goes back.
Who does what
The model emits a structured tool call, such as search_notes with arguments. Your app checks the name, parses the arguments, runs the matching function, and records the result.
Do not let the model pretend it ran the tool. If there is a tool call, your code must produce the tool result. If there is no tool call, the model’s message can be the final answer.
Loop shape
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 6 done
Minimal loop
This is the shape you want in your repo. The callModel function stands for whichever model API or SDK you use. Keep the loop code separate from the tool functions.
This example uses one fake campus tool so you can test the flow without paid APIs.
const tools = {
get_canteen_menu: async ({ day }) => {
const menus = {
monday: 'Idli, sambar, chai',
tuesday: 'Poha, bread omelette, chai',
wednesday: 'Paratha, curd, chai'
};
return menus[day.toLowerCase()] || 'Menu not available';
}
};
async function runAgent(userMessage) {
const messages = [{ role: 'user', content: userMessage }];
while (true) {
const response = await callModel({
messages,
tools: [
{
name: 'get_canteen_menu',
description: 'Get the college canteen breakfast menu for a day',
parameters: {
type: 'object',
properties: {
day: { type: 'string', description: 'Day name, like Monday' }
},
required: ['day']
}
}
]
});
messages.push(response.message);
if (!response.toolCalls || response.toolCalls.length === 0) {
return response.message.content;
}
for (const call of response.toolCalls) {
const tool = tools[call.name];
if (!tool) throw new Error(`Unknown tool: ${call.name}`);
const result = await tool(call.arguments);
messages.push({
role: 'tool',
toolCallId: call.id,
name: call.name,
content: JSON.stringify(result)
});
}
}
}Common wrong version
Beginners often call the model once, see a tool call, run the function, and print the raw result. That is not an agent loop.
The model needs the tool result back so it can explain, combine, retry, or answer the user in normal language.
Log every turn
Print the model message, tool call name, arguments, and tool result while developing. It makes bugs obvious.
If the agent gives a strange final answer, your logs show whether the schema was unclear, the arguments were wrong, or the tool returned poor data.
console.log('MODEL:', response.message);
console.log('TOOL CALLS:', response.toolCalls);
console.log('TOOL RESULT:', result);Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done