Skip to main content

What Are Toolboxes?

Toolboxes let you group related tools into logical collections with built-in authorization support. Think of them as “tool bundles” that can be enabled or disabled based on user permissions, subscription tiers, or any other context.

Organized Tools

Group related tools together for cleaner agent definitions

Built-in Authorization

Use Laravel Gates and Policies at both toolbox and tool levels

Dynamic Loading

Tools are loaded on-demand based on user context

Runtime Flexibility

Add or remove toolboxes at runtime based on conditions

Using Toolboxes in Agents

The easiest way to use toolboxes is to declare them in your agent’s $toolboxes property:
app/Agents/CustomerAgent.php
<?php

namespace App\Agents;

use App\Toolboxes\CustomerSupportToolbox;
use App\Toolboxes\OrderManagementToolbox;
use Vizra\VizraADK\Agents\BaseLlmAgent;

class CustomerAgent extends BaseLlmAgent
{
    protected string $name = 'customer_agent';
    protected string $description = 'Helps customers with support and orders';
    protected string $instructions = 'You are a helpful customer support agent.';

    protected array $toolboxes = [
        CustomerSupportToolbox::class,
        OrderManagementToolbox::class,
    ];

    // You can also include individual tools alongside toolboxes
    protected array $tools = [
        GeneralInfoTool::class,
    ];
}
When the agent loads, it automatically:
  1. Checks toolbox-level authorization for each toolbox
  2. Filters individual tools based on per-tool gates/policies
  3. Applies any conditional inclusion logic
  4. Merges authorized tools with the agent’s direct tools

Runtime Toolbox Management

You can add or remove toolboxes dynamically at runtime:
Adding/Removing Toolboxes at Runtime
// Add a toolbox based on user tier
if ($user->isPremium()) {
    $agent->addToolbox(PremiumFeaturesToolbox::class);
}

// Remove a toolbox if certain conditions aren't met
if (!$user->hasVerifiedEmail()) {
    $agent->removeToolbox(SensitiveOperationsToolbox::class);
}

// Force reload tools after changes
$agent->forceReloadTools();

Checking Toolbox Status

Toolbox Inspection Methods
// Check if a toolbox is registered
if ($agent->hasToolbox(AdminToolbox::class)) {
    // ...
}

// Get all registered toolbox classes
$toolboxClasses = $agent->getToolboxes();

// Get loaded toolbox instances (after agent initialization)
$loadedToolboxes = $agent->getLoadedToolboxes();

Creating Your First Toolbox

Generate a new toolbox using the Artisan command:
php artisan vizra:make:toolbox CustomerSupportToolbox
You can also specify options during generation:
# With a Laravel Gate
php artisan vizra:make:toolbox AdminToolbox --gate=admin-access

# With a Laravel Policy
php artisan vizra:make:toolbox PremiumToolbox --policy="App\Policies\SubscriptionPolicy"

# With initial tools
php artisan vizra:make:toolbox OrderToolbox --tools="App\Tools\CreateOrderTool,App\Tools\CancelOrderTool"

Basic Toolbox Structure

app/Toolboxes/CustomerSupportToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\CreateTicketTool;
use App\Tools\SearchKnowledgeBaseTool;
use App\Tools\EscalateIssueTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;

class CustomerSupportToolbox extends BaseToolbox
{
    /**
     * The unique identifier for this toolbox.
     */
    protected string $name = 'customer_support';

    /**
     * Human-readable description of this toolbox.
     */
    protected string $description = 'Tools for customer support operations';

    /**
     * Array of tool class names that belong to this toolbox.
     */
    protected array $tools = [
        CreateTicketTool::class,
        SearchKnowledgeBaseTool::class,
        EscalateIssueTool::class,
    ];
}

Authorization

Toolboxes support a powerful multi-level authorization system using Laravel’s built-in Gates and Policies.

Toolbox-Level Gates

The simplest form of authorization uses a Laravel Gate:
app/Toolboxes/AdminToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\DatabaseQueryTool;
use App\Tools\UserManagementTool;
use App\Tools\SystemConfigTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;

class AdminToolbox extends BaseToolbox
{
    protected string $name = 'admin';
    protected string $description = 'Administrative tools';

    /**
     * Gate name for toolbox-level authorization.
     * The entire toolbox is hidden if the gate fails.
     */
    protected ?string $gate = 'admin-access';

    protected array $tools = [
        DatabaseQueryTool::class,
        UserManagementTool::class,
        SystemConfigTool::class,
    ];
}
Define the gate in your AuthServiceProvider:
app/Providers/AuthServiceProvider.php
use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    Gate::define('admin-access', function ($user) {
        return $user->hasRole('admin');
    });
}

