Skip to content

AI-Parrot Tools Documentation

Complete reference guide for all available tools in the AI-parrot library.


Core Mathematical Tools

MathTool

Description: Performs basic arithmetic operations including addition, subtraction, multiplication, division, and square root calculations.

Usage:

from parrot.tools.math import MathTool

tool = MathTool()
result = await tool.execute(
    a=10.0,
    operation="add",
    b=5.0
)

Example:

# Addition
result = await math_tool.execute(a=25, operation="add", b=15)
# Returns: {"operation": "add", "operands": [25, 15], "result": 40, "expression": "25 + 15 = 40"}

# Square root
result = await math_tool.execute(a=144, operation="sqrt")
# Returns: {"operation": "sqrt", "operands": [144], "result": 12.0, "expression": "sqrt(144) = 12.0"}

# Division
result = await math_tool.execute(a=100, operation="divide", b=4)
# Returns: {"operation": "divide", "operands": [100, 4], "result": 25.0, "expression": "100 / 4 = 25.0"}

Supported Operations: - add, addition, +, plus, sum - subtract, subtraction, -, minus, difference - multiply, multiplication, *, times, ×, product - divide, division, /, ÷, quotient - sqrt, square_root, square root


Weather & Environment Tools

OpenWeatherTool

Description: Retrieves current weather conditions and forecasts for any location using the OpenWeatherMap API. Supports multiple temperature units and provides comprehensive weather data.

Usage:

from parrot.tools.openweather import OpenWeatherTool

tool = OpenWeatherTool(
    api_key="your_api_key",
    default_units='imperial',
    default_country='us',
    timeout=10
)

weather = await tool.execute(
    latitude=40.7128,
    longitude=-74.0060,
    request_type='weather',
    units='imperial',
    country='us'
)

Example:

# Get current weather for New York City
weather_tool = OpenWeatherTool(api_key="your_key")

current_weather = await weather_tool.execute(
    latitude=40.7128,
    longitude=-74.0060,
    request_type='weather',
    units='imperial'
)

# Get 5-day forecast
forecast = await weather_tool.execute(
    latitude=40.7128,
    longitude=-74.0060,
    request_type='forecast',
    units='metric',
    forecast_days=5
)

Parameters: - latitude: Latitude coordinate (-90.0 to 90.0) - longitude: Longitude coordinate (-180.0 to 180.0) - request_type: 'weather' (current) or 'forecast' (future predictions) - units: 'metric' (Celsius), 'imperial' (Fahrenheit), or 'standard' (Kelvin) - country: Two-letter ISO 3166 country code (default: 'us') - forecast_days: Number of days for forecast (1-16, only for 'forecast' type)


Database Tools

DatabaseTool

Description: Unified database tool that handles the complete database interaction pipeline including schema discovery, query generation from natural language, query validation, and safe execution across multiple database types.

Usage:

from parrot.tools.db import DatabaseTool

tool = DatabaseTool(
    knowledge_store=vector_store,
    default_connection_params={
        DatabaseFlavor.POSTGRESQL: {
            "host": "localhost",
            "port": 5432,
            "database": "mydb",
            "user": "user",
            "password": "pass"
        }
    }
)

result = await tool.execute(
    natural_language_query="Show me all users who registered in the last 30 days",
    database_flavor="postgresql",
    operation="full_pipeline"
)

Example:

# Full pipeline: natural language to execution
db_tool = DatabaseTool(knowledge_store=my_vector_store)

result = await db_tool.execute(
    natural_language_query="What are the top 10 selling products by revenue?",
    database_flavor="postgresql",
    connection_params={
        "host": "localhost",
        "database": "sales_db"
    },
    operation="full_pipeline",
    max_rows=10
)

# Schema extraction only
schema_info = await db_tool.execute(
    database_flavor="postgresql",
    connection_params=connection_params,
    schema_names=["public", "analytics"],
    operation="schema_extract"
)

# Direct SQL execution
sql_result = await db_tool.execute(
    sql_query="SELECT * FROM users WHERE active = true",
    database_flavor="postgresql",
    operation="query_execute",
    max_rows=100
)

