← Laragents 16 / 18

Events

Two, both around a tool call.

use EduLazaro\Laragents\Events\InvokingTool;
use EduLazaro\Laragents\Events\ToolInvoked;

Event::listen(InvokingTool::class, function (InvokingTool $event) {
    $event->tool;        // 'list_properties'
    $event->arguments;   // what the model asked for, already restored
    $event->session;
});

Event::listen(ToolInvoked::class, function (ToolInvoked $event) {
    $event->tool;
    $event->arguments;
    $event->result;      // what it returned
    $event->seconds;     // how long it took
    $event->session;
});

They observe, they do not decide

Nothing you return from a listener changes anything. InvokingTool cannot veto the call and ToolInvoked cannot rewrite the result.

That is on purpose, and it is the difference between an event and a hook. An event that can quietly change what a tool returns turns "read the tool to know what it does" into "read the tool and then find every listener in the application". A tool result is the tool's business.

To actually change something, override the loop:

class MyLoop extends AgentLoop
{
    protected function arguments(string $tool, array $args, ToolContext $context): array
    {
        return [...$args, 'office_id' => $context->require('office')->id];
    }

    protected function afterTool(string $tool, array $result, ToolContext $context): array
    {
        return $result;
    }
}

Those are hooks and they are meant to change things, which is why they are a class you extend rather than a listener somebody can add from anywhere.

What they are for

Timing, mostly. seconds on ToolInvoked is the cheapest way to find out which of your tools is the one making every reply feel slow, and it is per call rather than per turn, so it separates "the model asked for six things" from "one of them takes four seconds".

After that, audit trails. A tool that issues a refund is worth logging with its arguments whether or not your own code logs it, and a listener gets that for every tool at once rather than a line in each.

Agent triggers are the other direction

Do not confuse these with the agent triggers. These two are the package telling you what it did. The events config is you telling the package that something happened in your application worth waking an agent for:

'events' => [
    \App\Events\DocumentUploaded::class => \App\Agents\ResolveDocumentUpload::class,
],

One flows out, the other flows in.