Skip to main content

What are Macros?

Macros allow you to add custom methods to classes at runtime. This is a powerful extensibility pattern borrowed from Laravel that lets you extend Vizra ADK’s functionality without modifying the core code.

Custom Tracking

Add analytics and tracking to your agents

Third-party Integrations

Integrate with external services seamlessly

Domain Logic

Add business-specific functionality

Reusable Patterns

Create patterns you can use across your app

Supported Classes

The following Vizra ADK classes support macros:
ClassAccessDescription
AgentManagerAgent facadeCentral agent management
AgentBuilderFluent builderAgent configuration and registration
WorkflowManagerWorkflow facadeWorkflow orchestration

Basic Usage

Registering a Macro

Register macros in your AppServiceProvider::boot() method:
app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Vizra\VizraADK\Services\AgentBuilder;
use Vizra\VizraADK\Facades\Agent;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        // Add a tracking macro for analytics
        AgentBuilder::macro('track', function (Model $model) {
            $this->trackedModel = $model;
            return $this; // Return $this for method chaining
        });
    }
}

Using Your Macro

use App\Models\Unit;
use Vizra\VizraADK\Facades\Agent;

// Step 1: Use the macro when registering the agent
Agent::build(CustomerSupportAgent::class)
    ->track(Unit::find(12))
    ->register();

// Step 2: Run the agent using the executor API
$response = CustomerSupportAgent::run('User input')
    ->forUser($user)
    ->go();
Always return $this from your macros to maintain the fluent interface and enable method chaining.

Real-World Examples

Analytics Tracking

Track which models are using AI features:
use Vizra\VizraADK\Services\AgentBuilder;
use Illuminate\Database\Eloquent\Model;

AgentBuilder::macro('track', function (Model $model) {
    $this->trackedModel = $model;
    $this->trackedModelType = get_class($model);
    $this->trackedModelId = $model->getKey();
    return $this;
});

// Usage
Agent::build(MyAgent::class)
    ->track(Unit::find(12))
    ->register();

// Then run the agent
MyAgent::run('User input')
    ->forUser($user)
    ->go();

Conditional Execution

Add conditional logic to your builder:
AgentBuilder::macro('whenCondition', function ($condition, callable $callback) {
    if ($condition) {
        $callback($this);
    }
    return $this;
});

// Usage
$agentName = Agent::define('conditional-agent')
    ->whenCondition($user->isPremium(), function ($builder) {
        $builder->model('gpt-4o');
    })
    ->whenCondition(!$user->isPremium(), function ($builder) {
        $builder->model('gpt-4o-mini');
    })
    ->register();

// Run the defined agent
Agent::named($agentName)->run('User input')->go();

Metadata Tagging

Add metadata for logging or debugging:
AgentBuilder::macro('withTags', function (array $tags) {
    $this->tags = $tags;
    return $this;
});

AgentBuilder::macro('withPriority', function (string $priority) {
    $this->priority = $priority;
    return $this;
});

// Usage
$agentName = Agent::define('support-agent')
    ->withTags(['customer-facing', 'urgent'])
    ->withPriority('high')
    ->register();

// Run the agent
Agent::named($agentName)->run('User input')->go();

Cost Tracking

Track estimated costs for budget monitoring:
AgentBuilder::macro('trackCost', function (string $costCenter) {
    $this->costCenter = $costCenter;
    $this->trackTokenUsage = true;
    return $this;
});

// Usage
Agent::build(AnalyticsAgent::class)
    ->trackCost('DEPT-001')
    ->register();

// Run the agent
AnalyticsAgent::run('User input')->go();

Using Mixins

Mixins allow you to add multiple macros at once by grouping related functionality in a class:
app/Mixins/AnalyticsMixin.php
<?php

namespace App\Mixins;

use Illuminate\Database\Eloquent\Model;

class AnalyticsMixin
{
    public function track()
    {
        return function (Model $model) {
            $this->trackedModel = $model;
            return $this;
        };
    }

    public function recordActivity()
    {
        return function ($activity) {
            $this->activityLog[] = $activity;
            return $this;
        };
    }

    public function getActivityLog()
    {
        return function () {
            return $this->activityLog ?? [];
        };
    }
}
Register the mixin in your service provider:
app/Providers/AppServiceProvider.php
use Vizra\VizraADK\Services\AgentBuilder;
use App\Mixins\AnalyticsMixin;

public function boot(): void
{
    AgentBuilder::mixin(new AnalyticsMixin());
}
Now use all the mixed-in methods:
$agentName = Agent::define('analytics-agent')
    ->track($unit)
    ->recordActivity('agent_created')
    ->recordActivity('agent_configured')
    ->register();

// Run the agent
Agent::named($agentName)->run('User input')->go();
Mixins are ideal when you have a group of related macros that logically belong together, such as analytics, auditing, or domain-specific operations.

Advanced Patterns

Integration with Events

Combine macros with Laravel events for powerful side effects:
use App\Events\AgentTracked;

AgentBuilder::macro('trackWithEvent', function (Model $model) {
    $this->trackedModel = $model;

    // Fire an event when the agent is used
    event(new AgentTracked($model, $this));

    return $this;
});

Dynamic Configuration

Load configuration dynamically from your models:
AgentBuilder::macro('configureFor', function (Model $model) {
    // Load model-specific configuration
    $config = $model->agentConfiguration ?? [];

    if (isset($config['model'])) {
        $this->model($config['model']);
    }

    if (isset($config['instructions'])) {
        $this->instructions($config['instructions']);
    }

    return $this;
});

// Usage
Agent::build(MyAgent::class)
    ->configureFor($tenant)
    ->register();

// Run the agent
MyAgent::run('User input')->go();

Workflow Macros

Add custom workflow types using the WorkflowManager:
use Vizra\VizraADK\Facades\Workflow;
use Vizra\VizraADK\Services\WorkflowManager;

WorkflowManager::macro('retryable', function (string $agentClass, int $maxRetries = 3) {
    $retries = $maxRetries;
    return Workflow::loop($agentClass)
        ->until(function ($result) use (&$retries) {
            return $result->success || $retries-- <= 0;
        });
});

// Usage
$result = Workflow::retryable(UnreliableAgent::class, 5)->go();

Best Practices

Return $this

Always return $this to maintain the fluent interface

Register Early

Register macros in AppServiceProvider::boot()

Descriptive Names

Use clear, descriptive names for your macros

Document Well

Document macros for other developers on your team
Additional tips:
  • Consider scope - Macros are global, so namespace them if needed to avoid conflicts
  • Test your macros - Write tests to ensure macros work as expected
  • Group related macros - Use mixins to organize related functionality

Testing Macros

Test your macros using Pest or PHPUnit:
tests/Feature/MacroTest.php
use Vizra\VizraADK\Services\AgentBuilder;
use Vizra\VizraADK\Facades\Agent;
use App\Models\Unit;

it('can track models with macro', function () {
    AgentBuilder::macro('track', function (Model $model) {
        $this->trackedModel = $model;
        return $this;
    });

    $model = Unit::factory()->create();
    $builder = Agent::define('test-agent')->track($model);

    expect($builder->trackedModel)->toBe($model);
});
The full test suite for macro support is available at tests/Feature/MacroSupportTest.php with 10 comprehensive tests covering all major use cases.

Learn More