Skip to main content

Overview

Lye tools follow a specific format that makes them compatible with Tyler agents and LLM function calling. Each tool consists of a definition (for the LLM) and an implementation (the actual function).

Tool Structure

Each Lye tool is a dictionary with the following structure:
{
    "definition": {
        "type": "function",
        "function": {
            "name": "tool-name",
            "description": "What the tool does",
            "parameters": {
                "type": "object",
                "properties": {
                    "param1": {
                        "type": "string",
                        "description": "Parameter description"
                    }
                },
                "required": ["param1"]
            }
        }
    },
    "implementation": tool_function,
    "type": "standard",  # Optional metadata
    "timeout": 30.0      # Optional: max execution time in seconds
}
FieldRequiredDescription
definitionYesOpenAI function calling format definition
implementationYesThe Python function to execute
typeNoOptional metadata (e.g., “standard”)
timeoutNoMaximum execution time in seconds. If exceeded, raises TimeoutError

Tool Implementation

Tool functions follow specific patterns:

Basic Tool

import weave

@weave.op(name="category-tool_name")
def tool_function(*, param1: str, param2: Optional[int] = None) -> str:
    """
    Tool implementation.
    
    Args:
        param1: Required parameter
        param2: Optional parameter with default
        
    Returns:
        String result for the agent
    """
    # Tool logic here
    result = f"Processed {param1}"
    
    return result

Tool with Files

Tools that return files use a tuple format:
@weave.op(name="files-create_file")
def create_file(*, filename: str, content: str) -> Tuple[str, List[Dict[str, Any]]]:
    """
    Create a file and return it.
    
    Returns:
        Tuple containing:
        - Status message
        - List of file dictionaries
    """
    files = [{
        "filename": filename,
        "content": base64.b64encode(content.encode()).decode(),
        "mime_type": "text/plain"
    }]
    
    return f"Created {filename}", files

Parameter Types

Basic Types

"parameters": {
    "type": "object",
    "properties": {
        "text": {
            "type": "string",
            "description": "Input text"
        },
        "count": {
            "type": "integer",
            "description": "Number of items"
        },
        "enabled": {
            "type": "boolean",
            "description": "Feature flag"
        },
        "threshold": {
            "type": "number",
            "description": "Decimal threshold"
        }
    }
}

Enums

"format": {
    "type": "string",
    "description": "Output format",
    "enum": ["text", "json", "html"],
    "default": "text"
}

Arrays

"tags": {
    "type": "array",
    "items": {
        "type": "string"
    },
    "description": "List of tags"
}

Optional Parameters

"parameters": {
    "type": "object",
    "properties": {
        "required_param": {...},
        "optional_param": {...}
    },
    "required": ["required_param"]  # Only list required params
}

Return Formats

Simple string return

def simple_tool(*, input: str) -> str:
    return f"Processed: {input}"

Structured return with files

def file_tool(*, data: str) -> Tuple[str, List[Dict[str, Any]]]:
    # Process data
    result_content = process_data(data)
    
    files = [{
        "filename": "result.txt",
        "content": base64.b64encode(result_content.encode()).decode(),
        "mime_type": "text/plain"
    }]
    
    return "Processing complete", files

Error Handling

def safe_tool(*, url: str) -> str:
    try:
        # Attempt operation
        result = fetch_data(url)
        return f"Success: {result}"
    except Exception as e:
        # Return error message for agent
        return f"Error: {str(e)}"

Tool Naming Conventions

Lye follows consistent naming patterns:
  • Format: category-action_target
  • Examples:
    • web-fetch_page
    • files-read_file
    • image-generate_image
    • slack-send_message

Using tools with agents

Direct Usage

from tyler import Agent
from lye import WEB_TOOLS

agent = Agent(
    name="web-researcher",
    tools=WEB_TOOLS
)

# Agent automatically uses tools based on user requests

Tool Selection

from lye import TOOLS

# Filter tools by name pattern
web_tools = [t for t in TOOLS if t["definition"]["function"]["name"].startswith("web-")]

# Select specific tools
selected_tools = [
    t for t in TOOLS 
    if t["definition"]["function"]["name"] in ["web-search", "files-write_file"]
]

