Skip to main content
Complete reference for the Laddr tool configuration schema.

Tool Definition

Laddr tools are Python functions decorated with @tool. Parameter schemas are automatically generated from function signatures, so you don’t need to manually define JSON schemas.

Basic Tool

from laddr import tool

@tool(
    name="weather_lookup",
    description="Fetches current weather for a given city"
)
def weather_lookup(city: str, units: str = "metric") -> dict:
    """Tool implementation."""
    # Parameter schema is auto-generated from function signature
    return {"status": "success", "data": result}

With Pydantic Model

For complex validation, use a Pydantic BaseModel as the first parameter:
from laddr import tool
from pydantic import BaseModel

class WeatherInput(BaseModel):
    city: str
    units: str = "metric"
    include_forecast: bool = False

@tool(
    name="weather_lookup",
    description="Fetches current weather for a given city"
)
def weather_lookup(inputs: WeatherInput) -> dict:
    """Tool implementation with Pydantic validation."""
    # Inputs are automatically validated via Pydantic
    return {"status": "success", "data": result}

Minimal Tool (Auto-inferred)

If you omit name and description, they’re inferred from the function:
@tool()
def web_search(query: str, max_results: int = 5) -> dict:
    """Search the web for information."""
    # Name: "web_search" (from function name)
    # Description: "Search the web for information." (from docstring)
    return {"status": "success", "results": [...]}

@tool Decorator Parameters

ParameterTypeRequiredDescription
namestrUnique tool identifier (auto-inferred from function name)
descriptionstrWhat the tool does (auto-inferred from docstring)
traceboolEnable tracing (default: True)
trace_masklist[str]Fields to redact in traces
Note: Parameter schemas are automatically generated from function signatures. You don’t need to manually define JSON schemas.

Parameter Descriptions

name

Rules:
  • Must be unique and descriptive
  • Use lowercase snake_case
  • Avoid generic names
  • If omitted, uses function name
Examples:
name="web_search"
name="calculate_area"
name="query_database"

description

Best Practices:
  • Begin with an action verb
  • Limit to 100 characters
  • Avoid redundant phrasing like “use this tool to…”
  • If omitted, uses first line of docstring
Examples:
description="Scrape text content from a webpage"
description="Translate text from English to French"

trace

Enables or disables trace logging. Example:
trace=True  # Default - all tool calls are traced
trace=False  # Disable tracing for sensitive operations
Set to False when:
  • Handling sensitive user data
  • Reducing log volume for high-frequency tools

trace_mask

Redacts specified fields in traces. Example:
trace_mask=["api_key", "token", "password"]
Fields matching these keys will appear as ***REDACTED*** in logs.

Automatic Schema Generation

Parameter schemas are automatically generated from Python function signatures. The system maps Python types to JSON Schema types:
Python TypeJSON Schema TypeExample
strstringquery: str
intintegerlimit: int
floatnumberprice: float
boolbooleanenabled: bool
list[T]arrayitems: list[str]
dictobjectconfig: dict
Optional[T]Type with nulltimeout: int | None
BaseModelobject (validated)inputs: MyModel

Type Hints Examples

# String parameter
def search(query: str) -> dict:
    ...

# Integer with default
def fetch(limit: int = 10) -> dict:
    ...

# Optional parameter
def process(timeout: int | None = None) -> dict:
    ...

# List parameter
def batch_process(items: list[str]) -> dict:
    ...

# Dict parameter
def configure(config: dict) -> dict:
    ...

# Complex nested (use Pydantic)
from pydantic import BaseModel

class Config(BaseModel):
    host: str
    port: int = 8080
    ssl: bool = False

def setup(inputs: Config) -> dict:
    ...

Supported Type Annotations

  • Basic types: str, int, float, bool
  • Collections: list[T], dict, tuple
  • Optional: Optional[T] or T | None
  • Union: str | int (maps to first type)
  • Pydantic Models: Full validation support
Note: Type annotations are optional but recommended for better schema generation.

Complete Examples

Example 1: Basic Tool

from laddr import tool

@tool(
    name="weather_lookup",
    description="Fetches current weather for a given city"
)
def weather_lookup(city: str, units: str = "metric") -> dict:
    """Get weather for a city."""
    try:
        result = get_weather(city, units)
        return {"status": "success", "data": result}
    except Exception as e:
        return {"status": "error", "error": str(e)}
Generated Schema:
{
  "type": "object",
  "properties": {
    "city": {"type": "string"},
    "units": {"type": "string", "default": "metric"}
  },
  "required": ["city"]
}

Example 2: With Pydantic Validation

from laddr import tool
from pydantic import BaseModel, Field

class WeatherInput(BaseModel):
    city: str = Field(..., description="City name", min_length=1)
    units: str = Field("metric", description="Temperature units", pattern="^(metric|imperial)$")
    include_forecast: bool = Field(False, description="Include 5-day forecast")