Supported Operations: - schema_extract: Extract and cache table schemas - query_generate: Convert natural language to SQL - query_validate: Syntax and security validation - query_execute: Safe query execution - full_pipeline: Complete end-to-end workflow

Supported Databases: - PostgreSQL - MySQL - SQLite - Microsoft SQL Server - Oracle


Web Scraping & Browser Automation

WebScrapingTool

Description: Advanced web scraping and browser automation tool with support for both Selenium and Playwright. Provides step-by-step navigation, flexible content extraction, and comprehensive browser control.

Usage:

from parrot.tools.scraping import WebScrapingTool

tool = WebScrapingTool(
    browser='chrome',
    driver_type='selenium',
    headless=True,
    mobile=False,
    default_timeout=10
)

result = await tool.execute(
    steps=[
        {"action": "navigate", "url": "https://example.com"},
        {"action": "click", "selector": "#login-button"},
        {"action": "fill", "selector": "#username", "value": "user@example.com"},
        {"action": "wait", "condition": "element_visible", "selector": ".dashboard"}
    ],
    selectors=[
        {"name": "title", "selector": "h1.page-title", "extract_type": "text"},
        {"name": "prices", "selector": ".product-price", "extract_type": "text", "multiple": True}
    ]
)

Example:

# Basic page scraping
scraper = WebScrapingTool(browser='chrome', headless=True)

result = await scraper.execute(
    steps=[
        {
            "action": "navigate",
            "url": "https://news.ycombinator.com",
            "description": "Go to Hacker News"
        },
        {
            "action": "wait",
            "condition": "element_visible",
            "selector": ".titleline",
            "timeout": 5
        }
    ],
    selectors=[
        {
            "name": "story_titles",
            "selector": ".titleline > a",
            "extract_type": "text",
            "multiple": True
        },
        {
            "name": "story_links",
            "selector": ".titleline > a",
            "extract_type": "attribute",
            "attribute": "href",
            "multiple": True
        }
    ]
)

# Form interaction with authentication
login_result = await scraper.execute(
    steps=[
        {"action": "navigate", "url": "https://example.com/login"},
        {"action": "fill", "selector": "#email", "value": "user@example.com"},
        {"action": "fill", "selector": "#password", "value": "secret"},
        {"action": "click", "selector": "button[type='submit']"},
        {"action": "wait", "condition": "url_contains", "value": "/dashboard"}
    ]
)

# Mobile device emulation
mobile_scraper = WebScrapingTool(
    browser='chrome',
    mobile=True,
    mobile_device='iPhone 14 Pro Max'
)

LLM-friendly JSON flow schema: Each step should be a small, explicit JSON object. Include: - action: What to do (navigate, authenticate, wait, click, etc.). - description: A short explanation to keep flows readable when scanned by humans or LLMs. - selector plus selector_type: Declare whether you are using css, xpath, or text for element targeting. - condition plus condition_type: For waits, define whether you expect an exact URL (url_is), substring (url_contains), element check (selector), or a simple timed pause (simple). - timeout/duration: Declare timings so headless runs stay deterministic.

Complex flow example (login + filtering):

steps = [
    {
        "action": "navigate",
        "url": "https://manage.dispatch.me/login",
        "description": "Open Dispatch login page"
    },
    {
        "action": "authenticate",
        "method": "form",
        "username_selector": "input[name='email']",
        "username": config.get('DISPATCHME_USERNAME'),
        "enter_on_username": True,
        "password_selector": "input[name='password']",
        "password": config.get('DISPATCHME_PASSWORD'),
        "submit_selector": "button[type='submit']",
        "description": "Fill and submit login form"
    },
    {
        "action": "wait",
        "timeout": 5,
        "condition_type": "url_is",
        "condition": "https://manage.dispatch.me/providers/list",
        "description": "Confirm redirect to providers list"
    },
    {
        "action": "navigate",
        "url": "https://manage.dispatch.me/recruit/out-of-network/list",
        "description": "Open recruiters page"
    },
    {
        "action": "click",
        "selector": "//button[contains(., 'Filtering On')]",
        "selector_type": "xpath",
        "description": "Open Filters panel"
    },
    {
        "action": "wait",
        "timeout": 2,
        "condition_type": "simple",
        "description": "Short pause for UI to settle"
    },
    {
        "action": "click",
        "selector": "//button[contains(., 'Filters')]",
        "selector_type": "xpath",
        "description": "Re-open filter options"
    },
]
result = await scraper.execute(steps=steps)