agent = Agent(
    name="selective-agent",
    tools=selected_tools
)

Tool Execution Flow

  1. User Request: User asks agent to perform a task
  2. Tool Selection: Agent selects appropriate tool based on description
  3. Parameter Extraction: Agent extracts parameters from context
  4. Validation: Parameters are validated against schema
  5. Execution: Tool function is called with parameters
  6. Result Processing: Result is returned to agent
  7. Response: Agent incorporates result into response

Best practices

Clear descriptions

# Good
"description": "Search the web using Google and return relevant results with titles, snippets, and URLs"

# Bad
"description": "Search tool"

Parameter descriptions

# Good
"url": {
    "type": "string",
    "description": "The complete URL to fetch, including protocol (http:// or https://)"
}

# Bad
"url": {
    "type": "string",
    "description": "URL"
}

Error messages

# Good
return "Error: Unable to connect to https://example.com - Connection timeout after 30 seconds"

# Bad
return "Error"

File returns

# Always include metadata
files = [{
    "filename": "report.pdf",
    "content": base64_content,
    "mime_type": "application/pdf"
}]

# Include helpful status message
return f"Generated PDF report with {page_count} pages", files

Tool Timeout

For tools that may take a long time (external API calls, file processing), set a timeout value:
SLOW_API_TOOL = {
    "definition": {
        "type": "function",
        "function": {
            "name": "slow_api_call",
            "description": "Call an external API that may be slow",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "API query"}
                },
                "required": ["query"]
            }
        }
    },
    "implementation": slow_api_call,
    "timeout": 60.0  # 60 second timeout
}
When a tool exceeds its timeout:
  1. A TimeoutError is raised with the message: Tool 'tool_name' timed out after X seconds
  2. The error is returned to the LLM as the tool result
  3. The LLM can then decide how to proceed

Example: Complete Tool

import weave
import requests
from typing import Tuple, List, Dict, Any
import base64

# Tool definition
WEB_DOWNLOAD_TOOL = {
    "definition": {
        "type": "function",
        "function": {
            "name": "web-download_file",
            "description": "Download a file from a URL and return it as an attachment",
            "parameters": {
                "type": "object",
                "properties": {
                    "url": {
                        "type": "string",
                        "description": "The URL of the file to download"
                    },
                    "timeout": {
                        "type": "integer",
                        "description": "Timeout in seconds",
                        "default": 30
                    }
                },
                "required": ["url"]
            }
        }
    },
    "implementation": download_file,
    "type": "standard",
    "timeout": 120.0  # Tool-level timeout (2 minutes max)
}

# Tool implementation
@weave.op(name="web-download_file")
def download_file(*, url: str, timeout: int = 30) -> Tuple[str, List[Dict[str, Any]]]:
    """Download a file from URL."""
    try:
        response = requests.get(url, timeout=timeout)
        response.raise_for_status()
        
        # Get filename from URL
        filename = url.split('/')[-1] or "download"
        
        # Encode content
        content = base64.b64encode(response.content).decode()
        
        # Detect MIME type
        mime_type = response.headers.get('content-type', 'application/octet-stream')
        
        files = [{
            "filename": filename,
            "content": content,
            "mime_type": mime_type
        }]
        
        size_mb = len(response.content) / (1024 * 1024)
        return f"Downloaded {filename} ({size_mb:.2f} MB)", files
        
    except requests.exceptions.Timeout:
        return f"Error: Download timed out after {timeout} seconds", []
    except requests.exceptions.RequestException as e:
        return f"Error downloading file: {str(e)}", []
    except Exception as e:
        return f"Unexpected error: {str(e)}", []

Testing tools

# Test tool directly
result = await download_file(url="https://example.com/file.pdf")
print(result[0])  # Status message
print(len(result[1]))  # Number of files

# Test with agent
from tyler import Agent, Thread, Message

agent = Agent(tools=[WEB_DOWNLOAD_TOOL])
thread = Thread()
thread.add_message(Message(
    role="user",
    content="Download the PDF from https://example.com/report.pdf"
))

result = await agent.run(thread)