adam-dziuk / laravel-agent-cost
Calculate AI costs for Laravel AI SDK responses using up-to-date model pricing.
Requires
- php: ^8.4
- illuminate/contracts: ^11.0||^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/ai: ^0.11
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^11.0.0||^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
Suggests
- laravel/ai: Required to use AiCost::for() with Laravel AI SDK responses.
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-18 06:19:39 UTC
README
Know what your AI calls actually cost - now you can calculate AI costs for Laravel AI SDK. This package syncs LiteLLM's community-maintained model pricing data and uses it to calculate the USD cost of a Laravel AI SDK response, or of any token counts you already have on hand.
use AdamDziuk\LaravelAgentCost\Facades\AiCost; use App\Ai\Agents\SupportAgent; // any Laravel\Ai\Contracts\Agent $response = SupportAgent::make()->prompt('What is a llama?'); // laravel/ai AiCost::for($response); // 0.0075 AiCost::tokens('gpt-4o', inputTokens: 1000, outputTokens: 500); // 0.0075 AiCost::agent(SupportAgent::make())->monthFrom('2026-01')->total(); // total SupportAgent cost from January 2026 onward
Installation
You can install the package via composer:
composer require adam-dziuk/laravel-agent-cost
Run the migrations to create the agent_cost_records table used by AiCost::agent():
php artisan migrate
You can publish the config file with:
php artisan vendor:publish --tag="agent-cost-config"
This is the contents of the published config file:
return [ // The URL `ai-prices:sync` downloads LiteLLM's pricing data from. 'source_url' => env( 'AGENT_COST_SOURCE_URL', 'https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json' ), // Where the synced pricing data is cached. A `store` of null uses // the application's default cache store. 'cache' => [ 'store' => env('AGENT_COST_CACHE_STORE'), 'key' => 'agent-cost::prices', ], // Manual price overrides, keyed the same way as the LiteLLM pricing // file. Prices are USD per single token. 'overrides' => [ // 'gpt-4o' => [ // 'input_cost_per_token' => 0.0000025, // 'output_cost_per_token' => 0.00001, // ], ], // Automatically records the cost of every laravel/ai agent // invocation, so `AiCost::agent()` can total it up. See "Tracking // the total cost of an agent" below. 'agent_tracking' => [ 'enabled' => env('AGENT_COST_TRACK_AGENTS', true), 'table' => env('AGENT_COST_TABLE', 'agent_cost_records'), ], ];
Before calculating any costs, sync the pricing data at least once:
php artisan ai-prices:sync
If the download or the response fails to parse, the command exits with an error and leaves any previously cached pricing data untouched. You're never left without prices because of a temporary network hiccup. Schedule it to run regularly so pricing stays current, for example in routes/console.php:
Schedule::command('ai-prices:sync')->daily();
Usage
Calculating the cost of a laravel/ai response
If you're using laravel/ai, pass any response that carries usage information straight to AiCost::for(). It understands text, agent, structured, streamed, image, transcription, and embeddings responses:
use AdamDziuk\LaravelAgentCost\Facades\AiCost; use App\Ai\Agents\SupportAgent; // any Laravel\Ai\Contracts\Agent, created with `php artisan make:agent` $response = SupportAgent::make()->prompt('Summarize this document.'); $cost = AiCost::for($response); // e.g. 0.007500
The model and provider are read from the response's own metadata, and prompt, completion, cached, and reasoning tokens are all billed at their correct rates, so there's no need to pass anything else. laravel/ai is not a hard dependency of this package: AiCost::for() only needs it installed when you actually call it with one of its response objects.
Manual calculation
If you already have token counts from somewhere else, calculate the cost directly:
use AdamDziuk\LaravelAgentCost\Facades\AiCost; AiCost::tokens('gpt-4o', inputTokens: 1000, outputTokens: 500); // 0.0075 // Provider-prefixed keys, like LiteLLM uses for Azure, are resolved too. AiCost::tokens('azure/o3', inputTokens: 1000, outputTokens: 500);
Tracking the total cost of an agent
Every time a laravel/ai agent finishes a prompt() or stream() call, this package automatically records its cost to the database, keyed by the agent's class. AiCost::agent() lets you total that up, optionally narrowed down to a date or month range:
use AdamDziuk\LaravelAgentCost\Facades\AiCost; use App\Ai\Agents\SupportAgent; AiCost::agent(SupportAgent::make())->total(); // every recorded invocation of SupportAgent, ever AiCost::agent(SupportAgent::class)->total(); // a class name works too, no instance needed AiCost::agent(SupportAgent::make()) ->dateFrom('2026-01-01') ->dateTo('2026-01-31') ->total(); AiCost::agent(SupportAgent::make()) ->monthFrom('2026-01') ->monthTo('2026-03') ->total();
Costs are tracked per agent class, not per instance, since laravel/ai agents are typically stateless value objects created fresh on every call (SupportAgent::make()).
Run php artisan migrate to create the agent_cost_records table this relies on. Failed invocations (AgentFailed) aren't recorded, since they carry no usage information; invocations for a model with no pricing data are silently skipped rather than breaking the agent call.
If that table name clashes with something you already have, change it before running the migration:
// config/agent-cost.php 'agent_tracking' => [ 'table' => 'my_custom_table_name', // or set AGENT_COST_TABLE in .env ],
If you don't want a permanent log of every agent call, turn tracking off:
// config/agent-cost.php 'agent_tracking' => [ 'enabled' => false, ],
When pricing data is missing
AiCost::tokens() and AiCost::for() throw AdamDziuk\LaravelAgentCost\Exceptions\UnknownModelException when there's no pricing data for a model. Run ai-prices:sync first, or add an override for it. AiCost::for() throws AdamDziuk\LaravelAgentCost\Exceptions\UnsupportedResponseException if you pass it a response that doesn't expose any token usage (audio and reranking responses, for example).
Overriding prices
Use the overrides config to correct a price, or to add pricing for a model that isn't in LiteLLM's file at all (a private deployment, for instance). Overrides are merged on top of the synced data, field by field, so you only need to specify what you want to change:
// config/agent-cost.php 'overrides' => [ 'gpt-4o' => [ 'output_cost_per_token' => 0.000008, // a negotiated rate ], 'my-fine-tuned-model' => [ 'input_cost_per_token' => 0.000003, 'output_cost_per_token' => 0.000006, ], ],
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
- Adam Dziuk
- Pricing data is downloaded from LiteLLM, licensed under the MIT license. This package is not affiliated with or endorsed by LiteLLM.
- All Contributors
License
The MIT License (MIT). Please see License File for more information.