Error Handling
Handle errors like a pro! ๐ก๏ธ The Vizra ADK provides a robust error handling system with specialized exceptions to help you build resilient AI agents that gracefully handle the unexpected.
๐ Exception Types
The framework includes three specialized exception classes that extend PHP's base \Exception
class:
๐ AgentNotFoundException
Thrown when attempting to access or execute an agent that doesn't exist in the registry.
use Vizra\VizraADK\Exceptions\AgentNotFoundException;
// Example from AgentRegistry::getAgent()
if (!isset($this->registeredAgents[$name])) {
throw new AgentNotFoundException("Agent '{$name}' is not registered.");
}
โ๏ธ AgentConfigurationException
Thrown when there are issues with agent configuration, such as invalid settings or missing required parameters.
use Vizra\VizraADK\Exceptions\AgentConfigurationException;
// Example usage
if (!class_exists($config)) {
throw new AgentConfigurationException(
"Agent class '{$config}' does not exist."
);
}
๐ง ToolExecutionException
Thrown when errors occur during tool execution, including invalid parameters or runtime failures.
use Vizra\VizraADK\Exceptions\ToolExecutionException;
// Example in tool execution
try {
$result = $tool->execute($arguments, $context);
} catch (\Exception $e) {
throw new ToolExecutionException(
"Tool '{$toolName}' failed: " . $e->getMessage()
);
}
๐ฎ Handling Exceptions in Controllers
The AgentApiController
demonstrates comprehensive exception handling:
use Vizra\VizraADK\Facades\Agent;
use Vizra\VizraADK\Exceptions\AgentNotFoundException;
use Vizra\VizraADK\Exceptions\ToolExecutionException;
use Vizra\VizraADK\Exceptions\AgentConfigurationException;
class AgentApiController extends Controller
{
public function handleAgentInteraction(Request $request): JsonResponse
{
try {
// Check if agent exists
if (!Agent::hasAgent($agentName)) {
return response()->json([
'error' => "Agent '{$agentName}' is not registered or found.",
'message' => "Please ensure the agent is registered..."
], 404);
}
// Execute agent
$response = Agent::run($agentName, $input, $sessionId);
return response()->json([
'agent_name' => $agentName,
'session_id' => $sessionId,
'response' => $response,
]);
} catch (AgentNotFoundException $e) {
logger()->error("Agent not found: " . $e->getMessage());
return response()->json([
'error' => "Agent '{$agentName}' could not be found or loaded.",
'detail' => $e->getMessage()
], 404);
} catch (ToolExecutionException $e) {
logger()->error("Tool execution error for agent {$agentName}: " . $e->getMessage(), [
'exception' => $e
]);
return response()->json([
'error' => 'A tool required by the agent failed to execute.',
'detail' => $e->getMessage()
], 500);
} catch (AgentConfigurationException $e) {
logger()->error("Agent configuration error for agent {$agentName}: " . $e->getMessage(), [
'exception' => $e
]);
return response()->json([
'error' => 'Agent configuration error.',
'detail' => $e->getMessage()
], 500);
} catch (\Throwable $e) {
// Catch-all for unexpected errors
logger()->error("Error during agent '{$agentName}' execution: " . $e->getMessage(), [
'exception' => $e
]);
return response()->json([
'error' => 'An unexpected error occurred while processing your request.',
'detail' => $e->getMessage()
], 500);
}
}
}
๐ป Error Handling in Commands
Artisan commands handle errors gracefully to provide helpful feedback:
// Example from RunEvalCommand
try {
$evaluation = $this->loadEvaluation($evaluationName);
$results = $evaluation->run();
} catch (\Exception $e) {
$this->error("โ Evaluation failed: " . $e->getMessage());
return 1; // Return non-zero exit code
}
๐ญ Error Handling in Services
Services like AgentRegistry
validate configuration and throw appropriate exceptions:
public function getAgent(string $name): BaseAgent
{
if (!isset($this->registeredAgents[$name])) {
throw new AgentNotFoundException("Agent '{$name}' is not registered.");
}
$config = $this->registeredAgents[$name];
if (is_string($config)) {
if (!class_exists($config)) {
throw new AgentConfigurationException(
"Agent class '{$config}' does not exist."
);
}
$agent = new $config();
if (!$agent instanceof BaseAgent) {
throw new AgentConfigurationException(
"Agent class '{$config}' must extend BaseAgent."
);
}
return $agent;
}
// Handle array configuration...
}
โจ Best Practices
1๏ธโฃ Use Specific Exception Types
Always throw the most specific exception type for the error scenario:
// โ
Good - specific exception
if (!$agent) {
throw new AgentNotFoundException("Agent 'chatbot' not found");
}
// โ Avoid - generic exception
if (!$agent) {
throw new \Exception("Agent not found");
}
2๏ธโฃ Provide Meaningful Error Messages
Include context in error messages to help with debugging:
throw new ToolExecutionException(
"Weather tool failed for location '{$location}': API key not configured"
);
3๏ธโฃ Log Errors with Context
Always log errors with relevant context for debugging:
catch (ToolExecutionException $e) {
logger()->error("Tool execution failed", [
'agent' => $agentName,
'tool' => $e->getToolName(),
'session_id' => $sessionId,
'exception' => $e
]);
}
4๏ธโฃ Handle Errors at the Right Level
Let exceptions bubble up to where they can be handled appropriately:
// In a tool - let exception bubble up
public function execute(array $arguments, AgentContext $context): string
{
if (!isset($arguments['location'])) {
throw new ToolExecutionException("Location parameter is required");
}
// Tool logic...
}
// In the controller - handle and return appropriate response
try {
$result = $agent->run($input);
} catch (ToolExecutionException $e) {
return response()->json(['error' => $e->getMessage()], 400);
}
๐จ Creating Custom Exceptions
You can create custom exceptions for your specific use cases:
<?php
namespace App\Exceptions;
use Vizra\VizraADK\Exceptions\ToolExecutionException;
class ApiRateLimitException extends ToolExecutionException
{
protected string $service;
protected int $retryAfter;
public function __construct(string $service, int $retryAfter)
{
$this->service = $service;
$this->retryAfter = $retryAfter;
parent::__construct(
"Rate limit exceeded for {$service}. Retry after {$retryAfter} seconds."
);
}
public function getRetryAfter(): int
{
return $this->retryAfter;
}
}
๐ Error Recovery Strategies
๐ Graceful Degradation
Provide fallback behavior when non-critical operations fail:
public function execute(array $arguments, AgentContext $context): string
{
try {
// Try to get weather from primary API
$weather = $this->primaryApi->getWeather($location);
} catch (ToolExecutionException $e) {
logger()->warning("Primary weather API failed, using fallback", [
'error' => $e->getMessage()
]);
// Fallback to secondary API
try {
$weather = $this->fallbackApi->getWeather($location);
} catch (ToolExecutionException $e) {
// Return cached or default response
return json_encode([
'error' => 'Weather service temporarily unavailable',
'cached' => true,
'data' => $this->getCachedWeather($location)
]);
}
}
return json_encode($weather);
}
๐ Retry Logic
Implement retry logic for transient failures:
use Illuminate\Support\Facades\Http;
public function executeWithRetry(callable $operation, int $maxAttempts = 3)
{
$attempt = 1;
while ($attempt <= $maxAttempts) {
try {
return $operation();
} catch (ToolExecutionException $e) {
if ($attempt === $maxAttempts) {
throw $e;
}
logger()->warning("Operation failed, retrying", [
'attempt' => $attempt,
'max_attempts' => $maxAttempts,
'error' => $e->getMessage()
]);
sleep(pow(2, $attempt)); // Exponential backoff
$attempt++;
}
}
}
๐งช Testing Error Handling
Always test your error handling paths:
use Vizra\VizraADK\Exceptions\AgentNotFoundException;
test('throws exception for non-existent agent', function () {
$registry = app(AgentRegistry::class);
expect(fn() => $registry->getAgent('non-existent'))
->toThrow(AgentNotFoundException::class, "Agent 'non-existent' is not registered.");
});
test('handles tool execution failure gracefully', function () {
$response = $this->postJson('/api/vizra/interact', [
'agent_name' => 'test_agent',
'input' => 'trigger tool failure'
]);
$response->assertStatus(500)
->assertJson([
'error' => 'A tool required by the agent failed to execute.'
]);
});
๐ Ready to Build Resilient Agents?
Master error handling and continue your journey: