Create reusable tool classes for complex functionality or build tools dynamically at runtime using the fluent API.
While the #[Tool] attribute is recommended for most use cases, Tool Classes and Inline Tools offer additional flexibility for reusable or dynamically generated tools.
namespace App\AiTools;use LarAgent\Tool;use LarAgent\Core\Abstractions\DataModel;class WeatherTool extends Tool{ protected string $name = 'get_weather'; protected string $description = 'Get the current weather for a location'; protected array $properties = [ 'location' => [ 'type' => 'string', 'description' => 'The city and state, e.g. San Francisco, CA', ], 'unit' => [ 'type' => 'string', 'description' => 'Temperature unit', 'enum' => ['celsius', 'fahrenheit'], ], ]; protected array $required = ['location']; protected function handle(array|DataModel $input): mixed { $location = $input['location']; $unit = $input['unit'] ?? 'celsius'; return WeatherService::get($location, $unit); }}
The handle() method replaces execute() for class-based tools from v1.2. It provides automatic DataModel and Enum conversion. The execute() method still works for backward compatibility.
Define your entire tool schema using a DataModel class:
use LarAgent\Tool;use LarAgent\Core\Abstractions\DataModel;class TaskDataModel extends DataModel{ public string $title; public int $estimatedHours; public ?string $description = null;}class CreateTaskTool extends Tool{ protected string $name = 'create_task'; protected string $description = 'Create a new task'; // Automatically populates all properties from TaskDataModel protected ?string $dataModelClass = TaskDataModel::class; protected function handle(array|DataModel $input): mixed { // $input is already a TaskDataModel instance! $task = $input; return "Task '{$task->title}' created with {$task->estimatedHours} hours."; }}
Use addProperty() with a DataModel class as the type:
use LarAgent\Tool;$tool = Tool::create('schedule_meeting', 'Schedule a meeting') ->addProperty('title', 'string', 'Meeting title') ->addProperty('attendee', PersonDataModel::class) // DataModel as type! ->addProperty('location', AddressDataModel::class) // DataModel as type! ->setRequired(['title', 'attendee', 'location']) ->setCallback(function (string $title, PersonDataModel $attendee, AddressDataModel $location) { return "Meeting '{$title}' scheduled with {$attendee->name} at {$location->city}"; });
Or use addDataModelAsProperties() to use an entire DataModel as your tool’s input:
use LarAgent\Tool;use LarAgent\Core\Abstractions\DataModel;class TaskDataModel extends DataModel{ public string $title; public int $estimatedHours; public ?string $description = null;}$tool = Tool::create('create_task', 'Create a task') ->addDataModelAsProperties(TaskDataModel::class) ->setCallback(function (TaskDataModel $task) { return "Task '{$task->title}' created with {$task->estimatedHours} hours."; });