# Guide: tool calling
ARES supports tool calling, also known as function calling. It lets agents use external tools during a conversation. When an agent needs to run a calculation, search the web, or interact with an external system, the agent requests a tool call. ARES executes the tool and feeds the result back to the agent. The agent then puts the result into its response.
---
## How it works
Tool calling in ARES follows a multi-turn loop managed by the ToolCoordinator:
```
User message
|
v
Agent (LLM) generates response
|
├── If response is final text → return to user
|
└── If response contains tool_calls →
|
v
ARES executes each tool
|
v
Results sent back to agent
|
v
Agent generates next response (may call more tools or return final text)
```
The loop continues until the agent produces a final text response or reaches the maximum iteration limit. The process is transparent to the caller: you send one chat message and receive one complete response.
---
## Built-in tools
ARES ships with two built-in tools:
### calculator
The tool evaluates mathematical expressions and returns the result.
**Capabilities:**
- Basic arithmetic: `+`, `-`, `*`, `/`
- Exponents: `^` or `**`
- Parentheses for grouping
- Common functions: `sqrt`, `sin`, `cos`, `log`, `ln`, `abs`
- Constants: `pi`, `e`
**Example tool call from agent:**
```json
{
"name": "calculator",
"arguments": {
"expression": "50000 * (1.15 ^ 10)"
}
}
```
**Result returned to agent:**
```json
{
"result": 202278.25
}
```
### web_search
The tool searches the web and returns relevant results.
**Example tool call from agent:**
```json
{
"name": "web_search",
"arguments": {
"query": "current US federal interest rate 2026"
}
}
```
**Result returned to agent:**
```json
{
"results": [
{
"title": "Federal Reserve holds rate at 4.25%",
"url": "https://...",
"snippet": "The Federal Reserve maintained its benchmark rate..."
}
]
}
```
---
## Configuring tool access
### Per-Agent tool filtering
Each agent specifies its usable tools. An agent without configured tools cannot make tool calls, even when the underlying model supports them.
**In ares.toml:**
```toml
[[agents]]
name = "research-assistant"
model = "llama-3.3-70b"
system_prompt = "You are a research assistant with access to web search and calculation tools."
tools = ["calculator", "web_search"]
[[agents]]
name = "math-tutor"
model = "llama-3.3-70b"
system_prompt = "You are a math tutor. Use the calculator to verify your work."
tools = ["calculator"]
[[agents]]
name = "simple-chat"
model = "llama-3.3-70b"
system_prompt = "You are a conversational assistant."
tools = []
```
**Via the API:**
```bash
curl -X POST http://localhost:3000/api/admin/tenants/{id}/agents \
-H "X-Admin-Secret: your-admin-secret" \
-H "Content-Type: application/json" \
-d '{
"name": "analyst",
"agent_type": "analyst",
"config": {
"model": "llama-3.3-70b",
"system_prompt": "You are a data analyst.",
"tools": ["calculator", "web_search"],
"max_tokens": 4096
}
}'
```
---
## ToolCoordinator
The ToolCoordinator is the internal component that manages the tool-calling loop. It handles:
- **Multi-turn orchestration:** it sends tool results back to the model and processes follow-up tool calls
- **Parallel execution:** when the model requests multiple tools in one turn, they run concurrently
- **Timeout enforcement:** each tool call runs within a configurable timeout
- **Iteration limits:** they prevent infinite tool-calling loops
### Configuration
You configure the tool-calling behavior at the server level:
| `max_iterations` | `10` | Maximum tool-calling rounds before forcing a text response |
| `parallel_execution` | `true` | Runs multiple tool calls concurrently within one turn |
| `tool_timeout` | `30s` | Maximum time for a single tool execution |
When an agent hits the iteration limit, ARES instructs the model to produce a final response from the information gathered so far.
---
## Provider compatibility
Tool calling needs model support. Not all providers and models support function calling:
| Groq | llama-3.3-70b, llama-3.1-8b | Supported |
| Anthropic | claude-3.5-sonnet | Supported |
| NVIDIA | deepseek-r1 | Not supported |
| Ollama | Varies by model | Model-dependent |
If you assign tools to an agent with a model that does not support tool calling, ARES ignores the tools. The agent then responds with text only.
---
## Example: conversation with tool calls
This section shows what happens internally when a user asks a question that needs a tool.
**User sends:**
```bash
curl -X POST http://localhost:3000/v1/chat \
-H "Authorization: Bearer ares_xxx" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "What is the monthly payment on a $400,000 mortgage at 6.5% for 30 years?"}
],
"agent_type": "financial-analyst"
}'
```
**Internal flow:**
1. ARES sends the message to the LLM together with the calculator tool definition
2. The LLM responds with a tool call:
```json
{
"tool_calls": [{
"name": "calculator",
"arguments": {"expression": "(400000 * (0.065/12) * (1 + 0.065/12)^360) / ((1 + 0.065/12)^360 - 1)"}
}]
}
```
3. ARES runs the calculator and gets `2528.27`
4. ARES sends the result back to the LLM
5. The LLM puts the calculated value into a final text response
**User receives:**
```json
{
"content": "The monthly payment on a $400,000 mortgage at 6.5% APR over 30 years would be **$2,528.27**.\n\nThis is calculated using the standard amortization formula...",
"model": "llama-3.3-70b",
"tokens_used": 412
}
```
The tool-calling steps are invisible to the caller. You send one question and receive one complete answer.
---
## Example: multiple tool calls in one turn
Models can request multiple tools at the same time. For example, a research agent with the question "Compare the population of Tokyo and New York" can request two web searches in parallel:
```json
{
"tool_calls": [
{"name": "web_search", "arguments": {"query": "Tokyo population 2026"}},
{"name": "web_search", "arguments": {"query": "New York population 2026"}}
]
}
```
With `parallel_execution` enabled (the default), the two searches run concurrently. ARES sends both results back to the model together. The model then produces a response that compares the two cities.
---
## Example: Multi-Turn tool usage
Some questions need multiple rounds of tool use. For example:
**User:** "What is 15% of the GDP of France?"
**Turn 1, Agent calls web_search:**
```json
{"name": "web_search", "arguments": {"query": "France GDP 2026 USD"}}
```
Result: France's GDP is approximately $3.1 trillion.
**Turn 2, Agent calls calculator:**
```json
{"name": "calculator", "arguments": {"expression": "3100000000000 * 0.15"}}
```
Result: 465,000,000,000
**Turn 3, Agent produces final response:**
"15% of France's GDP (approximately $3.1 trillion) is **$465 billion**."
Each round counts toward the `max_iterations` limit.
---
## Error handling
When a tool call fails (timeout, invalid input), ARES returns an error result to the model:
```json
{
"tool_result": {
"name": "web_search",
"error": "Search timed out after 30 seconds"
}
}
```
The model can then:
- retry the tool call with different parameters
- use a different tool
- respond from its own knowledge and note the tool failure
A good system prompt tells the agent how to handle tool failures gracefully.