> ## Documentation Index
> Fetch the complete documentation index at: https://agentictoolbox.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Calling Patterns

> Learn how to effectively use single and multiple tools with Prism

## Single Tool Calling

The simplest pattern is calling a single tool. This is useful for straightforward operations like getting weather data or sending an email.

```php theme={null}
$weatherTool = new WeatherTool();

$response = Prism::text()
    ->using(config('toolbox.ai.provider'))
    ->withSystemPrompt("You can get weather data for any location.
        Provide a natural, conversational response including:
        - Temperature
        - Conditions
        - Humidity
        - Wind speed")
    ->withPrompt("What's the weather in London?")
    ->withTools([$weatherTool])
    ->withMaxSteps(2)  // One for tool call, one for summary
    ->generate();
```

### Understanding Single Tool Steps

When using a single tool, you typically need 2 steps:

1. Step 1: Call the tool and get data
2. Step 2: Process the data and provide a natural language response

## Multiple Tool Calling

For more complex operations, you can chain multiple tools together. This is useful for workflows like getting weather data and sending it via email.

```php theme={null}
$weatherTool = new WeatherTool();
$emailTool = new EmailTool();

$response = Prism::text()
    ->using(config('toolbox.ai.provider'))
    ->withSystemPrompt("You can get weather data and send it via email.
        For weather + email operations:
        1. First use the weather tool to get the data
        2. Then use the email tool to send that data
        3. Format the weather data nicely in the email body
        
        When sending emails:
        - Use 'Weather Update' as subject if not specified
        - Format the weather data in a readable way")
    ->withPrompt("Send the current weather in London to user@example.com")
    ->withTools([$weatherTool, $emailTool])
    ->withMaxSteps(5)  // Important: More steps needed for multiple tools
    ->generate();
```

### Understanding Multiple Tool Steps

For multiple tools, the steps typically flow like this:

1. Step 1: Call first tool (e.g., weather)
2. Step 2: Process first tool's data
3. Step 3: Call second tool (e.g., email)
4. Step 4: Process second tool's result
5. Step 5: Provide final summary

### Complex Example: Weather + Crypto + Email

Here's an example of chaining three tools to send both weather and crypto data via email:

```php theme={null}
$weatherTool = new WeatherTool();
$cryptoTool = new CryptoTool();
$emailTool = new EmailTool();

$response = Prism::text()
    ->using(config('toolbox.ai.provider'))
    ->withSystemPrompt("You can get weather data, crypto prices, and send emails.
        For this combined operation:
        1. Get the weather data for the specified location
        2. Get the crypto price for the specified coin
        3. Send an email containing both pieces of information
        
        Format the data nicely in the email, with sections for:
        - Current Weather Conditions
        - Cryptocurrency Prices")
    ->withPrompt("Send London's weather and Bitcoin's price to user@example.com")
    ->withTools([$weatherTool, $cryptoTool, $emailTool])
    ->withMaxSteps(7)  // (2 × number of tools) + 1
    ->generate();
```

## Best Practices

When working with tools, follow these guidelines:

### Setting Max Steps

* Single tool: Use 2 steps (call + summary)
* Multiple tools: Use (2 × number of tools) + 1
* Complex workflows: Add extra steps if needed for better processing

### System Prompts

* Be specific about the order of operations
* Include formatting instructions
* Specify default values (e.g., email subjects)
* Define error handling preferences

### Monitoring and Debugging

Track tool execution and responses using structured logging:

```php theme={null}
$debugInfo = [];

$response = Prism::text()
    ->withSystemPrompt("Get weather data and send via email")
    ->withPrompt("Send London weather to user@example.com")
    ->withTools([$weatherTool, $emailTool])
    ->withMaxSteps(5)
    ->generate();

// Log response structure
$debugInfo['response'] = [
    'has_text' => isset($response->text),
    'steps_count' => count($response->steps ?? []),
    'finish_reason' => $response->finishReason?->value,
];

// Log each step's details
foreach ($response->steps as $index => $step) {
    $debugInfo['steps'][] = [
        'index' => $index,
        'text' => $step->text ?? null,
        'finish_reason' => $step->finishReason?->value,
        'tool_calls' => collect($step->toolCalls)->map(fn($call) => [
            'tool' => $call->name,
            'args' => $call->arguments(),
        ])->toArray(),
        'tool_results' => collect($step->toolResults)->map(fn($result) => [
            'tool' => $result->toolName,
            'result' => $result->result,
        ])->toArray(),
    ];
}

// Log for analysis
Log::info('Tool Execution Debug Info:', $debugInfo);
```

Example debug output:

```json theme={null}
{
    "response": {
        "has_text": true,
        "steps_count": 5,
        "finish_reason": "stop"
    },
    "steps": [
        {
            "index": 0,
            "text": "I'll get the weather for London",
            "finish_reason": "tool_calls",
            "tool_calls": [
                {
                    "tool": "weather",
                    "args": {"location": "London"}
                }
            ],
            "tool_results": [
                {
                    "tool": "weather",
                    "result": {"temp": 18, "conditions": "cloudy"}
                }
            ]
        }
        // ... more steps
    ]
}
```