Supported Actions: - Navigation: navigate, back, refresh - Interaction: click, fill, press_key, scroll - Data Extraction: get_text, get_html, get_cookies, screenshot - Authentication: authenticate, set_cookies - File Operations: upload_file, wait_for_download - Waiting: wait, await_human, await_keypress, await_browser_event - Advanced: evaluate (JavaScript), loop (iterations)

Supported Browsers: - Chrome (default) - Firefox - Edge - Safari - Undetected Chrome (anti-detection)


Agent Tools

AgentTool

Description: Wraps any BasicAgent or AbstractBot as a tool, allowing agents to be used as tools by other agents in a multi-agent orchestration system.

Usage:

from parrot.tools.agent import AgentTool
from parrot.bots.agent import BasicAgent

# Create a specialized agent
research_agent = BasicAgent(
    name="ResearchAgent",
    role="Research Specialist",
    goal="Find and synthesize information"
)

# Wrap it as a tool
research_tool = AgentTool(
    agent=research_agent,
    name="research_tool",
    description="Use this tool to perform in-depth research on any topic"
)

# Use in another agent
orchestrator.register_tool(research_tool)

Example:

# Create specialized agents as tools
code_agent = BasicAgent(
    name="CodeExpert",
    role="Software Engineer",
    tools=["DatabaseTool", "WebScrapingTool"]
)

writer_agent = BasicAgent(
    name="ContentWriter",
    role="Technical Writer",
    goal="Create clear documentation"
)

# Convert to tools
code_tool = AgentTool(agent=code_agent, name="coding_expert")
writer_tool = AgentTool(agent=writer_agent, name="writing_expert")

# Orchestrator uses both
orchestrator = BasicAgent(
    name="ProjectManager",
    tools=[code_tool, writer_tool]
)

result = await orchestrator.conversation(
    prompt="Build a web scraper and document how it works"
)


Tool Management

ToolManager

Description: Central registry for managing and sharing tools across agents. Handles tool registration, discovery, and schema generation for different LLM providers.

Usage:

from parrot.tools.manager import ToolManager

# Create manager
tool_manager = ToolManager()

# Register tools
tool_manager.register_tool(MathTool())
tool_manager.register_tool(OpenWeatherTool(api_key="key"))
tool_manager.load_tool("DatabaseTool")

# Get tools for specific LLM format
openai_tools = tool_manager.get_tool_schemas(ToolFormat.OPENAI)
anthropic_tools = tool_manager.get_tool_schemas(ToolFormat.ANTHROPIC)

# Execute tool
result = await tool_manager.execute_tool(
    "MathTool",
    {"a": 10, "operation": "add", "b": 5}
)

Example:

# Shared tool manager for multiple agents
shared_manager = ToolManager()

# Load common tools
shared_manager.load_tool("MathTool")
shared_manager.load_tool("OpenWeatherTool")
shared_manager.register_tool(CustomTool())

# Agent 1 uses the manager
agent1 = BasicAgent(
    name="Assistant1",
    tool_manager=shared_manager
)

# Agent 2 shares the same tools
agent2 = BasicAgent(
    name="Assistant2",
    tool_manager=shared_manager
)

# Get all available tools
all_tools = shared_manager.all_tools()
tool_names = [tool.name for tool in all_tools]

Tool-Result Compression

Every execute_tool() call above passes through a client-agnostic compression stage before the result reaches any LLM — no per-tool or per-client opt-in required. Zero configuration means lossless-only (MINIMAL) compaction; a .parrot/compressors.toml manifest can raise specific tools to NORMAL (columnar splitting, constant-column factoring) with automatic working-memory recovery for anything lossy.

See Tool-Result Compression Pipeline for the full configuration format, the kill switch (PARROT_COMPRESSION_DISABLED=1), the tee recovery flow, and the optional Rust acceleration path.

Claude Agent Tool Bridge (FEAT-434)

