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).
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
}
| Field | Required | Description |
|---|
definition | Yes | OpenAI function calling format definition |
implementation | Yes | The Python function to execute |
type | No | Optional metadata (e.g., “standard”) |
timeout | No | Maximum execution time in seconds. If exceeded, raises TimeoutError |
Tool functions follow specific patterns:
Automatic Weave Tracing: Tyler automatically wraps all tool implementations with weave.op() when they are registered. You don’t need to add @weave.op() decorators to your tools - they will appear in Weave traces automatically with the tool name as the operation 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
Tools that return files use a tuple format:
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
}
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)}"
Lye follows consistent naming patterns:
- Format:
category-action_target
- Examples:
web-fetch_page
files-read_file
image-generate_image
slack-send_message
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
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
)
- User Request: User asks agent to perform a task
- Tool Selection: Agent selects appropriate tool based on description
- Parameter Extraction: Agent extracts parameters from context
- Validation: Parameters are validated against schema
- Execution: Tool function is called with parameters
- Result Processing: Result is returned to agent
- 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
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:
- A
TimeoutError is raised with the message: Tool 'tool_name' timed out after X seconds
- The error is returned to the LLM as the tool result
- The LLM can then decide how to proceed
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 (automatically traced by Tyler)
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)}", []
# 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)