Laravel AI v0.11: Trace Agent Runs With Lifecycle Events
Laravel AI #Laravel AI #AI Agents #Laravel Events #Observability #v0.11.0

Laravel AI v0.11: Trace Agent Runs With Lifecycle Events

4 min read Mohamed Said Mohamed Said

What Changed in Laravel AI v0.11.0

Before v0.11.0, the Laravel AI SDK reported only two events for an entire agent run: PromptingAgent at the start and AgentPrompted at the end. A run that made five provider round-trips looked identical to one that made a single call, and a run that threw an exception midway reported nothing at all because AgentPrompted was never dispatched.

Seven pull requests from @pushpak1300, merged as #870–#876, change that completely. Every run now carries one stable ID, and every round-trip and tool call fires start and end events with wall timings.

One Invocation ID for the Whole Run

streamPrompt() already generated a run-level invocation ID, but prompt() did not. Synchronous middleware saw $prompt->invocationId === null while streaming middleware saw a real value. Worse, failover across three providers produced three unrelated IDs for what was logically one run.

prompt() now generates the ID up front, and the provider reuses whatever the caller supplied. Every event carries it as its first constructor argument:

public function __construct(
    public string $invocationId,
    public int $stepNumber,
    // ...
) {}

AgentFailedOver also gained the ID as a required first argument. Any code constructing that event manually needs updating.

Step Events

StartingStep, StepCompleted, and StepFailed fire around every provider round-trip on both the synchronous and streaming paths.

StartingStep carries the full message history sent for that step, the resolved options, stepNumber, and isFinalStep. StepCompleted carries the whole StepResponse plus a float $time in milliseconds — the same unit as QueryExecuted::$time:

use Laravel\Ai\Events\StepCompleted;

Event::listen(StepCompleted::class, function (StepCompleted $event) {
    Log::info('AI step completed', [
        'invocation'     => $event->invocationId,
        'step'           => $event->stepNumber,
        'ms'             => $event->time,
        'prompt_tokens'  => $event->response->usage->promptTokens,
        'finish'         => $event->response->finishReason->value,
    ]);
});

Per-step usage was available before through $response->steps, but only as a bulk payload on the terminal event with no timing attached. Now cost and duration are reported as the run progresses.

StepFailed covers steps that end without a response, carrying the Throwable and the time spent before it threw.

Tool Events

InvokingTool and ToolInvoked already existed, but a shared mutable property on the provider caused the outer ToolInvoked to report the inner call's ID when an agent was invoked as a tool. A RunContext now owns the run identity and dispatches events directly, and each invocation receives its own ID inside executeTool().

The new ToolFailed event closes the gap for tool exceptions:

use Laravel\Ai\Events\ToolFailed;

Event::listen(ToolFailed::class, function (ToolFailed $event) {
    Log::error('AI tool failed', [
        'invocation'      => $event->invocationId,
        'tool_invocation' => $event->toolInvocationId,
        'tool'            => class_basename($event->tool),
        'ms'              => $event->time,
        'exception'       => $event->exception->getMessage(),
    ]);
});

The exception is still rethrown, so existing behavior is unchanged. ToolInvoked also gained a required float $time; update any manual constructor calls.

Run Failure and Sub-Agent Linking

AgentFailed fires once per run after the entire chain is exhausted, carrying the invocation ID, the prompt, and the exception. AgentFailedOver no longer fires for the final provider in a chain — that attempt is now reported as the run's failure instead.

Sub-agents invoked as tools now receive parentInvocationId and parentToolInvocationId on their prompt, correlating nested runs to their parent. The link does not cross a queue boundary; a prompt dispatched with promptOnQueue() starts its own unparented run.

Key Takeaways

  • Every agent run now has a single invocationId shared across prompt() and streamPrompt().
  • StartingStep, StepCompleted, and StepFailed give per-round-trip visibility with millisecond timings.
  • ToolFailed closes the silent-exception gap in tool execution.
  • AgentFailed fires once per failed run; AgentFailedOver no longer fires on the final provider.
  • Sub-agent runs are linked to their parent via parentInvocationId and parentToolInvocationId.
  • If you only need timings and token counts, prefer StepCompleted over StartingStep to avoid serializing the full message history in queued listeners.

Source: Laravel News — Laravel AI: Trace Agent Runs With Lifecycle Events

Found this useful?

Frequently Asked Questions

3 questions
Q01 What is the difference between StartingStep and StepCompleted, and which should I listen to in a queued listener?
StartingStep carries the run's entire message history up to that point, so a queued listener will serialize all messages and attachments. StepCompleted carries only the step's own response plus wall-time and token usage. If you only need timings and token counts, listen for StepCompleted to keep queued payloads small.
Q02 Does AgentFailed fire for every provider failure when failover is configured?
No. With failover configured, a provider that throws a FailoverableException is not terminal, so AgentFailed only fires after the entire provider chain is exhausted. AgentFailedOver also no longer fires for the last provider in the chain; that attempt is reported as the run's failure instead.
Q03 How are sub-agent runs linked to their parent run in Laravel AI v0.11?
When an agent is invoked as a tool, the tool call tracks the current run and tool invocation IDs. Any agent prompted during that tool execution receives parentInvocationId and parentToolInvocationId on its prompt. This works for hand-written tools as well as AgentTool, but the link does not cross a queue boundary.

Continue reading

More Articles

View all