fix(pricing): pick closest-length fuzzy match in LiteLLM pricing lookup - #1018
Conversation
When no direct pricing entry exists for a model name, the fuzzy fallback in getModelPricing() previously returned the first substring match in iteration order. For "gpt-5.4-mini" this matched "gpt-5" instead of "gpt-5.4", producing a ~5x cost overcharge. Collect all substring matches and pick the candidate whose name length is closest to the input length, so "gpt-5.4-mini" prefers "gpt-5.4" over the more generic "gpt-5" entry. Fixes #934
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | b22019d | Commit Preview URL Branch Preview URL |
May 17 2026, 10:07 AM |
|
Caution Review failedPull request was closed or merged during review No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR improves pricing lookup accuracy by changing ChangesPricing fuzzy matching improvement
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
packages/internal/src/pricing.ts[baseline-browser-mapping] The data in this module is over two months old. To ensure accurate Baseline data, please update: Oops! Something went wrong! :( ESLint: 9.35.0 Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'eslint-plugin-format' imported from /node_modules/.pnpm/@antfu+eslint-config@4.19.0_@vue[email protected][email protected][email protected]_vit_670a2c5c75d4275eabd7bc195a173ee6/node_modules/@antfu/eslint-config/dist/index.js Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ccusage performance comparisonThis compares the PR build against the base branch build on the same CI runner. Committed fixture performanceCommitted small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage. Fixtures: Claude
Large real-world-shaped fixture performanceGenerated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures. Fixtures: Claude
Package size
Lower medians and smaller packed package sizes are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Summary
Fixes #934.
When a model has no direct entry in the LiteLLM pricing map,
getModelPricing()falls back to a substring-based fuzzy match. The old loop returned the first key whose name was a substring of (or contained) the input, inMapinsertion order. Forgpt-5.4-minithis matchedgpt-5instead ofgpt-5.4, producing a ~5x cost overcharge in the Codex adapter.This change collects all substring matches and picks the candidate whose name length is closest to the input length. So
gpt-5.4-mininow resolves togpt-5.4(length diff 5) overgpt-5(length diff 7). The heuristic also handles the reverse direction: when the input is shorter than candidates, the closest-length key still wins.This is the algorithmic fix suggested as option 2 in the issue. It does not require adding new prefetched entries and does not introduce a strict-mode flag.
Changes
packages/internal/src/pricing.ts— replace first-match fuzzy loop inLiteLLMPricingFetcher.getModelPricing()with a closest-length-difference scan.Test plan
pnpm --filter @ccusage/internal test— 58 passingpnpm run test— 497 passing, 3 skippedpnpm typecheck— cleanpnpm run format— cleanGenerated by Claude Code
Summary by cubic
Fixes pricing lookup when a model has no direct entry by choosing the closest-length fuzzy match. This prevents cases like
gpt-5.4-minimapping togpt-5and overcharging.LiteLLMPricingFetcher.getModelPricing()to scan all substring matches and select the key with the smallest length difference to the input.Written for commit b22019d. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
Bug Fixes
Tests