Appearance
Tool Calling
Extend AI capabilities with built-in and custom tools through an agentic loop.
Overview
Tool calling allows the AI to:
- Execute functions and workflows
- Search knowledge bases (RAG)
- Browse web pages
- Execute SQL queries
- Interact with browser sessions
- Send emails and notifications
- Access external APIs
Agentic Loop
The chat system uses an agentic loop for tool calling:
User Message
│
▼
┌─────────────────────────────┐
│ Agentic Loop │
│ (max 8 iterations) │
│ │
│ For each iteration: │
│ 1. Send "thinking" event │
│ 2. Call LLM with tools │
│ 3. Parse tool calls │
│ 4. If no tools → respond │
│ 5. Execute each tool │
│ 6. Add results to context │
│ 7. Next iteration │
└─────────────────────────────┘
│
▼
Final ResponseKey Features
- Maximum 8 iterations: Prevents runaway loops
- Loop detection: Stops repeated identical tool calls
- Parallel execution: Multiple tools can run concurrently
- Result truncation: Large results are trimmed to save context
- Error handling: Failed tools report errors, loop continues
Built-in Tools
search_knowledge
Search the knowledge base for relevant information.
json
{
"name": "search_knowledge",
"arguments": {
"query": "React hooks tutorial"
}
}browse_url
Fetch and read content from a URL.
json
{
"name": "browse_url",
"arguments": {
"url": "https://example.com/article"
}
}browser_action
Execute actions in a browser session.
json
{
"name": "browser_action",
"arguments": {
"sessionId": "session-123",
"action": "click",
"selector": "#submit-button"
}
}analyze_page
Analyze the current browser page content.
json
{
"name": "analyze_page",
"arguments": {
"sessionId": "session-123"
}
}execute_sql
Execute a SQL query against the database.
json
{
"name": "execute_sql",
"arguments": {
"query": "SELECT * FROM users WHERE status = 'active'"
}
}execute_workflow
Run a workflow and return results.
json
{
"name": "execute_workflow",
"arguments": {
"workflowId": "wf-123",
"input": {"email": "[email protected]"}
}
}send_email
Send an email message.
json
{
"name": "send_email",
"arguments": {
"to": "[email protected]",
"subject": "Hello",
"body": "Message content"
}
}get_schedule_info
Get information about scheduled tasks.
json
{
"name": "get_schedule_info",
"arguments": {
"scheduleId": "sched-123"
}
}create_schedule
Create a new scheduled task.
json
{
"name": "create_schedule",
"arguments": {
"name": "Daily Report",
"cron": "0 9 * * *",
"workflowId": "wf-123"
}
}Tool Message Format
Tool Call (from AI)
json
{
"role": "assistant",
"content": null,
"toolCalls": [
{
"id": "tc_abc123",
"name": "search_knowledge",
"arguments": {"query": "React tutorials"}
}
]
}Tool Result (from system)
json
{
"role": "tool",
"toolCallId": "tc_abc123",
"content": "{\"results\": [...]}"
}Streaming Tool Events
During streaming, tool execution emits SSE events:
tool_call Event
Sent when a tool is being called:
event: message
data: {"type": "tool_call", "id": "tc_abc123", "name": "search_knowledge", "arguments": {"query": "React"}}tool_result Event
Sent when tool execution completes:
event: message
data: {"type": "tool_result", "toolCallId": "tc_abc123", "name": "search_knowledge", "success": true, "result": [...], "resultPreview": "Found 5 results"}For errors:
event: message
data: {"type": "tool_result", "toolCallId": "tc_abc123", "success": false, "error": "Search failed"}Loop Detection
The system prevents infinite loops by:
- Tracking recent calls: Last 10 tool calls are remembered
- Argument comparison: Detects same tool with same arguments
- Maximum repeats: Same call allowed maximum 2 times
- Force exit: Loop terminates after 8 iterations regardless
Enabling Tools
Via API Request
json
{
"content": "Search for React tutorials",
"enableTools": true
}Via Agent Settings
Configure in agent settings:
json
{
"tools_enabled": true,
"enabled_tools": ["search_knowledge", "browse_url", "execute_sql"]
}Via Chat Interface
Toggle the "Tools" switch in the chat settings panel.
Custom Tools via MCP
Add custom tools using MCP (Model Context Protocol) servers:
json
{
"type": "mcp",
"config": {
"server_id": "my-mcp-server",
"tool_name": "custom_search"
}
}See MCP Servers for configuration details.
OpenAPI Auto-Import
Import all endpoints from an OpenAPI 3.x JSON spec as callable HTTP tools, grouped under a tool cluster.
Importing via UI
- Go to Tools page
- Click Import OpenAPI
- Enter the spec URL (e.g.
https://api.example.com/openapi.json) - Optionally set a cluster name (defaults to the spec's
info.title) - All paths and operations become individual HTTP tools
Importing via API
bash
POST /api/agents/{id}/tools/import-openapi
Content-Type: application/json
{
"url": "https://api.example.com/openapi.json",
"cluster": "my_api"
}Returns the list of created tools.
Agent Self-Provisioning
The agent can import APIs during conversation using the built-in import_openapi_tools tool:
User: "I need to work with the Petstore API"
Agent: [calls import_openapi_tools]
url: "https://petstore.swagger.io/v2/swagger.json"
cluster: "petstore"
Agent: "I've imported 20 Petstore API endpoints. What would you like to do?"
User: "Look up pet #42"
Agent: [calls call_custom_tool]
toolName: "getPetById"
arguments: { "id": 42 }The agent can also remove imported APIs with delete_tool_cluster.
Tool Clusters
Imported tools are grouped by cluster name. On the Tools page, clusters appear as collapsible sections:
▼ Petstore API (3 tools)
GET /pets - List all pets
GET /pets/{petId} - Get pet by ID
POST /pets - Create a pet
▼ Ungrouped (2 tools)
my_webhook_tool
my_js_functionEach cluster can be deleted as a group, removing all tools in the cluster at once.
How Imported Tools Execute
Imported HTTP tools use baseUrl + pathTemplate from the OpenAPI spec:
- Path parameters are substituted:
/pets/{petId}becomes/pets/42 - Query parameters are appended for GET requests
- GET/HEAD requests don't send a body
- POST/PUT/PATCH requests send non-path arguments as JSON body
Trigger Keywords
The custom tools category (including OpenAPI import) activates when messages contain: openapi, import api, api spec, swagger, custom tool, mcp, tool call
Tool Schema
Define tools with JSON Schema parameters:
json
{
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or coordinates"
},
"units": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"default": "celsius"
}
},
"required": ["location"]
}
}Result Handling
Truncation
Large results are automatically truncated:
- Results over 10,000 characters are truncated
- Base64 images are replaced with placeholders
- Preview text is generated for UI display
Screenshot Results
Browser tools that return screenshots:
- Full image stored in R2
- Placeholder added to context:
[image displayed above] - URL provided for display in UI
Best Practices
1. Clear Tool Descriptions
Write descriptive tool descriptions:
json
{
"description": "Search the product catalog by name, category, or price range. Returns up to 10 matching products with name, price, and availability."
}2. Validate Parameters
Define required fields and types:
json
{
"parameters": {
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "Customer email address"
}
},
"required": ["email"]
}
}3. Handle Errors Gracefully
Return clear error messages:
json
{
"error": "Product not found",
"code": "NOT_FOUND",
"suggestion": "Try searching with a different query"
}4. Limit Tool Count
Only enable needed tools:
- Reduces model confusion
- Faster response times
- Lower token costs
- Better focused responses
5. Monitor Tool Usage
Track tool metrics:
- Call frequency
- Success/failure rates
- Response times
- Token usage per tool
Code Mode
Code Mode allows the LLM to write JavaScript code instead of making structured tool calls. This is more efficient for complex, multi-step tasks.
Why Code Mode?
Traditional tool calling requires one LLM round-trip per tool call. With Code Mode:
- Fewer API calls - Multiple tool calls in one code block
- Better orchestration - Use JavaScript for loops, conditionals, error handling
- More natural - LLM can express complex logic as code
- Cost savings - Reduced token usage and latency
Code Mode Options
Configure in Settings → Prompts → Code Mode:
| Mode | Description | Token Impact |
|---|---|---|
| Off | Traditional tool calling only | Baseline |
| Selective | Tools as TypeScript hints (~2,400 tokens) | -77% vs Full |
| Full | Complete TypeScript API (~10,700 tokens) | +8x vs Selective |
How It Works
When Code Mode is enabled, the LLM can respond with JavaScript code blocks:
javascript
// Example: Browse a site and take action
const page = await tools.browseUrl({ url: "https://example.com" });
const analysis = await tools.analyzePage({
sessionId: page.sessionId,
task: "find login button"
});
await tools.browserAction({
sessionId: page.sessionId,
action: "click",
selector: analysis.selector
});Available Functions
The tools object exposes all agent tools as async functions:
typescript
// Memory
await tools.remember({ key: "user_preference", value: "dark mode" });
await tools.recall({ key: "user_preference" });
// Browser
await tools.browseUrl({ url: "https://...", task: "..." });
await tools.browserAction({ action: "click", selector: "#btn" });
// Knowledge
await tools.searchKnowledge({ query: "..." });
// Workflows
await tools.executeWorkflow({ workflowId: "...", inputs: {} });
// Messaging
await tools.sendMessage({ gateway: "telegram", recipient: "...", message: "..." });
// And more...Code Execution Sandbox
Code runs in a secure sandbox with:
- Limited scope (only
toolsandconsoleavailable) - No access to
fetch, globals, or environment - Async execution with timeout limits
- Captured logs and tool call history
Selective Tool Loading
By default, all 30+ tools are included in every prompt, consuming ~10,000 tokens. Selective loading dramatically reduces this.
How It Works
Tools are loaded based on message triggers:
User: "Search for React tutorials"
→ Loads: search_knowledge, browse_url
User: "Send a message to John on Telegram"
→ Loads: send_message, list_gateways, get_contact
User: "Run my daily report workflow"
→ Loads: execute_workflow, list_workflows, get_workflow_statusTrigger Keywords
| Tool Category | Trigger Keywords |
|---|---|
| Browser | browse, visit, go to, navigate, click, page, website |
| Memory | remember, recall, forget, memory, preference |
| Knowledge | search, find, knowledge, document, vector |
| Workflows | workflow, run, execute, trigger, automate |
| Messaging | send, message, email, telegram, notify |
| Calendar | calendar, schedule, event, reminder, task |
| SQL | query, database, sql, select, table |
| Custom / OpenAPI | custom tool, mcp, tool call, openapi, import api, swagger |
Token Savings
| Configuration | Approximate Tokens |
|---|---|
| All tools | ~10,700 |
| Selective (typical) | ~2,400 |
| Minimal context | ~800 |
Configuration
Enable selective loading in Settings → Prompts:
json
{
"codeMode": "selective",
"toolLoadingMode": "context-aware"
}Example: Multi-Tool Interaction
User: "Find React tutorials and summarize the best one"
The AI will:
Iteration 1: Call
search_knowledgejson{"name": "search_knowledge", "arguments": {"query": "React tutorials"}}Result: Returns list of tutorials
Iteration 2: Call
browse_urlfor top resultjson{"name": "browse_url", "arguments": {"url": "https://example.com/react-guide"}}Result: Returns page content
Final Response: AI synthesizes information and returns summary
API Reference
Get Available Tools
bash
GET /api/agents/{id}/chat/toolsResponse:
json
{
"tools": [
{
"name": "search_knowledge",
"description": "Search the knowledge base",
"parameters": {...}
},
...
]
}See Tools API for complete endpoint documentation.
