Vizra.ai |

Documentation

๐Ÿ› ๏ธ

Tools

Supercharge your agents with powerful capabilities! Tools let your AI agents interact with the real world - from databases to APIs to custom business logic ๐Ÿš€

๐ŸŽฏ What Makes Tools Awesome?

Think of tools as your agent's superpowers! While agents are great at conversation, tools let them actually do things - like looking up orders, sending emails, or integrating with your favorite APIs. It's like giving your AI a Swiss Army knife! ๐Ÿ”ง

๐Ÿ“š Understanding Tools

Here's what makes Vizra tools special:

๐Ÿ—๏ธ Simple PHP Classes

Just implement the ToolInterface and you're ready to roll!

๐Ÿค– Self-Describing

JSON Schema definitions help LLMs understand exactly how to use your tools

โšก Auto-Integration

Prism automatically connects your tools to the LLM's function calling

๐Ÿง  Context-Aware

Access the full AgentContext for stateful operations

๐ŸŽจ Creating Your First Tool

โœจ Quick Start with Artisan

The easiest way to create a tool? Let Artisan do the heavy lifting!

Terminal
php artisan vizra:make:tool OrderLookupTool

๐Ÿ’ก Pro tip: This creates a fully-functional tool template in app/Tools/ ready for your custom logic!

๐Ÿ—๏ธ Tool Structure

Every tool follows a simple pattern - implement the ToolInterface and define two key methods:

app/Tools/OrderLookupTool.php
<?php

namespace App\Tools;

use Vizra\VizraADK\Contracts\ToolInterface;
use Vizra\VizraADK\System\AgentContext;
use Vizra\VizraADK\Memory\AgentMemory;

class OrderLookupTool implements ToolInterface
{
    public function definition(): array
    {
        return [
            'name' => 'order_lookup',
            'description' => 'Look up order information by order ID',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'order_id' => [
                        'type' => 'string',
                        'description' => 'The order ID to look up',
                    ],
                ],
                'required' => ['order_id'],
            ],
        ];
    }

    public function execute(array $arguments, AgentContext $context, AgentMemory $memory): string
    {
        $orderId = $arguments['order_id'] ?? null;

        if (!$orderId) {
            return json_encode([
                'status' => 'error',
                'message' => 'Order ID is required',
            ]);
        }

        // Look up the order in your database
        $order = Order::find($orderId);

        if (!$order) {
            return json_encode([
                'status' => 'error',
                'message' => "Order {$orderId} not found",
            ]);
        }
        
        // Store this interaction in memory
        $memory->addFact("Recent order lookup: #{$orderId}", 1.0);
        $memory->addLearning("User inquired about order #{$orderId}");

        return json_encode([
            'status' => 'success',
            'order_id' => $order->id,
            'status' => $order->status,
            'total' => $order->total,
            'created_at' => $order->created_at->toDateTimeString(),
        ]);
    }
}

๐Ÿ”ง Tool Interface Methods

๐Ÿ“‹ The definition() Method

This is where you tell the LLM exactly what your tool does and what parameters it needs. Think of it as your tool's instruction manual! ๐Ÿ“–

Tool Definition Example
public function definition(): array
{
    return [
        'name' => 'weather_tool',
        'description' => 'Get current weather information',
        'parameters' => [
            'type' => 'object',
            'properties' => [
                'location' => [
                    'type' => 'string',
                    'description' => 'The city and state, e.g. San Francisco, CA',
                ],
                'units' => [
                    'type' => 'string',
                    'enum' => ['celsius', 'fahrenheit'],
                    'description' => 'Temperature units',
                ],
            ],
            'required' => ['location'],
        ],
    ];
}

โœ… Clear Names

Use descriptive names that tell the LLM exactly what your tool does

๐Ÿ“ Good Descriptions

Help the LLM understand when and how to use your tool

๐ŸŽฏ Type Safety

Define parameter types to ensure correct usage

โšก The execute() Method

This is where the magic happens! Your tool receives arguments from the LLM and the current context, then returns results as JSON. ๐ŸŽญ

Tool Execution Example
public function execute(array $arguments, AgentContext $context): string
{
    // Access arguments
    $location = $arguments['location'] ?? null;

    // Access context
    $sessionId = $context->getSessionId();
    $previousValue = $context->getState('some_key');

    // Implement tool logic
    $result = [
        'status' => 'success',
        'temperature' => 25,
        'condition' => 'sunny',
        'location' => $location,
    ];

    // Must return JSON string
    return json_encode($result);
}