When an agent's LLM is claude-agent:* (ClaudeAgentClient), its whole ToolManager is exposed to the delegated Claude Code sub-agent as an in-process SDK-MCP serverClaudeAgentToolBridge (parrot.clients.claude_agent_bridge). Exposure is automatic: whatever tools the agent has registered is what the sub-agent sees (subject to the narrowing budget below), no separate opt-in list.

from parrot.clients.claude_agent_bridge import ClaudeAgentToolBridge

bridge = ClaudeAgentToolBridge(tool_manager, namespace="parrot", tool_timeout=30.0)
tools = bridge.select(query=prompt, limit=15)   # ranked + bounded (TASK-2289)
server = bridge.build_server(tools, permission_context)
# ClaudeAgentOptions.mcp_servers = {"parrot": server, **caller_supplied}

Every exposed tool is reachable to the sub-agent as mcp__parrot__<tool_name> (the mcp__<namespace>__ prefix disambiguates a parrot tool from a same-named native Claude Code tool, e.g. a parrot tool literally called Read). Each call still dispatches through ToolManager.execute_tool() — never tool.execute() directly — so the TOOL_CALL guardrail pipeline, GrantGuard, ConfirmationGuard (see docs/hitl-confirmation.md) and the tool-result compression pipeline above all apply unchanged. A tool requiring confirmation has its confirm: boolean schema property stripped on this path only — the sub-agent is never handed a switch it can flip itself; the stdio MCP proxy (parrot mcp-serve) keeps the confirm property unchanged, since it has no HITL channel of its own.

Narrowing budget. Claude Code loads every exposed MCP tool eagerly — no deferral. ClaudeAgentRunOptions.max_exposed_tools (default 15) bounds the exposed set each turn; ClaudeAgentToolBridge.select() ranks against the turn's prompt via ToolManager.rank_tools() and logs what was dropped (count + names) rather than silently truncating.

Behavior change: search_tools() is now relevance-ordered, not alphabetical — and the match set can differ too. ToolManager. rank_tools() (a genuine lexical relevance ranker) is the new source of truth; search_tools() is a thin JSON-formatting wrapper over it. The return type (a JSON string), the name/description keys, and the no-match message are unchanged. The old substring check required the whole query to appear literally; the new scorer also gives credit for individual tokens found separately, so a multi-word query can now match more tools than before. A blank/whitespace query still matches the full registry (preserved deliberately, matching the old "" in name.lower() behavior). This affects every existing caller, including LLM-visible calls, since search_tools is itself a registered tool.

See docs/agentd.md "Claude Code sub-agent tool bridge" for the daemon-level configuration (use_tools, tools:, the auth caveat).


Integration & Communication

MCP Server Tools

Description: Model Context Protocol (MCP) server that exposes AI-Parrot tools via the MCP protocol, enabling integration with MCP-compatible clients.

Usage:

from parrot.tools.server import MCPServerConfig, MCPToolAdapter

config = MCPServerConfig(
    name="ai-parrot-mcp",
    transport="stdio",  # or "http"
    port=8080,
    allowed_tools=["MathTool", "OpenWeatherTool"]
)

# Adapt tools to MCP format
adapter = MCPToolAdapter(tool=MathTool())
mcp_definition = adapter.to_mcp_tool_definition()

Example:

# Start MCP server exposing tools
from parrot.tools.server import start_mcp_server

server = start_mcp_server(
    tools=[
        MathTool(),
        OpenWeatherTool(api_key="key"),
        DatabaseTool()
    ],
    config=MCPServerConfig(
        transport="http",
        host="0.0.0.0",
        port=8080
    )
)


Custom Tool Development

AbstractTool Base Class

Description: Base class for creating custom tools in AI-parrot. Provides standardized interface, schema generation, and error handling.

Usage:

from parrot.tools.abstract import AbstractTool, ToolResult
from pydantic import BaseModel, Field

class MyToolArgs(BaseModel):
    """Arguments schema for MyTool."""
    input_text: str = Field(description="Text to process")
    options: dict = Field(default={}, description="Processing options")

class MyTool(AbstractTool):
    """Custom tool implementation."""

    name = "MyTool"
    description = "Processes text with custom logic"
    args_schema = MyToolArgs

    async def _execute(self, input_text: str, options: dict = None, **kwargs) -> dict:
        """Execute tool logic."""
        result = self._process_text(input_text, options)
        return {
            "processed_text": result,
            "metadata": {"length": len(result)}
        }

    def _process_text(self, text: str, options: dict) -> str:
        # Custom processing logic
        return text.upper()

