# Token Tracking Fixes - Summary ## Issues Fixed ### 1. Plan Messages Now Use 1x Multiplier **Location:** `chat/server.js:4013` - **Problem:** Plan messages were using `getModelTier(model || providerName)` which could return 'plus' or 'pro' tier, causing plan tokens to be counted at 2x or 3x multiplier - **Fix:** Changed to `getModelTier(model || providerName, 'free')` to force plan messages to use 'free' tier (1x multiplier) - **Impact:** Plan messages (OpenRouter, Mistral, Google, Groq, NVIDIA) now always counted at 1x multiplier regardless of the model used ### 2. Missing Tier Information Defaults to 1x Usage **Location:** `chat/server.js:2508-2523` - **Problem:** Models without configured tiers could have inconsistent tier detection - **Fix:** Enhanced `getModelTier()` function with: - Optional `forceTier` parameter to override tier when needed - Better validation to check if tier is in `VALID_TIERS` before using it - Default to 'free' (1x) if tier is not configured - **Impact:** All messages with missing tier info now consistently use 1x multiplier ### 3. Both Plan and OpenCode Tokens Counted in Overall Usage **Status:** ✅ Already Working - **Location:** `chat/public/builder.js:356-390` - **Explanation:** Builder's usage meter uses 'aggregate' tier which sums up usage across all tiers (free, plus, pro) - **Result:** Plan tokens (from OpenRouter etc.) and OpenCode tokens are both included in the total usage display ### 4. Enhanced Debugging **Location:** `chat/server.js:2640` - **Enhancement:** Added source tracking to `recordUserTokens()` logging - **New Log Format:** `[USAGE] recording tokens for user=${userId} tier=${safeTier} raw=${tokens} rounded=${roundedTokens} effective=${effectiveTokens} source=${caller_file}` - **Benefit:** Helps identify where token recording is coming from (plan vs opencode) ## Technical Details ### Tier Multipliers ```javascript TIER_USAGE_MULTIPLIER = { free: 1, // 1x multiplier plus: 2, // 2x multiplier pro: 3 // 3x multiplier } ``` ### Token Recording Flow #### Plan Messages (1x multiplier) 1. User sends message to `/api/plan` 2. `handlePlanMessage()` processes request 3. Provider (OpenRouter, Mistral, etc.) generates response 4. `extractTokenUsageFromResult()` extracts actual token count 5. `recordUserTokens(userId, 'free', tokensUsed)` records at 1x multiplier 6. Tokens go to `bucket.usage.free` #### OpenCode Messages (model tier multiplier) 1. User sends message to `/api/sessions/{id}/messages` 2. `processMessage()` handles OpenCode execution 3. `getModelTier(message.model)` determines tier from model configuration 4. `extractTokenUsageFromResult()` or `estimateTokensFromMessages()` gets token count 5. `recordUserTokens(userId, tier, tokensUsed)` records at appropriate multiplier 6. Tokens go to `bucket.usage[tier]` (free, plus, or pro) ### Usage Summary Calculation ```javascript // For each tier (free, plus, pro): const used = bucket.usage[tier]; const limit = getPlanTokenLimits(plan, userId)[tier]; const remaining = limit - used; const percent = (used / limit) * 100; ``` ## Testing Checklist - [ ] Create a plan message and verify it's counted at 1x multiplier - [ ] Create an OpenCode message and verify it's counted at model's configured tier - [ ] Check that both plan and OpenCode tokens appear in the aggregate usage meter - [ ] Verify logs show proper tier assignment for each message type - [ ] Test with a model that has no tier configured (should default to 1x) - [ ] Test with a model that has 'plus' or 'pro' tier configured ## How to Verify Token Tracking ### Check Server Logs Look for these log patterns: ``` [PLAN] Recording tokens for successful plan: user=xxx tokens=1000 provider=openrouter model=gpt-4o [USAGE] recording tokens for user=xxx tier=free raw=1000 rounded=1000 effective=1000 source=handlePlanMessage [USAGE] processMessage: recording tokens user=xxx tier=plus raw=500 rounded=500 effective=1000 source=processMessage [USAGE] Persisted token usage. New total for xxx/free: 15000 [USAGE] Persisted token usage. New total for xxx/plus: 2000 ``` ### Check Client Usage Meter Open browser DevTools Console and look for: ``` [USAGE] Usage summary loaded: { month: "2025-01", plan: "hobby", tiers: { free: { used: 15000, limit: 50000, remaining: 35000, percent: 30, ... }, plus: { used: 2000, limit: 2500000, remaining: 2498000, percent: 0, ... }, pro: { used: 0, limit: 5000000, remaining: 5000000, percent: 0, ... } } } ``` ## Files Modified - `chat/server.js` - Enhanced `getModelTier()` function, fixed plan message recording, enhanced logging - `chat/public/builder.js` - Already had aggregate tier support (no changes needed)