Tools (also known as function calling) allow your AI agents to interact with external systems, APIs, and services, greatly expanding their capabilities beyond simple text generation.

Tool Configuration

Tools in LarAgent can be configured using these properties in your Agent class:
/** @var bool - Controls whether tools can be executed in parallel */
protected $parallelToolCalls;

/** @var array - List of tool classes to be registered with the agent */
protected $tools = [];
You can set $parallelToolCalls to null if you want to remove it from the request, as some models (o1) do not support parallel tool calls.

Creating Tools

There are three ways to create and register tools in your agent:

1. Using the Tool Attribute

The simplest approach is using the #[Tool] attribute to transform your agent’s methods into tools:
use LarAgent\Attributes\Tool;

#[Tool('Get the current weather in a given location')]
public function weatherTool($location, $unit = 'celsius')
{
    return 'The weather in '.$location.' is '.'20'.' degrees '.$unit;
}

The agent will automatically register the tool with the given description and extract method information, including parameter names and types.
You can add tools without properties (= Method without parameters)

Using Enum Types with Tools

You can use PHP Enums to provide the AI with a specific set of options to choose from, as well as provide separate descriptions for each property (argument):
// app/Enums/Unit.php
namespace App\Enums;

enum Unit: string
{
    case CELSIUS = 'celsius';
    case FAHRENHEIT = 'fahrenheit';
}

// app/AiAgents/WeatherAgent.php
use LarAgent\Attributes\Tool;
use App\Enums\Unit;

// ...

#[Tool(
    'Get the current weather in a given location',
    [
        'unit' => 'Unit of temperature',
        'location' => 'The city and state, e.g. San Francisco, CA'
    ]
)]
public static function weatherToolForNewYork(Unit $unit, $location = 'New York')
{
    return WeatherService::getWeather($location, $unit->value);
}
It’s recommended to use the #[Tool] attribute with static methods if there’s no need for the agent instance ($this).

2. Using the registerTools Method

This method allows you to programmatically create and register tools using the LarAgent\Tool class:
use LarAgent\Tool;

public function registerTools()
{
    $user = auth()->user();
    return [
        Tool::create("user_location", "Returns user's current location")
             ->setCallback(function () use ($user) {
                  return $user->location()->city;
             }),
        Tool::create("get_current_weather", "Returns the current weather in a given location")
             ->addProperty("location", "string", "The city and state, e.g. San Francisco, CA")
             ->setCallback("getWeather"),
    ];
}
setCallback method accepts any php callable, such as a function name, a closure, or a class method.

3. Using Tool Classes

For complex tools, you can create dedicated tool classes and add them to the $tools property:
protected $tools = [
    WeatherTool::class,
    LocationTool::class
];

Example Tool Class

Tool creation artisan command is comming soon…
class WeatherTool extends LarAgent\Tool
{
    protected string $name = 'get_current_weather';

    protected string $description = 'Get the current weather in a given location';

    protected array $properties = [
        'location' => [
            'type' => 'string',
            'description' => 'The city and state, e.g. San Francisco, CA',
        ],
        'unit' => [
            'type' => 'string',
            'description' => 'The unit of temperature',
            'enum' => ['celsius', 'fahrenheit'],
        ],
    ];

    protected array $required = ['location'];

    protected array $metaData = ['sent_at' => '2024-01-01'];

    public function execute(array $input): mixed
    {
        // Call the weather API
        return 'The weather in '.$input['location'].' is '.rand(10, 60).' degrees '.$input['unit'];
    }
}

Tool choice

You can set the tool choice for your agent using the following methods:
// Disable tools for this specific call:
WeatherAgent::for('test_chat')->toolNone()->respond('What is my name?');

// Require at least 1 tool call for this specific call:
WeatherAgent::for('test_chat')->toolRequired()->respond('Who is president of US?');

// Force specific tool to be used for this specific call:
WeatherAgent::for('test_chat')->forceTool('weatherToolForNewYork')->respond('What is weather in New York?');
forceTool method requires tool’s name as a parameter.
toolRequired & forceTool is set only at the first call, after that it will automatically switched to ‘auto’ avoiding infinite loop.
If tools are registered, default value is ‘auto’, otherwise it’s ‘none’.
protected $toolChoice = 'auto';

Phantom Tools 👻

Phantom Tools are dynamically registered tools that are not executed on the LarAgent side, but instead returns ToolCallMessage
use LarAgent\PhantomTool;

// ...

// Create a Phantom tool with properties and custom callback
$PhantomTool = PhantomTool::create('Phantom_tool', 'Get the current weather in a given location')
            ->addProperty('location', 'string', 'The city and state, e.g. San Francisco, CA')
            ->setRequired('location')
            ->setCallback("PhantomTool");

// Register the Phantom tool with the agent
$agent->withTool($PhantomTool);
Phantom Tools are particularly useful when:
  • You need to integrate with external services dynamically
  • You want to handle tool execution outside of LarAgent
  • You need to make tool registration/execution available from API
Phantom Tools follow the same interface as regular tools but instead of automatical execution, they return ToolCallMessage instance, providing more flexibility in terms of when and how they are executed.

Chainable Tool Methods

You can dynamically add or remove tools during runtime using withTool and removeTool methods: Add tool with instance
$tool = Tool::create('test_tool', 'Test tool')->setCallback(fn () => 'test');
$agent->withTool($tool);
Add tool with predefined tool class
$agent->withTool(WeatherTool::class);
Remove tool by name
$agent->removeTool('get_current_weather');
Remove tool by instance
$tool = Tool::create('test_tool', 'Test tool')->setCallback(fn () => 'test');
$agent->withTool($tool);
if (!$needsTool) {
    $agent->removeTool($tool);
}
Remove tool by class name
$agent->removeTool(WeatherTool::class);
Set toolChoice property
// @param  string|array|null  $toolChoice  Tool choice configuration
$agent->setToolChoice('none');
Enable/Disable parallel tool calls
// @param bool|null $parallel Parallel tool calls configuration
$agent->parallelToolCalls(true);

Best Practices

Do create separate tool classes for complex functionality that might be reused
Do provide clear, descriptive names and parameter descriptions
Do use Enums when you need to restrict the AI to specific options
Don’t create tools with ambiguous functionality or unclear parameter requirements Don’t expose sensitive operations without proper validation and security checks