1. Clear Documentation
Provide clear documentation for each tool, including:- Purpose: What the tool does
- Parameters: What parameters the tool accepts
- Return Value: What the tool returns
- Examples: Examples of how to use the tool
2. Input Validation
Validate all tool inputs to prevent errors and security issues:function validateToolInput(toolName, args) {
switch (toolName) {
case 'get_weather':
if (!args.location) {
throw new Error('Location is required for get_weather tool');
}
if (args.unit && !['celsius', 'fahrenheit'].includes(args.unit)) {
throw new Error('Unit must be either "celsius" or "fahrenheit"');
}
break;
case 'search_database':
if (!args.query) {
throw new Error('Query is required for search_database tool');
}
if (args.limit && (!Number.isInteger(args.limit) || args.limit <= 0)) {
throw new Error('Limit must be a positive integer');
}
break;
default:
throw new Error(`Unknown tool: ${toolName}`);
}
}
def validate_tool_input(tool_name, args):
if tool_name == 'get_weather':
if 'location' not in args or not args['location']:
raise ValueError('Location is required for get_weather tool')
if 'unit' in args and args['unit'] not in ['celsius', 'fahrenheit']:
raise ValueError('Unit must be either "celsius" or "fahrenheit"')
elif tool_name == 'search_database':
if 'query' not in args or not args['query']:
raise ValueError('Query is required for search_database tool')
if 'limit' in args:
if not isinstance(args['limit'], int) or args['limit'] <= 0:
raise ValueError('Limit must be a positive integer')
else:
raise ValueError(f'Unknown tool: {tool_name}')
package main
import (
"errors"
"fmt"
)
func validateToolInput(toolName string, args map[string]interface{}) error {
switch toolName {
case "get_weather":
location, ok := args["location"]
if !ok || location == "" {
return errors.New("Location is required for get_weather tool")
}
if unit, ok := args["unit"]; ok {
unitStr, ok := unit.(string)
if !ok || (unitStr != "celsius" && unitStr != "fahrenheit") {
return errors.New(`Unit must be either "celsius" or "fahrenheit"`)
}
}
case "search_database":
query, ok := args["query"]
if !ok || query == "" {
return errors.New("Query is required for search_database tool")
}
if limit, ok := args["limit"]; ok {
limitFloat, ok := limit.(float64) // JSON numbers are float64
if !ok || limitFloat <= 0 || limitFloat != float64(int(limitFloat)) {
return errors.New("Limit must be a positive integer")
}
}
default:
return fmt.Errorf("Unknown tool: %s", toolName)
}
return nil
}
3. Error Handling
Return meaningful error messages when tools fail:async function executeToolCall(toolName, args) {
try {
// Validate the tool input
validateToolInput(toolName, args);
// Execute the tool
if (toolFunctions[toolName]) {
return await toolFunctions[toolName](args);
} else {
throw new Error(`Tool not implemented: ${toolName}`);
}
} catch (error) {
// Return a structured error response
return JSON.stringify({
error: {
message: error.message,
type: 'tool_execution_error',
code: error.code || 'unknown_error'
}
});
}
}
import json
# Assume validate_tool_input and tool_functions are defined elsewhere
async def execute_tool_call(tool_name, args):
try:
# Validate the tool input
validate_tool_input(tool_name, args)
# Execute the tool
if tool_name in tool_functions:
return await tool_functionstool_name
else:
raise NotImplementedError(f'Tool not implemented: {tool_name}')
except Exception as error:
return json.dumps({
"error": {
"message": str(error),
"type": "tool_execution_error",
"code": getattr(error, 'code', 'unknown_error')
}
})
package main
import (
"encoding/json"
"fmt"
)
type ToolFunc func(map[string]interface{}) (interface{}, error)
var toolFunctions = map[string]ToolFunc{
// "get_weather": getWeatherFunc,
// "search_database": searchDatabaseFunc,
}
func executeToolCall(toolName string, args map[string]interface{}) string {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
if err := validateToolInput(toolName, args); err != nil {
return formatError(err)
}
if toolFunc, ok := toolFunctions[toolName]; ok {
result, err := toolFunc(args)
if err != nil {
return formatError(err)
}
resultJSON, _ := json.Marshal(result)
return string(resultJSON)
}
return formatError(fmt.Errorf("Tool not implemented: %s", toolName))
}
func formatError(err error) string {
errorResponse := map[string]interface{}{
"error": map[string]interface{}{
"message": err.Error(),
"type": "tool_execution_error",
"code": "unknown_error",
},
}
jsonBytes, _ := json.Marshal(errorResponse)
return string(jsonBytes)
}
4. Timeouts
Implement timeouts for tool execution to prevent blocking:async function executeToolWithTimeout(toolName, args, timeout = 5000) {
return Promise.race([
executeToolCall(toolName, args),
new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Tool execution timed out: ${toolName}`)), timeout);
})
]);
}
import asyncio
async def execute_tool_with_timeout(tool_name, args, timeout=5):
try:
return await asyncio.wait_for(execute_tool_call(tool_name, args), timeout=timeout)
except asyncio.TimeoutError:
return {
"error": {
"message": f"Tool execution timed out: {tool_name}",
"type": "tool_execution_error",
"code": "timeout_error"
}
}
package main
import (
"encoding/json"
"fmt"
"time"
)
func executeToolWithTimeout(toolName string, args map[string]interface{}, timeout time.Duration) string {
resultChan := make(chan string, 1)
go func() {
result := executeToolCall(toolName, args)
resultChan <- result
}()
select {
case result := <-resultChan:
return result
case <-time.After(timeout):
errorResponse := map[string]interface{}{
"error": map[string]interface{}{
"message": fmt.Sprintf("Tool execution timed out: %s", toolName),
"type": "tool_execution_error",
"code": "timeout_error",
},
}
jsonBytes, _ := json.Marshal(errorResponse)
return string(jsonBytes)
}
}
5. Statelessness
Design tools to be stateless when possible:// Avoid this (stateful)
let cachedData = null;
async function getDataTool(args) {
if (cachedData) {
return cachedData;
}
cachedData = await fetchData(args);
return cachedData;
}
// Prefer this (stateless)
async function getDataTool(args) {
// Use a cache service that's external to the tool
const cacheKey = generateCacheKey(args);
const cachedData = await cacheService.get(cacheKey);
if (cachedData) {
return cachedData;
}
const data = await fetchData(args);
await cacheService.set(cacheKey, data);
return data;
}
# Avoid this
cached_data = None
async def get_data_tool(args):
global cached_data
if cached_data:
return cached_data
cached_data = await fetch_data(args)
return cached_data
# Prefer this
async def get_data_tool(args):
cache_key = generate_cache_key(args)
cached_data = await cache_service.get(cache_key)
if cached_data:
return cached_data
data = await fetch_data(args)
await cache_service.set(cache_key, data)
return data
package main
var cachedData interface{}
// Avoid this
func getDataTool(args map[string]interface{}) (interface{}, error) {
if cachedData != nil {
return cachedData, nil
}
data, err := fetchData(args)
if err != nil {
return nil, err
}
cachedData = data
return data, nil
}
// Prefer this
func getDataTool(args map[string]interface{}) (interface{}, error) {
cacheKey := generateCacheKey(args)
cachedData, err := cacheService.Get(cacheKey)
if err == nil && cachedData != nil {
return cachedData, nil
}
data, err := fetchData(args)
if err != nil {
return nil, err
}
_ = cacheService.Set(cacheKey, data)
return data, nil
}
6. Security
Implement appropriate security measures for tool access:function authorizeToolAccess(user, toolName) {
// Check if the user has permission to use this tool
const userPermissions = getUserPermissions(user);
if (!userPermissions.tools.includes(toolName)) {
throw new Error(`User does not have permission to use tool: ${toolName}`);
}
}
def authorize_tool_access(user, tool_name):
# Check if the user has permission to use this tool
user_permissions = get_user_permissions(user)
if tool_name not in user_permissions.get('tools', []):
raise PermissionError(f'User does not have permission to use tool: {tool_name}')
import (
"errors"
"fmt"
)
type User struct {
ID string
// other fields
}
type Permissions struct {
Tools []string
}
func authorizeToolAccess(user User, toolName string) error {
userPermissions := getUserPermissions(user)
for _, tool := range userPermissions.Tools {
// Check if the user has permission to use this tool
if tool == toolName {
return nil
}
}
return errors.New(fmt.Sprintf("User does not have permission to use tool: %s", toolName))
}

