sulimanbenhalim/laravel-ai-cost

Cost reporting and budget guardrails for the Laravel AI SDK.

Maintainers

Package info

github.com/sulimanbenhalim/laravel-ai-cost

pkg:composer/sulimanbenhalim/laravel-ai-cost

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-06-18 13:18 UTC

This package is auto-updated.

Last update: 2026-06-18 15:40:14 UTC


README

Cost reporting and budget guardrails for the Laravel AI SDK.

Turn the raw token counts the SDK already returns into real dollars, and give any agent a hard spend budget that stops it before it blows past the limit. It is purely additive: no changes to the AI SDK, just a service provider, a few value objects, and two event listeners.

Cost & budget dashboard

Installation

composer require sulimanbenhalim/laravel-ai-cost

The package auto-registers. Optionally publish the config:

php artisan vendor:publish --tag=ai-cost-config

Cost reporting

AiCost::for() prices a text or agent response from its usage and model:

use SulimanBenhalim\AiCost\Facades\AiCost;

$response = (new ResearchAgent)->prompt('Summarize Q3 earnings', provider: 'anthropic');

$cost = AiCost::for($response);

$cost->total();      // 0.0032
$cost->format();     // "$0.0032"
$cost->breakdown();  // ['input' => 0.000174, 'output' => 0.00303, ...]

The cost API

Pricing is config driven. The package ships a small default table (USD per 1M tokens); add or override models in config/ai-cost.php, or at runtime:

use SulimanBenhalim\AiCost\Pricing\ModelPricing;
use SulimanBenhalim\AiCost\Pricing\PriceList;

app(PriceList::class)->register('openai', 'my-fine-tune', new ModelPricing(input: 5.0, output: 15.0));

A model with no known price returns an unknown cost (isKnown() is false, total 0) instead of throwing, so reporting is always safe.

breakdown() also includes cache_read, cache_write, and reasoning components. If you have raw usage without a response, price it directly:

use Laravel\Ai\Responses\Data\Usage;

AiCost::forUsage(new Usage(promptTokens: 1_000, completionTokens: 500), 'openai', 'gpt-4o');

Budgets

Tag an agent with #[MaxCost]. Once it has spent that budget within the current request or queued job, the next prompt is blocked with a BudgetExceededException, before any model call is made:

use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Promptable;
use SulimanBenhalim\AiCost\Attributes\MaxCost;

#[MaxCost(0.50)]
class ResearchAgent implements Agent
{
    use Promptable;
}

Inspect spend at any time:

use SulimanBenhalim\AiCost\Facades\Budget;

Budget::spent(ResearchAgent::class); // 0.38
Budget::total();                     // across all agents
Budget::reset();                     // e.g. between queue jobs

Set ai-cost.budget.enabled to false to keep cost reporting while turning enforcement off.

Scope and caveats

  • Spend is scoped to the request or queued job. The meter is a scoped binding, so it resets per HTTP request and per queue job. In a long-lived worker that batches many prompts in one job, call Budget::reset() between units of work.
  • Budgets only guard models with known pricing. An unpriced model records $0, so its budget never trips; the package logs a warning when a #[MaxCost] agent runs on an unpriced model. Register pricing for every budgeted model.
  • Pricing keys match the connection name. Rates are looked up by meta->provider, which is the connection name from your ai.php config. Keep connection names equal to the driver (openai, anthropic, ...) or register pricing under your custom name.
  • A few SDK-level flows are outside this package's reach: an exception thrown by a sub-agent used as a tool is caught by the SDK and returned as a tool result, so give the parent agent its own budget; streamed spend is recorded only once the stream is fully consumed; and the SDK's automatic conversation-title generation makes its own model call that is not tracked.

How it works

The package never touches the AI SDK's classes. It listens to the lifecycle events the SDK already fires:

  • PromptingAgent / StreamingAgent run before the model call, so the budget check can abort a request without spending.
  • AgentPrompted / AgentStreamed run after, recording the response cost against the agent.

Cost itself is computed from data already public on every response: usage (token counts) plus the provider and model on meta. That is why it works across every provider with zero gateway changes.

Testing

composer test

Notes

This started as a proposal to the AI SDK itself (laravel/ai#721). The maintainers prefer to keep that package lean and suggested releasing it standalone, which is what this is. The price table in particular is better maintained here, where it can be versioned independently of the SDK.

License

MIT. See LICENSE.md.