> ## Documentation Index
> Fetch the complete documentation index at: https://connect.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Guidelines

> Guidelines to use tools with your agents

## 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:

<CodeGroup>
  ```javascript JS theme={null}
  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}`);
    }
  }
  ```

  ```python Python theme={null}
  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}')

  ```

  ```go Go theme={null}
  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
  }
  ```
</CodeGroup>

## 3. Error Handling

Return meaningful error messages when tools fail:

<CodeGroup>
  ```javascript JS theme={null}
  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'
        }
      });
    }
  }
  ```

  ```python Python theme={null}
  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')
              }
          })
  ```

  ```go Go theme={null}
  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)
  }
  ```
</CodeGroup>

## 4. Timeouts

Implement timeouts for tool execution to prevent blocking:

<CodeGroup>
  ```javascript JS theme={null}
  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);
      })
    ]);
  }
  ```

  ```python Python theme={null}
  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"
              }
          }

  ```

  ```go Go theme={null}
  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)
  	}
  }
  ```
</CodeGroup>

## 5. Statelessness

Design tools to be stateless when possible:

<CodeGroup>
  ```javascript JS theme={null}
  // 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;
  }
  ```

  ```python Python theme={null}
  # 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
  ```

  ```go Go theme={null}
  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
  }
  ```
</CodeGroup>

## 6. Security

Implement appropriate security measures for tool access:

<CodeGroup>
  ```javascript JS theme={null}
  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}`);
    }
  }
  ```

  ```python Python theme={null}
  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}')
  ```

  ```go Go theme={null}
  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))
  }
  ```
</CodeGroup>
