Overview
Credits track two types of costs:- LLM costs: computed from token usage + model pricing
- API costs: fixed per-tool costs (e.g. Tavily, sandbox, image generation)
Architecture
Tool Costs (lib/ai/tools/tools-definitions.ts)
Tool costs are external API fees only (in cents). LLM costs are accounted via token usage separately.
| Tool | Cost | Notes |
|---|---|---|
| webSearch | 5¢ | Tavily |
| codeExecution | 5¢ | Vercel Sandbox execution |
| generateImage | 17¢ | Traditional image gen API (multimodal image models are billed via LLM usage instead) |
| deepResearch | 0¢ | LLM calls tracked via usage; webSearch calls tracked separately |
| createTextDocument | 0¢ | LLM calls tracked via usage |
| createCodeDocument | 0¢ | LLM calls tracked via usage |
| createSheetDocument | 0¢ | LLM calls tracked via usage |
| editTextDocument | 0¢ | LLM calls tracked via usage |
| editCodeDocument | 0¢ | LLM calls tracked via usage |
| editSheetDocument | 0¢ | LLM calls tracked via usage |
| retrieveUrl | 0¢ | Internal (Firecrawl billed via webSearch if you want fixed API pricing) |
How It Works
TheCostAccumulator collects costs throughout a request lifecycle:
- A new accumulator is created at request start
- The main chat stream adds LLM token costs on finish
- Tools report their costs after execution (either LLM tokens or fixed API costs)
- At request end, total cost is calculated and deducted from the user’s balance
Adding Cost Tracking to New Tools
To add cost tracking to a new tool:- Add
costAccumulator?: CostAccumulatorto your tool’s props type - Accept it in
getTools()and pass to your tool factory - After any LLM call, add:
costAccumulator?.addLLMCost(modelId, result.usage, "your-source") - For fixed API costs, add to
toolsDefinitionsand call:costAccumulator?.addAPICost("toolName", cost)
Anonymous User Credits
Anonymous users have a separate, simpler credit system stored in browser cookies instead of the database.Why Two Systems?
| Aspect | Anonymous | Authenticated |
|---|---|---|
| Storage | Cookie (anonymous-session) | Database (userCredit) |
| Unit | Message count | Cents (dollars × 100) |
| Cost per request | Fixed: 1 credit | Actual LLM + API costs |
| Deduction timing | Pre-streaming | Post-streaming |
| Default balance | 10 (prod) / 1000 (dev) | Based on plan |
- Easier to communicate (“10 free messages” vs explaining token costs)
- Pre-deduction required because cookies cannot be set after response streaming begins
- No need for database writes for unregistered users
How Anonymous Credits Work
- On first visit, a session is created with
ANONYMOUS_LIMITS.CREDITSremaining - Session is stored as JSON in the
anonymous-sessioncookie - Before each request, 1 credit is deducted and cookie is updated
- When credits reach 0, user is prompted to sign up
Configuration
Anonymous limits are configured inchat.config.ts:
Anonymous Credit Files
| File | Purpose |
|---|---|
lib/anonymous-session-client.ts | Client-side cookie read/write |
lib/anonymous-session-server.ts | Server-side cookie read/write |
lib/create-anonymous-session.ts | Shared session factory |
lib/types/anonymous.ts | Types and ANONYMOUS_LIMITS |
components/upgrade-cta/limit-display.tsx | UI for remaining credits |
Key Files
| File | Purpose |
|---|---|
lib/credits/cost-accumulator.ts | CostAccumulator class with LLM cost calculation |
lib/db/credits.ts | Credit storage (getCredits, deductCredits, addCredits) |
lib/ai/tools/tools-definitions.ts | Fixed API costs per tool |
app/(chat)/api/chat/route.ts | Instantiates accumulator and finalizes costs |