Tools

How to define external tool interfaces for your agents.

What is a Tool?

A tool represents an external capability that your agent can invoke. It defines:

  • What it does (description)
  • What input it expects (input schema)
  • What output it produces (output schema)

Important: The SDK only defines the tool’s interface contract. The platform provides the actual implementation.

Creating a Tool

from ainalyn import ToolBuilder
 
tool = (
    ToolBuilder("web-search")
    .description("Searches the web for information")
    .input_schema({
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "max_results": {"type": "integer", "default": 10}
        },
        "required": ["query"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "results": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "title": {"type": "string"},
                        "url": {"type": "string"},
                        "snippet": {"type": "string"}
                    }
                }
            }
        }
    })
    .build()
)

EIP Binding

Tools can be linked to external EIP (Execution Implementation Provider) services using .eip_binding():

from ainalyn import ToolBuilder
from ainalyn.domain.entities import EIPBinding
 
# Tool with OpenAI Whisper binding
speech_to_text = (
    ToolBuilder("speech-to-text")
    .description("Converts audio to text using OpenAI Whisper")
    .eip_binding(EIPBinding(provider="openai", service="whisper"))
    .input_schema({
        "type": "object",
        "properties": {
            "audio_url": {"type": "string", "format": "uri"},
            "language": {"type": "string", "default": "auto"}
        },
        "required": ["audio_url"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "text": {"type": "string"},
            "segments": {"type": "array"}
        }
    })
    .build()
)

When to use EIP binding:

  • When the tool uses an external service (OpenAI, Anthropic, etc.)
  • When Platform Core needs to know which service to invoke
  • For tools that require specific provider implementations

Common EIP providers:

  • openai - OpenAI services (whisper, gpt-4, dall-e, etc.)
  • anthropic - Anthropic services (claude, etc.)
  • platform - Platform-provided services

Using Tools in Workflows

Step 1: Define the tool

search_tool = (
    ToolBuilder("web-search")
    .description("Searches the web")
    .input_schema({...})
    .output_schema({...})
    .build()
)

Step 2: Add tool to agent

agent = (
    AgentBuilder("research-agent")
    .version("1.0.0")
    .add_tool(search_tool)  # Register tool
    .add_workflow(workflow)
    .build()
)

Step 3: Reference in node

from ainalyn import NodeBuilder
 
node = (
    NodeBuilder("search")
    .description("Search for information")
    .uses_tool("web-search")  # References the tool
    .inputs("query")
    .outputs("results")
    .build()
)

Common Tool Patterns

search = (
    ToolBuilder("web-search")
    .description("Searches the web for information")
    .input_schema({
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "language": {"type": "string", "default": "en"},
            "safe_search": {"type": "boolean", "default": True}
        },
        "required": ["query"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "results": {"type": "array", "items": {"type": "object"}},
            "total_count": {"type": "integer"}
        }
    })
    .build()
)

Database Query

db_query = (
    ToolBuilder("database-query")
    .description("Executes SQL queries on database")
    .input_schema({
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "parameters": {"type": "array"},
            "timeout": {"type": "integer", "default": 30}
        },
        "required": ["query"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "rows": {"type": "array"},
            "row_count": {"type": "integer"},
            "execution_time": {"type": "number"}
        }
    })
    .build()
)

File Operations

file_writer = (
    ToolBuilder("file-writer")
    .description("Writes content to files")
    .input_schema({
        "type": "object",
        "properties": {
            "path": {"type": "string"},
            "content": {"type": "string"},
            "encoding": {"type": "string", "default": "utf-8"},
            "append": {"type": "boolean", "default": False}
        },
        "required": ["path", "content"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "success": {"type": "boolean"},
            "bytes_written": {"type": "integer"},
            "file_path": {"type": "string"}
        }
    })
    .build()
)

Email Sender

email_sender = (
    ToolBuilder("email-sender")
    .description("Sends emails via SMTP")
    .input_schema({
        "type": "object",
        "properties": {
            "to": {"type": "array", "items": {"type": "string", "format": "email"}},
            "subject": {"type": "string"},
            "body": {"type": "string"},
            "attachments": {"type": "array", "items": {"type": "string"}}
        },
        "required": ["to", "subject", "body"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "sent": {"type": "boolean"},
            "message_id": {"type": "string"},
            "recipients": {"type": "array"}
        }
    })
    .build()
)

API Client

api_client = (
    ToolBuilder("rest-api-client")
    .description("Makes REST API calls")
    .input_schema({
        "type": "object",
        "properties": {
            "endpoint": {"type": "string", "format": "uri"},
            "method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE"]},
            "headers": {"type": "object"},
            "body": {"type": "object"}
        },
        "required": ["endpoint", "method"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "status_code": {"type": "integer"},
            "headers": {"type": "object"},
            "body": {"type": "object"}
        }
    })
    .build()
)

Tool Naming

Valid names:

"web-search"          # Lowercase with hyphens
"file-writer"         # Descriptive
"api-client-v2"       # With version

Invalid names:

"WebSearch"           # Must be lowercase
"file_writer"         # No underscores
"my tool"             # No spaces

Best Practices

1. Use descriptive schemas

# Clear input contract
input_schema = {
    "type": "object",
    "properties": {
        "search_query": {"type": "string"},
        "result_limit": {"type": "integer", "minimum": 1, "maximum": 100}
    },
    "required": ["search_query"]
}

2. Provide defaults for optional parameters

{
    "properties": {
        "timeout": {"type": "integer", "default": 30},
        "retry_count": {"type": "integer", "default": 3},
        "encoding": {"type": "string", "default": "utf-8"}
    }
}

3. Use appropriate constraints

{
    "properties": {
        "page_size": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 20
        },
        "email": {
            "type": "string",
            "format": "email"
        },
        "url": {
            "type": "string",
            "format": "uri"
        }
    }
}

4. Document expected behavior

# Clear description
ToolBuilder("cache-manager")
    .description("Manages in-memory cache with TTL support")

Tool vs Module vs Prompt

Use Tool when:

  • You need external services (APIs, databases, web search)
  • Platform provides the integration
  • Task involves I/O operations

Use Module when:

  • You need custom business logic
  • Task is computation or data processing
  • See Modules Guide

Use Prompt when:

  • You need LLM-based reasoning
  • Task involves text understanding/generation
  • See Prompts Guide

Complete Example

from ainalyn import (
    AgentBuilder,
    WorkflowBuilder,
    NodeBuilder,
    ToolBuilder,
    NodeType
)
 
# Define tool
search_tool = (
    ToolBuilder("web-search")
    .description("Searches the web for information")
    .input_schema({
        "type": "object",
        "properties": {
            "query": {"type": "string"},
            "max_results": {"type": "integer", "default": 10}
        },
        "required": ["query"]
    })
    .output_schema({
        "type": "object",
        "properties": {
            "results": {"type": "array"},
            "total_found": {"type": "integer"}
        }
    })
    .build()
)
 
# Use in workflow
workflow = (
    WorkflowBuilder("research")
    .entry_node("search")
    .add_node(
        NodeBuilder("search")
        .description("Search for research topic")
        .uses_tool("web-search")
        .inputs("query")
        .outputs("results")
        .build()
    )
    .build()
)
 
# Create agent
agent = (
    AgentBuilder("research-agent")
    .version("1.0.0")
    .description("Web research assistant")
    .add_tool(search_tool)
    .add_workflow(workflow)
    .build()
)

See Also