Toolbox-Level Policies

For more complex authorization logic, use a Policy:
app/Toolboxes/PremiumToolbox.php
<?php

namespace App\Toolboxes;

use App\Policies\SubscriptionPolicy;
use App\Tools\AdvancedAnalyticsTool;
use App\Tools\BulkExportTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;

class PremiumToolbox extends BaseToolbox
{
    protected string $name = 'premium';
    protected string $description = 'Premium tier features';

    /**
     * Policy class for toolbox authorization.
     */
    protected ?string $policy = SubscriptionPolicy::class;

    /**
     * The policy ability to check (default is 'use').
     */
    protected ?string $policyAbility = 'accessPremiumFeatures';

    protected array $tools = [
        AdvancedAnalyticsTool::class,
        BulkExportTool::class,
    ];
}
app/Policies/SubscriptionPolicy.php
<?php

namespace App\Policies;

use App\Models\User;

class SubscriptionPolicy
{
    public function accessPremiumFeatures(User $user): bool
    {
        return $user->subscription?->tier === 'premium'
            && $user->subscription->isActive();
    }
}
When both a $gate and $policy are defined, the policy takes precedence. Only one authorization method is checked.

Per-Tool Gates

You can apply fine-grained authorization to individual tools within a toolbox:
app/Toolboxes/FinanceToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\ViewReportsTool;
use App\Tools\CreateInvoiceTool;
use App\Tools\ProcessRefundTool;
use App\Tools\DeleteTransactionTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;

class FinanceToolbox extends BaseToolbox
{
    protected string $name = 'finance';
    protected string $description = 'Financial operations tools';

    /**
     * Toolbox-level gate - user must pass this to see ANY tools.
     */
    protected ?string $gate = 'finance-access';

    protected array $tools = [
        ViewReportsTool::class,
        CreateInvoiceTool::class,
        ProcessRefundTool::class,
        DeleteTransactionTool::class,
    ];

    /**
     * Per-tool gate mappings.
     * Users must pass BOTH the toolbox gate AND the tool gate.
     */
    protected array $toolGates = [
        ProcessRefundTool::class => 'process-refunds',
        DeleteTransactionTool::class => 'delete-transactions',
    ];
}

Per-Tool Policies

For even more control, use policies on individual tools:
Per-Tool Policy Configuration
protected array $toolPolicies = [
    DeleteTransactionTool::class => [TransactionPolicy::class, 'delete'],
    ArchiveRecordsTool::class => [RecordPolicy::class, 'archive'],
];
The authorization hierarchy is:
  1. Toolbox gate/policy - Must pass to see any tools
  2. Per-tool gate - Additional check for specific tools
  3. Per-tool policy - Alternative to per-tool gates
  4. shouldIncludeTool() - Final conditional logic

Conditional Tool Inclusion

For dynamic logic that goes beyond gates and policies, override the shouldIncludeTool() method:
app/Toolboxes/ContextAwareToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\BasicSearchTool;
use App\Tools\AdvancedSearchTool;
use App\Tools\BetaFeatureTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;
use Vizra\VizraADK\System\AgentContext;

class ContextAwareToolbox extends BaseToolbox
{
    protected string $name = 'context_aware';
    protected string $description = 'Tools that adapt to user context';

    protected array $tools = [
        BasicSearchTool::class,
        AdvancedSearchTool::class,
        BetaFeatureTool::class,
    ];

    /**
     * Dynamically include/exclude tools based on context.
     */
    protected function shouldIncludeTool(string $toolClass, AgentContext $context): bool
    {
        // Only include advanced search for power users
        if ($toolClass === AdvancedSearchTool::class) {
            return $context->getState('user_tier') === 'power_user';
        }

        // Include beta features only for users in the beta program
        if ($toolClass === BetaFeatureTool::class) {
            return $context->getState('beta_tester') === true;
        }

        // Include all other tools by default
        return true;
    }
}
Authorized tools are cached per session ID for performance. If context changes mid-session and you need tools to be re-evaluated, call $toolbox->clearCache() or $agent->forceReloadTools().

Real-World Examples

Admin Toolbox with Gate

app/Toolboxes/AdminToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\UserManagementTool;
use App\Tools\SystemSettingsTool;
use App\Tools\ViewAuditLogTool;
use App\Tools\DatabaseQueryTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;

class AdminToolbox extends BaseToolbox
{
    protected string $name = 'admin';
    protected string $description = 'Administrative tools for system management';

    protected ?string $gate = 'admin-panel';

    protected array $tools = [
        UserManagementTool::class,
        SystemSettingsTool::class,
        ViewAuditLogTool::class,
        DatabaseQueryTool::class,
    ];

