AI Usage Observer
Automatically deducts credits and calculates profit metrics whenever an AI usage log is created.
Overview
The AIUsageLogObserver listens for the created event on AIUsageLog models. Every time your AI processes a request — whether it's a chat response, embedding, or playground query — this observer kicks in to:
- Deduct credits from the tenant's balance
- Calculate revenue and profit metrics
- Handle failed usage logs gracefully
File: app/Observers/AIUsageLogObserver.php
How It Works
When an AIUsageLog is created, the observer follows this flow:
- Check status — If the log is
failed, handle it separately (zero out credits, set model) - Validate context — Ensure an agent and tenant_id exist; try to resolve missing tenant context
- Route to correct credit pool — Playground types use
PlaygroundCredit, all others useCredit - Deduct credits — Uses FIFO ordering with atomic locks to prevent race conditions
- Calculate profit — Computes revenue vs. cost in both USD and NGN
Credit Deduction
Standard Credits
For regular AI usage (chat responses, embeddings, safety checks):
- Credits to deduct =
total_tokens / agent.tokens_per_credit - Credits are deducted from the tenant's
Creditpackages in FIFO order (oldest first) - When the oldest package is depleted, deduction spans to the next package
- A weighted average price per credit is calculated across packages
Playground Credits
For playground-related types (playground_chat_response, playground_embedding, playground_embedding_chunks, playground_safety):
- Same deduction logic as standard credits, but from the
PlaygroundCreditpool - No overdraft support — can only use credits with positive remaining balance
Atomic Locking
Credit deduction uses Cache::lock() with a 10-second TTL and 5-second wait to prevent race conditions when multiple AI requests complete simultaneously for the same tenant.
Overdraft Tenants
Tenants listed in ai.skip_charge_for_tenants settings can go into negative credit balance. Regular tenants can only use credits with positive remaining amounts.
Profit Metrics
After credit deduction, the observer calculates:
| Metric | Formula |
|---|---|
| Input Cost (USD) | input_token_count × agent.input_cost / 1,000,000 |
| Output Cost (USD) | output_token_count × agent.output_cost / 1,000,000 |
| Revenue (USD) | (price_per_credit_ngn / exchange_rate) × (total_tokens / tokens_per_credit) |
| Profit (USD) | revenue_usd - total_cost_usd |
Exchange rate comes from settings('ai.usage_exchange_rate') (default: 1500 NGN/USD).
All values are saved to the AIUsageLog record for historical reporting.
Failed Usage Handling
When an AI request fails (status = 'failed'):
credits_usedandcredits_costare zeroed outmodelis populated from the agent's base model or metadata- An exception is reported (unless
metadata.exception_reportedis alreadytrue)
Tenant Resolution
If tenant_id is missing on the usage log, the observer tries to resolve it from:
- The agent's tenant context
- The company's tenant_id
- The conversation's tenant_id
- The user's tenant_id
Auto-Created Credits
When a new tenant is created, TenantObserver automatically assigns 50 free credits (both standard and playground) with a 6-month expiry. These credits have price_per_credit_ngn = 0 since they're complimentary.
See Also
- Dynamic AI Service — Creates the usage logs that trigger this observer
- Test file:
tests/Feature/Observers/AIUsageLogObserverTest.php
Keywords
AI usage, credit deduction, billing, profit metrics, observer, token tracking, FIFO credits, playground credits, revenue calculation