@tool(
    name="weather_lookup",
    description="Fetches current weather for a given city"
)
def weather_lookup(inputs: WeatherInput) -> dict:
    """Get weather for a city with validation."""
    try:
        result = get_weather(inputs.city, inputs.units, inputs.include_forecast)
        return {"status": "success", "data": result}
    except Exception as e:
        return {"status": "error", "error": str(e)}

Example 3: API Wrapper Pattern

from laddr import tool
import requests
import os

@tool(
    name="api_call",
    description="Perform a GET request to external API",
    trace_mask=["api_key"]
)
def api_call(endpoint: str, api_key: str | None = None) -> dict:
    """Call external API."""
    key = api_key or os.getenv("API_KEY")
    response = requests.get(
        f"https://api.example.com/{endpoint}",
        headers={"Authorization": f"Bearer {key}"},
        timeout=10
    )
    return {"status": "success", "data": response.json()}

Example 4: Data Transformer

from laddr import tool
import json

@tool(
    name="convert_format",
    description="Convert data between formats"
)
def convert_format(data: str, to_format: str = "json") -> dict:
    """Convert data between formats."""
    if to_format == "json":
        return {"status": "success", "result": json.loads(data)}
    elif to_format == "csv":
        return {"status": "success", "result": parse_csv(data)}
    else:
        return {"status": "error", "error": f"Unsupported format {to_format}"}

Example 5: File Operations

from laddr import tool
import glob

@tool(
    name="list_files",
    description="List files by pattern"
)
def list_files(directory: str, pattern: str = "*") -> dict:
    """List files matching pattern."""
    files = glob.glob(f"{directory}/{pattern}")
    return {"status": "success", "files": files, "count": len(files)}

Return Format

Tools should return dictionaries with a consistent format:
# Success
return {
    "status": "success",
    "data": {...}
}

# Error
return {
    "status": "error",
    "error": "Error message"
}
Status Values:
  • "success" - Tool executed successfully
  • "error" - Tool execution failed

Registering Tools with Agents

Tools must be registered with agents. There are several ways to do this:

Method 1: Direct Registration

from laddr import Agent
from tools.web_tools import web_search
from tools.math_tools import calculate

agent = Agent(
    name="researcher",
    tools=[web_search, calculate]
)

Method 2: Auto-Discovery

Tools are automatically discovered from agents.<agent_name>.tools package:
agents/
  researcher/
    tools/
      __init__.py
      web_search.py
      calculate.py
The agent automatically loads all @tool decorated functions from this package.

Method 3: Using bind_tools

from laddr.core.tooling import bind_tools
from agents.researcher.tools import web_search

class ResearcherAgent(Agent):
    def __init__(self):
        super().__init__(name="researcher")
        bind_tools(self, [web_search, "summarize"])  # String names auto-import

Tool Registry

Tools are managed through a ToolRegistry that supports:
  • Registration: Add tools with optional aliases
  • Lookup: Find tools by name or alias
  • Listing: Get all available tools
  • Validation: Automatic input validation via Pydantic
from laddr.core.tooling import ToolRegistry

registry = ToolRegistry()
registry.register(web_search, aliases=["search", "web"])
tool = registry.get("web_search")  # or "search" or "web"

Testing Tools

Manual Testing (Python)

from tools.web_tools import web_search

result = web_search(query="AI trends", max_results=3)
print(result)

Testing via API

curl -X GET "http://localhost:8000/api/agents/researcher/tools"
Returns all tools with their schemas:
{
  "agent": "researcher",
  "tools": [
    {
      "name": "web_search",
      "description": "Search the web for information",
      "parameters": {
        "type": "object",
        "properties": {
          "query": {"type": "string"},
          "max_results": {"type": "integer", "default": 5}
        },
        "required": ["query"]
      }
    }
  ]
}

Best Practices

  1. Use Type Hints: Always annotate function parameters for better schema generation
  2. Descriptive Names: Use clear, action-oriented tool names (web_search not search)
  3. Error Handling: Always return consistent error format
  4. Sensitive Data: Use trace_mask for API keys, tokens, passwords
  5. Pydantic for Complex: Use Pydantic models for complex validation needs
  6. Documentation: Write clear docstrings (used as descriptions if not provided)

Common Patterns

Pattern: API Wrapper

@tool(name="api_call", description="Call external API")
def api_call(endpoint: str, method: str = "GET") -> dict:
    # Wraps external API calls

Pattern: Data Transformer

@tool(name="transform", description="Transform data format")
def transform(data: str, format: str) -> dict:
    # Converts between data formats

Pattern: File Operations

@tool(name="file_op", description="Perform file operation")
def file_op(path: str, operation: str) -> dict:
    # File system operations

Next Steps