Beginner-Friendly Topic
Take your time - it's perfectly normal to re-read this topic 2-3 times. Try the interactive code editor below to run code yourself. Use the Q&A section to check your understanding before moving on.You've got this!
Building a Safe Agent Tool
Putting it all together: build a complete, safe agent tool with validation, error handling, logging, and permission checks.
10 min•By Priygop Team•Updated 2026
Complete Safe Tool Template
Complete Safe Tool Template
# Complete safe tool with all best practices
import json
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
class SafeTool:
"""Base class for safe, production-quality agent tools."""
name = "base_tool"
description = "Base tool — override in subclass"
allowed_roles = {"admin"}
def validate(self, **kwargs) -> tuple[bool, str]:
"""Validate inputs. Returns (is_valid, error_message)."""
return True, ""
def execute(self, **kwargs) -> dict:
"""Run the tool logic. Override in subclass."""
raise NotImplementedError
def run(self, agent_role: str, **kwargs) -> dict:
"""Entry point: validate permissions, validate inputs, execute."""
# 1. Permission check
if agent_role not in self.allowed_roles:
logger.warning(f"Permission denied: {agent_role} tried to use {self.name}")
return {"status": "error", "error_type": "permission",
"error": f"Role '{agent_role}' cannot use tool '{self.name}'"}
# 2. Input validation
is_valid, error_msg = self.validate(**kwargs)
if not is_valid:
return {"status": "error", "error_type": "validation", "error": error_msg}
# 3. Execute with error handling
try:
result = self.execute(**kwargs)
logger.info(f"Tool {self.name} succeeded for role {agent_role}")
return result
except Exception as e:
logger.error(f"Tool {self.name} failed: {e}")
return {"status": "error", "error_type": "execution", "error": str(e)}
class GetOrderTool(SafeTool):
name = "get_order"
description = "Retrieve order details by order ID. Returns order status, items, and total."
allowed_roles = {"support_agent", "admin"}
def validate(self, order_id: str = "", **kwargs):
if not order_id or not order_id.startswith("ORD-"):
return False, "order_id must start with 'ORD-'"
return True, ""
def execute(self, order_id: str, **kwargs) -> dict:
# In a real tool, query the database here
return {
"status": "success",
"order_id": order_id,
"items": ["Laptop", "Mouse"],
"total": 849.99,
"order_status": "shipped"
}
# Use the tool
tool = GetOrderTool()
result = tool.run(agent_role="support_agent", order_id="ORD-12345")
print(json.dumps(result, indent=2))