laravel-neuro/ai-sdk-agent-logger

Logging middleware for Laravel AI SDK agents - can utilize the Log facade or the database.

Maintainers

Package info

github.com/LaravelNeuro/AiSdkAgentLoggingMiddleware

pkg:composer/laravel-neuro/ai-sdk-agent-logger

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-07-24 17:03 UTC

This package is auto-updated.

Last update: 2026-07-24 17:07:14 UTC


README

Logging and token-cost estimation middleware for the Laravel AI SDK.

Provides a single, unified AgentLogger middleware that you attach to any AI SDK agent. Choose exactly what to log via AgentLog enums — prompt input, response output, token usage with cost estimates, or any combination. Logs to either Laravel's Log facade or a database table, with configurable per-model pricing.

Requirements

  • PHP 8.3+
  • Laravel 13.x
  • laravel/ai SDK

Installation

composer require laravel-neuro/ai-sdk-agent-logger

Publish the config:

php artisan vendor:publish --tag=ai-agent-logger-config

If using the database driver, publish and run migrations:

php artisan vendor:publish --tag=ai-agent-logger-migrations
php artisan migrate

Quick Start

Attach the middleware to any agent implementing HasMiddleware:

use LaravelNeuro\AiSdk\Enums\AgentLog;
use LaravelNeuro\AiSdk\Middleware\AgentLogger;

class ResearchAgent implements Agent, HasMiddleware //,...
{
    //...
    public function middleware(): array
    {
        return [
            new AgentLogger('Research Agent', AgentLog::Prompt, AgentLog::Response, AgentLog::Usage),
        ];
    }
}

That's it. Every prompt and response through this agent is now logged with token usage and estimated cost.

What to Log

Pass any combination of AgentLog enums — order doesn't matter, duplicates are ignored:

// Just log prompts
new AgentLogger('Chat Agent', AgentLog::Prompt)

// Log responses and token costs, skip prompt content
new AgentLogger('Cost Tracker', AgentLog::Response, AgentLog::Usage)

// Name is optional — skip it for a quick anonymous setup
new AgentLogger(AgentLog::Prompt, AgentLog::Response)

// Everything
new AgentLogger('Full Trace Agent', AgentLog::Prompt, AgentLog::Response, AgentLog::Usage)
Enum When it fires What it captures
AgentLog::Prompt Before the provider call (synchronous) Agent name, prompt input, timestamp
AgentLog::Response After the response resolves (in .then()) Agent name, response text, timestamp
AgentLog::Usage After the response resolves (in .then()) Provider, model, token usage breakdown, estimated cost

Drivers

Log Driver (default)

Writes structured log entries through Laravel's Log facade. Configure a dedicated channel if desired:

AI_AGENT_LOGGER_DRIVER=log
AI_AGENT_LOGGER_CHANNEL=ai

Output looks like:

[Research Agent] Prompt received. {"prompt": "Summarize this document..."}
[Research Agent] Response received. {"text": "Here is the summary..."}
[Research Agent] Token usage data: {"usage": {"prompt_tokens": 1200, "completion_tokens": 450}}
 => total prompt expense: 0.011$

Database Driver

Persists to two UUID-keyed tables — agent_prompt_logs and agent_response_logs — with a foreign key linking responses to their prompts. Token usage is stored as JSON, cost as a decimal.

AI_AGENT_LOGGER_DRIVER=database
AI_AGENT_LOGGER_CONNECTION=null  # uses default connection

The database driver is idempotent: regardless of which enum combinations you enable or what order they run in, each invocation produces at most one prompt row and one response row. logResponse creates the row; logUsage updates it with usage and cost data rather than creating a duplicate.

Cost Estimation

Pricing is defined per-provider, per-model in the published config file. Rates are specified per 1 million tokens in USD.

Some sample pricing for the openai provider are included, but will not be kept up-to-date. If you want to get cost estimations for your agents, you need to fill in the current pricing for the models your application utilizes.

'pricing' => [
    'openai' => [
        'updated_at' => '2026-07-14',
        'models' => [
            'gpt-5.4-mini' => [
                'prompt_tokens'            => 0.75,
                'completion_tokens'        => 4.50,
                'cache_write_input_tokens' => 0,
                'cache_read_input_tokens'  => 0,
                'reasoning_tokens'         => 4.50,
            ],
            // ...
        ],
    ],
    'anthropic' => [
        'updated_at' => '2026-07-14',
        'models' => [
            'claude-sonnet-4-5' => [
                // ...
            ],
        ],
    ],
    // ...
],

The CostCalculator automatically:

  • Normalizes model names — strips date suffixes (e.g. gpt-4o-2026-07-14gpt-4o) before lookup.
  • Returns null gracefully — if a provider or model isn't in the pricing config, cost is logged as "No pricing information available" rather than throwing.

Note: Model names containing dots (like gpt-5.4-mini) are handled correctly — the calculator fetches the models array via config() then uses plain array access for the final key lookup, bypassing Laravel's dot-notation parser.

Configuration

The full published config at config/ai-agent-logger.php:

return [

    'driver' => env('AI_AGENT_LOGGER_DRIVER', 'log'),

    'channel' => env('AI_AGENT_LOGGER_CHANNEL', null),

    'connection' => env('AI_AGENT_LOGGER_CONNECTION', null),

    'capture' => [
        'prompt_input'    => true,   // store prompt text
        'response_output' => true,   // store response text
        'token_usage'     => true,   // store token counts
        'cost_estimate'   => true,   // store calculated cost
        'duration'        => true,   // store request duration
        'invocation_id'   => true,   // store SDK invocation ID
    ],

    'pricing' => [
        // ...see above...
    ],

];

Set any capture key to false to omit that field from logs or database rows — useful for compliance or storage concerns.

Nested Sub-Agents

When an agent has sub-agents as tools and both implement AgentLogger, the middleware generates a unique correlation ID per handle() call. Each sub-agent invocation gets its own ID, so prompt↔response linking is automatically isolated across nesting levels — no manual stack management or context cleanup required.

License

MIT