### Error Handling

Implement robust error handling with retries and fallbacks:

```php theme={null}
class WeatherEmailService
{
    private $maxRetries = 3;
    private $debugInfo = [];

    public function sendWeatherUpdate(string $location, string $email)
    {
        try {
            $response = $this->executeWithRetry(function () use ($location, $email) {
                return Prism::text()
                    ->withSystemPrompt("Get weather and send via email. Handle errors gracefully.")
                    ->withPrompt("Send {$location} weather to {$email}")
                    ->withTools([$this->weatherTool, $this->emailTool])
                    ->withMaxSteps(5)
                    ->generate();
            });

            $this->validateResponse($response);
            return $this->processResponse($response);

        } catch (WeatherToolException $e) {
            Log::error('Weather API Error', [
                'location' => $location,
                'error' => $e->getMessage(),
                'debug_info' => $this->debugInfo
            ]);
            
            // Fallback to cached weather data
            return $this->sendCachedWeather($location, $email);

        } catch (EmailToolException $e) {
            Log::error('Email Send Error', [
                'email' => $email,
                'error' => $e->getMessage(),
                'debug_info' => $this->debugInfo
            ]);

            // Queue for retry
            WeatherEmailRetryJob::dispatch($location, $email)
                ->delay(now()->addMinutes(5));

            throw new ServiceException(
                "Unable to send email. Queued for retry.",
                previous: $e
            );
        }
    }

    private function executeWithRetry(callable $operation)
    {
        $attempt = 1;
        $lastException = null;

        while ($attempt <= $this->maxRetries) {
            try {
                return $operation();
            } catch (Exception $e) {
                $lastException = $e;
                Log::warning("Attempt {$attempt} failed", [
                    'error' => $e->getMessage(),
                    'debug_info' => $this->debugInfo
                ]);
                
                if ($attempt < $this->maxRetries) {
                    sleep(pow(2, $attempt)); // Exponential backoff
                }
                $attempt++;
            }
        }

        throw new ServiceException(
            "Operation failed after {$this->maxRetries} attempts",
            previous: $lastException
        );
    }

    private function validateResponse($response)
    {
        if (empty($response->steps)) {
            throw new ServiceException("No steps in response");
        }

        // Check if we got weather data
        $hasWeatherData = collect($response->steps)
            ->flatMap->toolResults
            ->contains(fn($result) => 
                $result->toolName === 'weather' && !empty($result->result)
            );

        if (!$hasWeatherData) {
            throw new ServiceException("No weather data in response");
        }
    }
}
```

This implementation shows:

* Structured logging of all steps and tool calls
* Retry logic with exponential backoff
* Specific error handling for each tool
* Fallback behaviors (cached data, retry queue)
* Response validation
* Detailed error context for debugging

## Common Patterns

Here are some common tool calling patterns with practical examples:

### Sequential Processing

When one tool's output is needed for the next tool's input:

```php theme={null}
// Example: Get weather and email it
$response = Prism::text()
    ->withSystemPrompt("First get the weather, then email it to the user")
    ->withPrompt("Send London's weather to user@example.com")
    ->withTools([$weatherTool, $emailTool])
    ->withMaxSteps(5)  // 2 for weather, 2 for email, 1 for final summary
    ->generate();
```

### Conditional Branching

When the choice of second tool depends on the first tool's result:

```php theme={null}
// Example: Check weather and either send warning email or update status
$response = Prism::text()
    ->withSystemPrompt("Check the weather. If severe conditions, send warning email.
        Otherwise, just log the status.")
    ->withPrompt("Monitor weather conditions in Miami")
    ->withTools([$weatherTool, $emailTool, $statusTool])
    ->withMaxSteps(5)  // 2 for weather, 2 for chosen action, 1 for summary
    ->generate();
```

### Data Aggregation

When you need to combine data from multiple tools:

```php theme={null}
// Example: Send both weather and crypto data in one email
$response = Prism::text()
    ->withSystemPrompt("Get both weather and crypto data, then send combined report")
    ->withPrompt("Send London weather and Bitcoin price to user@example.com")
    ->withTools([$weatherTool, $cryptoTool, $emailTool])
    ->withMaxSteps(7)  // 2 for weather, 2 for crypto, 2 for email, 1 for summary
    ->generate();
```

### Interactive Processing

When you need multiple interactions with the same tool:

```php theme={null}
// Example: Compare weather in multiple cities
$response = Prism::text()
    ->withSystemPrompt("Get weather for multiple cities and compare them")
    ->withPrompt("Compare weather in London, Paris, and New York")
    ->withTools([$weatherTool])
    ->withMaxSteps(7)  // 2 steps per city (3 cities) + 1 for comparison
    ->generate();
```
