> ## Documentation Index
> Fetch the complete documentation index at: https://docs.laragent.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Classes & Inline Tools

> Create reusable tool classes for complex functionality or build tools dynamically at runtime using the fluent API.

<Note>
  While the [#\[Tool\] attribute](/v1/tools/attribute-tools) is recommended for most use cases, Tool Classes and Inline Tools offer additional flexibility for reusable or dynamically generated tools.
</Note>

## Tool Classes

Tool classes are standalone PHP classes that encapsulate tool logic. They're ideal for:

* Complex tools with extensive logic
* Tools shared across multiple agents
* Tools requiring their own dependencies or configuration

### Creating a Tool Class

```php theme={null}
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);
    }
}
```

<Info>
  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.
</Info>

### Registering Tool Classes

Add tool classes to the `$tools` property in your agent:

```php theme={null}
class WeatherAgent extends Agent
{
    protected $tools = [
        \App\Tools\WeatherTool::class,
        \App\Tools\LocationTool::class,
    ];
}
```

Or register them in the `registerTools()` method by instantiating:

```php theme={null}
public function registerTools()
{
    return [
        new \App\AiTools\WeatherTool(),
        new \App\AiTools\LocationTool(),
    ];
}
```

Or add them at runtime:

```php theme={null}
$agent->withTool(WeatherTool::class);
// or
$agent->withTool(new WeatherTool());
```

### Tool Class Properties

| Property          | Type      | Description                                       |
| ----------------- | --------- | ------------------------------------------------- |
| `$name`           | `string`  | Unique identifier for the tool                    |
| `$description`    | `string`  | Description shown to the LLM                      |
| `$properties`     | `array`   | Parameter definitions with types and descriptions |
| `$required`       | `array`   | List of required parameter names                  |
| `$dataModelClass` | `?string` | DataModel class to use as the tool's input schema |
| `$metaData`       | `array`   | Optional metadata (not sent to LLM)               |

### Property Definitions

Properties are OpenAPI compatible schemas. Each property in `$properties` can have:

```php theme={null}
protected array $properties = [
    'param_name' => [
        'type' => 'string',           // string, number, integer, boolean, array, object
        'description' => 'Help text',
        'enum' => ['a', 'b', 'c'],    // Optional: restrict to specific values
    ],
];
```

### Using DataModel as Input Schema

Define your entire tool schema using a DataModel class:

```php theme={null}
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.";
    }
}
```

### DataModel in Properties Array

Mix DataModel classes directly in your `$properties` array:

```php theme={null}
class PersonDataModel extends DataModel
{
    public string $name;
    public string $email;
}

class AddressDataModel extends DataModel
{
    public string $street;
    public string $city;
}

class ScheduleMeetingTool extends Tool
{
    protected string $name = 'schedule_meeting';
    protected string $description = 'Schedule a meeting';
    
    protected array $properties = [
        'title' => ['type' => 'string'],
        'attendee' => PersonDataModel::class,  // Auto-expanded!
        'location' => AddressDataModel::class, // Auto-expanded!
    ];
    
    protected array $required = ['title', 'attendee', 'location'];
    
    protected function handle(array|DataModel $input): mixed
    {
        // DataModel properties are automatically converted!
        $attendee = $input['attendee'];  // PersonDataModel instance
        $location = $input['location'];  // AddressDataModel instance
        
        return "Meeting '{$input['title']}' scheduled with {$attendee->name}";
    }
}
```

***

## Inline Tools

Inline tools are created programmatically using the fluent `Tool` API. They're ideal for:

* Tools that depend on runtime context (user state, request data)
* Dynamically generated tools based on configuration
* Quick prototyping before extracting to a class

### Creating Inline Tools

Use the `registerTools()` method in your agent:

```php theme={null}
use LarAgent\Tool;

class MyAgent extends Agent
{
    public function registerTools()
    {
        $user = auth()->user();

        return [
            Tool::create('get_user_location', "Get the current user's location")
                ->setCallback(fn() => $user->location->city),

            Tool::create('get_weather', 'Get weather for a location')
                ->addProperty('location', 'string', 'City name')
                ->addProperty('unit', 'string', 'Temperature unit', ['celsius', 'fahrenheit'])
                ->setRequired('location')
                ->setCallback(fn($location, $unit = 'celsius') => 
                    WeatherService::get($location, $unit)
                ),
        ];
    }
}
```

### Fluent API Reference

```php theme={null}
Tool::create(string $name, string $description)
    ->addProperty(string $name, string $type, string $description, ?array $enum = null)
    ->addDataModelAsProperties(string $dataModelClass)
    ->setRequired(string|array $properties)
    ->setCallback(callable $callback);
```

### Using DataModel with Inline Tools

Use `addProperty()` with a DataModel class as the type:

```php theme={null}
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:

```php theme={null}
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.";
    });
```

### Callback Options

The `setCallback()` method accepts any PHP callable, including:

```php theme={null}
// Closure
->setCallback(fn($param) => doSomething($param))

// Function name
->setCallback('myGlobalFunction')

// Class method (array syntax)
->setCallback([$this, 'methodName'])
```

### Runtime Tool Addition

Add inline tools at runtime using `withTool()`:

```php theme={null}
$tool = Tool::create('custom_tool', 'Do something custom')
    ->addProperty('input', 'string', 'The input value')
    ->setCallback(fn($input) => processInput($input));

$response = MyAgent::for('user-123')
    ->withTool($tool)
    ->respond('Use the custom tool');
```

### Context-Aware Tools Example

```php theme={null}
public function registerTools()
{
    $user = auth()->user();
    $tools = [];

    // Always available
    $tools[] = Tool::create('get_time', 'Get current server time')
        ->setCallback(fn() => now()->toIso8601String());

    // User-specific tool
    $tools[] = Tool::create('get_my_orders', 'Get my recent orders')
        ->addProperty('limit', 'integer', 'Number of orders to return')
        ->setCallback(fn($limit = 5) => 
            $user->orders()->latest()->take($limit)->get()->toArray()
        );

    // Permission-based tool
    if ($user->can('view_reports')) {
        $tools[] = Tool::create('get_sales_report', 'Get sales report')
            ->addProperty('period', 'string', 'Time period', ['day', 'week', 'month'])
            ->setCallback(fn($period) => ReportService::sales($period));
    }

    return $tools;
}
```

***

## Choosing the Right Approach

| Approach                                             | Best For                                           |
| ---------------------------------------------------- | -------------------------------------------------- |
| **[#\[Tool\] Attribute](/v1/tools/attribute-tools)** | Most use cases — simple, type-safe, IDE support    |
| **Tool Classes**                                     | Complex, reusable tools with multiple dependencies |
| **Inline Tools**                                     | Dynamic, context-dependent, or quick prototypes    |

<Tip>
  Start with the `#[Tool]` attribute. Use Inline Tools when the tool depends on runtime context.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Attribute Tools" icon="wand-magic-sparkles" href="/v1/tools/attribute-tools">
    The recommended way to create tools.
  </Card>

  <Card title="Tool Configuration" icon="sliders" href="/v1/tools/configuration">
    Configure tool choice and parallel execution.
  </Card>
</CardGroup>
