laravel-neuro / ai-sdk-agent-logger
Logging middleware for Laravel AI SDK agents - can utilize the Log facade or the database.
Package info
github.com/LaravelNeuro/AiSdkAgentLoggingMiddleware
pkg:composer/laravel-neuro/ai-sdk-agent-logger
Requires
- php: ^8.3
- illuminate/contracts: ^13.0
- illuminate/support: ^13.0
- laravel/ai: *
Requires (Dev)
- laravel/framework: ^13.0
- pestphp/pest: ^3.0
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/aiSDK
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-14→gpt-4o) before lookup. - Returns
nullgracefully — 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 viaconfig()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