โš ๏ธ Remember: Always return a JSON-encoded string! The LLM expects structured data it can understand.

๐Ÿง  Working with AgentContext

The AgentContext is your tool's memory bank! It lets you access session info, store state between calls, and maintain context across conversations. ๐Ÿ’พ

Using AgentContext
public function execute(array $arguments, AgentContext $context): string
{
    // Get session ID
    $sessionId = $context->getSessionId();

    // Access state
    $previousOrder = $context->getState('last_order_id');

    // Store state for future use
    $context->setState('last_order_id', $orderId);

    // Access user information if available
    $userId = $context->getState('user_id');
    $userEmail = $context->getState('user_email');

    // Your tool logic here...

    return json_encode(['status' => 'success']);
}

๐Ÿ“ Reading State

Use getState() to retrieve previously stored values

๐Ÿ’พ Writing State

Use setState() to persist data for future tool calls

๐Ÿ”— Connecting Tools to Agents

Ready to give your agent superpowers? Just add your tools to the agent's $tools array and watch the magic happen! โœจ

app/Agents/CustomerSupportAgent.php
class CustomerSupportAgent extends BaseLlmAgent
{
    /** @var array> */
    protected array $tools = [
        OrderLookupTool::class,
        RefundProcessorTool::class,
        TicketCreatorTool::class,
        EmailSenderTool::class,
    ];
}

๐Ÿ’ก Pro tip: Tools are automatically instantiated and made available to the LLM. Just list them and Vizra handles the rest!

๐Ÿš€ Advanced Tool Features

Let's explore some powerful patterns for building sophisticated tools! ๐Ÿ’ช

๐Ÿ—œ๏ธ Database Queries

Connect your tools directly to your database for powerful data operations:

Database Search Tool
class CustomerSearchTool implements ToolInterface
{
    public function execute(array $arguments, AgentContext $context): string
    {
        $customers = Customer::query()
            ->where('name', 'like', "%{$arguments['query']}%")
            ->orWhere('email', 'like', "%{$arguments['query']}%")
            ->limit(10)
            ->get();

        return json_encode([
            'status' => 'success',
            'customers' => $customers->map(fn($c) => [
                'id' => $c->id,
                'name' => $c->name,
                'email' => $c->email,
            ])->toArray(),
        ]);
    }
}

๐ŸŒ API Integration

Connect to external APIs and bring real-world data into your conversations:

External API Tool
class WeatherApiTool implements ToolInterface
{
    public function execute(array $arguments, AgentContext $context): string
    {
        try {
            $response = Http::get('https://api.weather.com/v1/current', [
                'location' => $arguments['location'],
                'api_key' => config('services.weather.key'),
            ]);

            return json_encode([
                'status' => 'success',
                'weather' => $response->json(),
            ]);
        } catch (Exception $e) {
            return json_encode([
                'status' => 'error',
                'message' => 'Failed to fetch weather: ' . $e->getMessage(),
            ]);
        }
    }
}

๐Ÿ“ File Operations

Handle file uploads, downloads, and processing with ease:

File Handler Tool
class FileUploaderTool implements ToolInterface
{
    public function definition(): array
    {
        return [
            'name' => 'file_uploader',
            'description' => 'Upload a file from base64 content',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'file_content' => [
                        'type' => 'string',
                        'description' => 'Base64 encoded file content',
                    ],
                    'filename' => [
                        'type' => 'string',
                        'description' => 'Name for the file',
                    ],
                ],
                'required' => ['file_content', 'filename'],
            ],
        ];
    }

    public function execute(array $arguments, AgentContext $context): string
    {
        $content = base64_decode($arguments['file_content']);
        $path = Storage::put('uploads/' . $arguments['filename'], $content);

        return json_encode([
            'status' => 'success',
            'file_path' => $path,
            'size' => strlen($content),
        ]);
    }
}

๐Ÿ›ก๏ธ Error Handling & Validation

Build bulletproof tools with proper validation and error handling! Your agents will thank you. ๐Ÿ™

โœ… Input Validation

Always validate your inputs - it's the first line of defense against errors:

Input Validation Example
public function execute(array $arguments, AgentContext $context, AgentMemory $memory): string
{
    // Validate inputs
    $validator = Validator::make($arguments, [
        'email' => 'required|email',
        'amount' => 'required|numeric|min:0|max:10000',
    ]);

    if ($validator->fails()) {
        return json_encode([
            'status' => 'error',
            'message' => 'Invalid parameters: ' . $validator->errors()->first(),
        ]);
    }
    
    // Store validated information
    $memory->addFact("User email: {$arguments['email']}", 1.0);
    $memory->addLearning("User requested transaction of amount: {$arguments['amount']}");

    // Proceed with validated data
    return json_encode(['status' => 'success']);
}

๐Ÿ‘ค User Context Access

Check for user authentication and access user-specific data safely:

User Context Validation
public function execute(array $arguments, AgentContext $context, AgentMemory $memory): string
{
    // Check if user context is available
    $userId = $context->getState('user_id');
    if (!$userId) {
        return json_encode([
            'status' => 'error',
            'message' => 'User authentication required',
        ]);
    }

    // Get user data from context
    $userData = $context->getState('user_data');
    $userEmail = $context->getState('user_email');
    
    // Store user-specific information
    if ($userEmail && !$memory->getFacts()->contains('content', "User email: {$userEmail}")) {
        $memory->addFact("User email: {$userEmail}", 1.0);
    }

    // Process with user context
    return json_encode(['status' => 'success']);
}

๐Ÿง  Tools with Memory Access

โœจ Every Tool Gets Memory Access!

All tools now receive the agent's memory as a third parameter. Build personalized experiences by reading and writing to memory! ๐ŸŽฏ

The execute method now includes AgentMemory:

app/Tools/UserProfileTool.php
<?php

namespace App\Tools;

use Vizra\VizraADK\Contracts\ToolInterface;
use Vizra\VizraADK\System\AgentContext;
use Vizra\VizraADK\Memory\AgentMemory;

class UserProfileTool implements ToolInterface
{
    public function definition(): array
    {
        return [
            'name' => 'manage_user_profile',
            'description' => 'Update or retrieve user profile information from memory',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'action' => [
                        'type' => 'string',
                        'description' => 'Action to perform',
                        'enum' => ['update_fact', 'add_preference', 'get_profile']
                    ],
                    'key' => ['type' => 'string'],
                    'value' => ['type' => 'string']
                ],
                'required' => ['action']
            ]
        ];
    }
    
    public function execute(
        array $arguments, 
        AgentContext $context, 
        AgentMemory $memory  // Now included in all tools!
    ): string {
        switch ($arguments['action']) {
            case 'update_fact':
                $memory->addFact(
                    "{$arguments['key']}: {$arguments['value']}", 
                    1.0
                );
                return json_encode(['success' => true]);
                
            case 'add_preference':
                $memory->addPreference(
                    $arguments['value'], 
                    $arguments['key'] ?? 'general'
                );
                return json_encode(['success' => true]);
                
            case 'get_profile':
                return json_encode([
                    'summary' => $memory->getSummary(),
                    'facts' => $memory->getFacts()->pluck('content'),
                    'preferences' => $memory->getPreferences()
                ]);
        }
    }
}

๐Ÿ”ง Memory Methods Available

  • โ€ข
    addFact() - Store immutable facts
  • โ€ข
    addLearning() - Track insights
  • โ€ข
    addPreference() - Store preferences
  • โ€ข
    updateSummary() - Update user profile

๐ŸŽฏ Use Cases

  • โ€ข
    Update user preferences from form submissions
  • โ€ข
    Store discovered facts during conversations
  • โ€ข
    Build comprehensive user profiles over time
  • โ€ข
    Sync memory across different tools

๐Ÿ’ก Pro Tip: Simple Memory Usage

Every tool automatically receives the agent's memory! Use it to store learnings, facts, and preferences. The memory persists across sessions, enabling truly personalized experiences.

๐Ÿงช Testing Your Tools

Great tools deserve great tests! Here's how to ensure your tools work perfectly every time ๐ŸŽฏ