Example:

# Complete custom tool with validation
from typing import Literal

class SentimentAnalyzerArgs(BaseModel):
    text: str = Field(description="Text to analyze")
    model: Literal["simple", "advanced"] = Field(
        default="simple",
        description="Analysis model to use"
    )

class SentimentAnalyzerTool(AbstractTool):
    name = "sentiment_analyzer"
    description = "Analyzes sentiment of text"
    args_schema = SentimentAnalyzerArgs

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.models = {
            "simple": self._simple_analysis,
            "advanced": self._advanced_analysis
        }

    async def _execute(self, text: str, model: str = "simple", **kwargs):
        analysis_func = self.models.get(model)
        sentiment = analysis_func(text)

        return ToolResult(
            status="success",
            result={
                "text": text,
                "sentiment": sentiment,
                "model_used": model
            },
            metadata={"text_length": len(text)}
        )

    def _simple_analysis(self, text: str) -> str:
        # Simple sentiment logic
        positive_words = ["good", "great", "excellent", "happy"]
        negative_words = ["bad", "terrible", "awful", "sad"]

        text_lower = text.lower()
        pos_count = sum(word in text_lower for word in positive_words)
        neg_count = sum(word in text_lower for word in negative_words)

        if pos_count > neg_count:
            return "positive"
        elif neg_count > pos_count:
            return "negative"
        return "neutral"

    def _advanced_analysis(self, text: str) -> str:
        # More sophisticated analysis
        return "neutral"

# Use the custom tool
sentiment_tool = SentimentAnalyzerTool()
result = await sentiment_tool.execute(
    text="This is a great day!",
    model="simple"
)


Tool Configuration Examples

Registering Tools with Agents

from parrot.bots.agent import BasicAgent
from parrot.tools.math import MathTool
from parrot.tools.openweather import OpenWeatherTool

# Method 1: Tool instances
agent = BasicAgent(
    name="Assistant",
    tools=[
        MathTool(),
        OpenWeatherTool(api_key="key")
    ]
)

# Method 2: Tool names (auto-loaded)
agent = BasicAgent(
    name="Assistant",
    tools=["MathTool", "DatabaseTool"]
)

# Method 3: Mixed approach
agent = BasicAgent(
    name="Assistant",
    tools=[
        "MathTool",
        OpenWeatherTool(api_key="key"),
        CustomTool()
    ]
)

Tool Manager Integration

from parrot.tools.manager import ToolManager

# Create shared tool manager
manager = ToolManager()

# Register multiple tools
manager.register_tools([
    MathTool(),
    OpenWeatherTool(api_key="key"),
    DatabaseTool(),
    WebScrapingTool()
])

# Use with agent
agent = BasicAgent(
    name="MultiToolAgent",
    tool_manager=manager
)

# Execute tools directly
result = await manager.execute_tool(
    "OpenWeatherTool",
    {"latitude": 40.7, "longitude": -74.0}
)

Best Practices

  1. Error Handling: Always wrap tool execution in try-except blocks
  2. Tool Selection: Use specific tools for specific tasks rather than general-purpose tools
  3. Resource Management: Clean up resources (database connections, browser instances) after use
  4. API Keys: Store API keys in environment variables, not in code
  5. Validation: Use Pydantic schemas to validate tool arguments
  6. Async Execution: Prefer async methods for I/O-bound operations
  7. Tool Descriptions: Provide clear, detailed descriptions for LLM tool selection
  8. Return Types: Use standardized ToolResult format for consistent responses

Additional Resources

  • Tool Manager Documentation: See parrot/tools/manager.py
  • Agent Integration: See parrot/bots/agent.py
  • Custom Tool Development: Extend AbstractTool class
  • MCP Integration: See parrot/tools/server.py for protocol details
  • Tool-Result Compression: See Tool-Result Compression Pipeline for the config format, kill switch, tee recovery flow, and optional Rust extension

For more information on specific tools or creating custom tools, consult the source code in the parrot/tools/ directory.