Documentation Index
Fetch the complete documentation index at: https://docs.celesto.ai/llms.txt
Use this file to discover all available pages before exploring further.
Tools give your agents the ability to interact with external systems, perform calculations, access APIs, and more. Agentor provides multiple ways to create and use custom tools.
Quick Start
Create a simple tool using the @function_tool decorator:
from agents import function_tool
from agentor import Agentor
@function_tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
# Your implementation here
return f"The weather in {city} is sunny and 72°F"
agent = Agentor(
name="Weather Agent",
model="gpt-5-mini",
tools=[get_weather]
)
result = agent.run("What's the weather in London?")
The simplest way to create tools is with decorated functions:
from agents import function_tool
@function_tool
def calculate_total(price: float, quantity: int, tax_rate: float = 0.1) -> str:
"""
Calculate total price including tax.
Args:
price: Unit price of the item
quantity: Number of items
tax_rate: Tax rate as decimal (default: 0.1 for 10%)
"""
subtotal = price * quantity
tax = subtotal * tax_rate
total = subtotal + tax
return f"Subtotal: ${subtotal:.2f}, Tax: ${tax:.2f}, Total: ${total:.2f}"
Key points:
- Function name becomes the tool name
- Docstring becomes the tool description (helps the LLM understand when to use it)
- Type hints are required for parameters
- Return type should be
str or JSON-serializable
For more complex tools with multiple capabilities:
from agentor.tools.base import BaseTool, capability
class CalculatorTool(BaseTool):
name = "calculator"
description = "Perform basic arithmetic operations"
@capability
def add(self, a: float, b: float) -> str:
"""
Add two numbers.
Args:
a: The first number
b: The second number
"""
return str(a + b)
@capability
def subtract(self, a: float, b: float) -> str:
"""
Subtract two numbers.
Args:
a: The first number
b: The second number
"""
return str(a - b)
@capability
def multiply(self, a: float, b: float) -> str:
"""
Multiply two numbers.
Args:
a: The first number
b: The second number
"""
return str(a * b)
@capability
def divide(self, a: float, b: float) -> str:
"""
Divide two numbers.
Args:
a: The first number
b: The divisor
"""
if b == 0:
return "Error: Division by zero"
return str(a / b)
# Use the tool
agent = Agentor(
name="Calculator Agent",
model="gpt-5-mini",
tools=[CalculatorTool()],
instructions="You are a precise math assistant. Always use the calculator tool."
)
result = agent.run("What is (37 * 12) - (144 / 3)?")
Create tools dynamically from any function:
from agentor.tools.base import BaseTool
def get_stock_price(symbol: str) -> str:
"""Get current stock price for a symbol."""
# Implementation here
return f"Stock price for {symbol}: $150.25"
tool = BaseTool.from_function(
get_stock_price,
name="stock_price",
description="Get real-time stock prices"
)
agent = Agentor(
name="Finance Agent",
model="gpt-5-mini",
tools=[tool]
)
Agentor comes with pre-built tools. Reference them by name:
agent = Agentor(
name="Assistant",
model="gpt-5-mini",
tools=["get_weather"] # Reference by string name
)
Available built-in tools:
get_weather - Weather information
calculator - Basic arithmetic
web_search - Internet search
- And more in the registry
import requests
from agents import function_tool
@function_tool
def search_github(query: str, limit: int = 5) -> str:
"""
Search GitHub repositories.
Args:
query: Search query
limit: Maximum number of results
"""
url = "https://api.github.com/search/repositories"
params = {"q": query, "per_page": limit}
response = requests.get(url, params=params)
if response.status_code != 200:
return f"Error: {response.status_code}"
repos = response.json()["items"]
results = []
for repo in repos:
results.append(f"{repo['full_name']}: {repo['description']} ({repo['stargazers_count']} stars)")
return "\n".join(results)
import sqlite3
from agentor.tools.base import BaseTool, capability
class DatabaseTool(BaseTool):
name = "database"
description = "Query and manage database"
def __init__(self, db_path: str):
super().__init__()
self.db_path = db_path
@capability
def query(self, sql: str) -> str:
"""
Execute a SELECT query.
Args:
sql: The SQL SELECT statement
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute(sql)
results = cursor.fetchall()
conn.close()
return str(results)
except Exception as e:
return f"Error: {str(e)}"
@capability
def insert(self, table: str, data: dict) -> str:
"""
Insert data into a table.
Args:
table: Table name
data: Dictionary of column:value pairs
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
columns = ", ".join(data.keys())
placeholders = ", ".join(["?" for _ in data])
sql = f"INSERT INTO {table} ({columns}) VALUES ({placeholders})"
cursor.execute(sql, list(data.values()))
conn.commit()
conn.close()
return "Success"
except Exception as e:
return f"Error: {str(e)}"
from agentor.tools.base import BaseTool, capability
import os
class FileOperationsTool(BaseTool):
name = "file_ops"
description = "Read and write files"
@capability
def read_file(self, path: str) -> str:
"""
Read contents of a file.
Args:
path: File path
"""
try:
with open(path, 'r') as f:
return f.read()
except Exception as e:
return f"Error reading file: {str(e)}"
@capability
def write_file(self, path: str, content: str) -> str:
"""
Write content to a file.
Args:
path: File path
content: Content to write
"""
try:
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as f:
f.write(content)
return f"Successfully wrote to {path}"
except Exception as e:
return f"Error writing file: {str(e)}"
@capability
def list_directory(self, path: str) -> str:
"""
List files in a directory.
Args:
path: Directory path
"""
try:
files = os.listdir(path)
return "\n".join(files)
except Exception as e:
return f"Error listing directory: {str(e)}"
Write Descriptive Docstrings
The LLM uses your docstrings to understand when to use the tool:
@function_tool
def send_email(to: str, subject: str, body: str) -> str:
"""
Send an email to a recipient.
Use this when the user wants to send an email or contact someone.
Args:
to: Recipient email address
subject: Email subject line
body: Email body content
"""
# Implementation
Type hints are required and help with validation:
from typing import List, Optional
@function_tool
def search_products(
query: str,
category: Optional[str] = None,
max_results: int = 10
) -> str:
"""Search for products."""
# Implementation
Always return error messages as strings:
@function_tool
def fetch_data(url: str) -> str:
"""Fetch data from a URL."""
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.text
except requests.RequestException as e:
return f"Error fetching data: {str(e)}"
Return formatted strings that are easy for the LLM to parse:
@function_tool
def get_user_info(user_id: str) -> str:
"""Get user information."""
user = fetch_user(user_id) # Your implementation
return f"""
Name: {user['name']}
Email: {user['email']}
Status: {user['status']}
Last Login: {user['last_login']}
"""
Add API Keys via Constructor
For tools that need credentials:
class APITool(BaseTool):
name = "api_tool"
description = "Access external API"
def __init__(self, api_key: str):
super().__init__(api_key=api_key)
@capability
def fetch(self, endpoint: str) -> str:
"""Fetch data from API endpoint."""
headers = {"Authorization": f"Bearer {self.api_key}"}
# Implementation
# Usage
tool = APITool(api_key=os.environ.get("API_KEY"))
agent = Agentor(name="Agent", model="gpt-5-mini", tools=[tool])
You can serve any BaseTool as an MCP server:
tool = CalculatorTool()
tool.serve(name="calculator-server", port=8000)
This makes your tool available to any MCP client. See Building MCP Servers for more details.
Next Steps