tests/Tools/OrderLookupToolTest.php
class OrderLookupToolTest extends TestCase
{
    public function test_finds_existing_order()
    {
        $order = Order::factory()->create();
        $tool = new OrderLookupTool();
        $context = new AgentContext('test-session');

        $result = $tool->execute(
            ['order_id' => $order->id],
            $context
        );

        $data = json_decode($result, true);
        $this->assertEquals('success', $data['status']);
        $this->assertEquals($order->id, $data['order_id']);
    }

    public function test_handles_missing_order()
    {
        $tool = new OrderLookupTool();
        $context = new AgentContext('test-session');

        $result = $tool->execute(
            ['order_id' => 'invalid'],
            $context
        );

        $data = json_decode($result, true);
        $this->assertEquals('error', $data['status']);
        $this->assertStringContainsString('not found', $data['message']);
    }
}

๐Ÿ” Testing tip: Test both success paths and error conditions. Your future self will appreciate it!

๐ŸŽ† Complete Example: Refund Processor

Let's put it all together with a real-world example that shows validation, error handling, and business logic! ๐Ÿ’ผ

app/Tools/RefundProcessorTool.php
<?php

namespace App\Tools;

use Vizra\VizraADK\Contracts\ToolInterface;
use Vizra\VizraADK\System\AgentContext;
use App\Models\Order;
use App\Services\RefundService;
use Illuminate\Support\Facades\Validator;

class RefundProcessorTool implements ToolInterface
{
    public function __construct(
        protected RefundService $refunds
    ) {}

    public function definition(): array
    {
        return [
            'name' => 'process_refund',
            'description' => 'Process a refund for an order',
            'parameters' => [
                'type' => 'object',
                'properties' => [
                    'order_id' => [
                        'type' => 'string',
                        'description' => 'The order ID to refund',
                    ],
                    'amount' => [
                        'type' => 'number',
                        'description' => 'Refund amount (optional for partial refunds)',
                        'minimum' => 0,
                    ],
                    'reason' => [
                        'type' => 'string',
                        'description' => 'Reason for refund',
                    ],
                ],
                'required' => ['order_id', 'reason'],
            ],
        ];
    }

    public function execute(array $arguments, AgentContext $context): string
    {
        // Validate inputs
        $validator = Validator::make($arguments, [
            'order_id' => 'required|string',
            'amount' => 'nullable|numeric|min:0',
            'reason' => 'required|string',
        ]);

        if ($validator->fails()) {
            return json_encode([
                'status' => 'error',
                'message' => 'Validation failed: ' . $validator->errors()->first(),
            ]);
        }

        // Check user authorization
        $userId = $context->getState('user_id');
        if (!$userId) {
            return json_encode([
                'status' => 'error',
                'message' => 'User authentication required',
            ]);
        }

        try {
            $order = Order::findOrFail($arguments['order_id']);

            // Verify order belongs to user
            if ($order->user_id !== $userId) {
                return json_encode([
                    'status' => 'error',
                    'message' => 'Order not found',
                ]);
            }

            $refund = $this->refunds->process(
                $order,
                $arguments['amount'] ?? $order->total,
                $arguments['reason']
            );

            return json_encode([
                'status' => 'success',
                'refund_id' => $refund->id,
                'amount' => $refund->amount,
                'refund_status' => $refund->status,
                'message' => 'Refund processed successfully',
            ]);

        } catch (\Exception $e) {
            return json_encode([
                'status' => 'error',
                'message' => 'Failed to process refund: ' . $e->getMessage(),
            ]);
        }
    }
}

๐Ÿ’ก Tool Best Practices

โœ…

Single Responsibility

Each tool should do one thing and do it well

โœ…

Input Validation

Always validate parameters before processing

โœ…

Clear Error Messages

Help the LLM understand what went wrong

โœ…

Descriptive Naming

Use names that clearly describe the tool's purpose

โœ…

Error Handling

Gracefully handle exceptions and edge cases

โœ…

Rate Limiting

Protect expensive operations from abuse

โœ…

Thorough Testing

Test success paths and error conditions

โœ…

JSON Responses

Always return properly formatted JSON strings

Ready for Professional AI Agent Evaluation? ๐Ÿš€

Evaluate and debug your Vizra ADK agents with professional cloud tools. Get early access to Vizra Cloud and be among the first to experience advanced evaluation and trace analysis at scale.

Cloud evaluation runs
Trace visualization
Team collaboration

Join other developers already on the waitlist. No spam, just launch updates.