    // Restrict dangerous tools to super admins only
    protected array $toolGates = [
        DatabaseQueryTool::class => 'database-access',
    ];
}

Multi-Tenant Toolbox

app/Toolboxes/TenantToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\TenantReportsTool;
use App\Tools\TenantSettingsTool;
use App\Tools\CrossTenantSearchTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;
use Vizra\VizraADK\System\AgentContext;

class TenantToolbox extends BaseToolbox
{
    protected string $name = 'tenant';
    protected string $description = 'Multi-tenant management tools';

    protected array $tools = [
        TenantReportsTool::class,
        TenantSettingsTool::class,
        CrossTenantSearchTool::class,
    ];

    protected function shouldIncludeTool(string $toolClass, AgentContext $context): bool
    {
        // Cross-tenant search only for users managing multiple tenants
        if ($toolClass === CrossTenantSearchTool::class) {
            $tenantIds = $context->getState('managed_tenant_ids', []);
            return count($tenantIds) > 1;
        }

        return true;
    }
}

Feature-Flagged Toolbox

app/Toolboxes/ExperimentalToolbox.php
<?php

namespace App\Toolboxes;

use App\Tools\AiSummaryTool;
use App\Tools\VoiceInputTool;
use App\Tools\ImageAnalysisTool;
use Vizra\VizraADK\Toolboxes\BaseToolbox;
use Vizra\VizraADK\System\AgentContext;
use Illuminate\Support\Facades\Feature;

class ExperimentalToolbox extends BaseToolbox
{
    protected string $name = 'experimental';
    protected string $description = 'Experimental features in development';

    protected array $tools = [
        AiSummaryTool::class,
        VoiceInputTool::class,
        ImageAnalysisTool::class,
    ];

    protected function shouldIncludeTool(string $toolClass, AgentContext $context): bool
    {
        // Map tool classes to feature flags
        $featureFlags = [
            AiSummaryTool::class => 'ai-summary',
            VoiceInputTool::class => 'voice-input',
            ImageAnalysisTool::class => 'image-analysis',
        ];

        $flag = $featureFlags[$toolClass] ?? null;

        if ($flag === null) {
            return true;
        }

        // Use Laravel Pennant or similar feature flag system
        $userId = $context->getState('user_id');
        return Feature::for($userId)->active($flag);
    }
}

Best Practices

Group by Domain

Organize tools by business domain (orders, payments, support) rather than technical function

Use Gates for Simple Checks

Gates are perfect for role-based checks. Use policies for complex business logic

Keep Toolboxes Focused

A toolbox should have 3-8 related tools. Split large toolboxes into smaller ones

Prefer Toolbox Auth

Use toolbox-level authorization when possible. Per-tool auth adds complexity
Naming Convention: Use descriptive names ending in Toolbox - e.g., CustomerSupportToolbox, PaymentProcessingToolbox, AdminToolbox.

API Reference

BaseToolbox Properties

PropertyTypeDescription
$namestringUnique identifier for the toolbox
$descriptionstringHuman-readable description
$toolsarrayArray of tool class names
$gate?stringLaravel Gate name for toolbox auth
$policy?stringLaravel Policy class for toolbox auth
$policyAbility?stringPolicy ability to check (default: 'use')
$toolGatesarrayPer-tool gate mappings
$toolPoliciesarrayPer-tool policy mappings

BaseToolbox Methods

MethodDescription
name(): stringGet the toolbox name
description(): stringGet the toolbox description
tools(): arrayGet the array of tool class names
authorize(AgentContext $context): boolCheck toolbox-level authorization
authorizedTools(AgentContext $context): arrayGet instantiated, authorized tools
getGate(): ?stringGet the configured gate name
getPolicy(): ?stringGet the configured policy class
getToolGates(): arrayGet per-tool gate mappings
clearCache(): voidClear the authorized tools cache

Agent Toolbox Methods

MethodDescription
addToolbox(string $toolboxClass): staticAdd a toolbox at runtime
removeToolbox(string $toolboxClass): staticRemove a toolbox
getToolboxes(): arrayGet registered toolbox class names
hasToolbox(string $toolboxClass): boolCheck if toolbox is registered
getLoadedToolboxes(): arrayGet loaded toolbox instances
forceReloadTools(): voidClear cache and reload all tools

Artisan Command

php artisan vizra:make:toolbox {name} [options]

Options:
  -g, --gate=GATE        Laravel Gate name for authorization
  -p, --policy=POLICY    Laravel Policy class for authorization
  -t, --tools=TOOLS      Comma-separated tool class names