fix(pricing): add Claude Opus 4.8 rates#1182
Conversation
Embed Claude Opus 4.8 pricing for offline reports so usage does not fall back to the deprecated Claude Opus 4 rate when the runtime LiteLLM refresh is unavailable. Use the current Anthropic fast mode rate for Opus 4.8, which is input and output per MTok, so the fast multiplier is 2x instead of the 6x multiplier used by Opus 4.6 and 4.7. Tighten pricing-key fuzzy matching so date-suffixed model IDs can still resolve through their base key while unknown numeric model revisions such as claude-opus-4.8 or claude-opus-4.70 no longer match claude-opus-4.
|
@coderabbitai review |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
View logs |
ccusage-guide | 2688af0 | May 29 2026, 08:45 AM |
✅ Actions performedReview triggered.
|
|
@coderabbitai Please focus the review on the pricing resolution behavior: (1) Claude Opus 4.8 should use embedded offline pricing at $5/$25 per MTok with cache rates $6.25/$0.50 matching Anthropic pricing, (2) fast mode for Opus 4.8 should use $10/$50 per MTok, so a 2x multiplier, while Opus 4.6/4.7 stay at $30/$150 and 6x, and (3) fuzzy model matching should still resolve date-suffixed aliases like claude-opus-4-20250514 but must not fall back across unknown numeric model versions such as claude-opus-4.8 or claude-opus-4.70 to claude-opus-4. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find pricing-related Rust files
fd -e rs . rust/ | xargs grep -l "opus.4" 2>/dev/null
echo "=== Find pricing/model data files ==="
fd -e rs . rust/ | head -40Length of output: 2296 🏁 Script executed: #!/bin/bash
echo "=== Search for claude-opus-4-8 pricing entries ==="
rg -n "opus.4.8\|opus_4_8\|opus-4-8" --type rust -C3
echo ""
echo "=== Search for fast mode multiplier logic ==="
rg -n "fast.*mult\|mult.*fast\|fast_mode\|FastMode\|6x\|2x\|multiplier" --type rust -C3 | head -100
echo ""
echo "=== Search for fuzzy matching logic ==="
rg -n "fuzzy\|fallback\|date.suffix\|date_suffix\|match.*model\|model.*match" --type rust -C5 | head -100Length of output: 630 🏁 Script executed: #!/bin/bash
echo "=== Full pricing.rs ==="
cat rust/crates/ccusage/src/pricing.rs
echo ""
echo "=== Check for embedded JSON/TOML pricing data ==="
fd -e json -e toml -e yaml . rust/ | xargs grep -l "opus" 2>/dev/null | head -10
echo ""
echo "=== Check for any data files with opus pricing ==="
rg -rn "opus-4-8\|opus_4_8\|4\.8" rust/ -C2 | head -80Length of output: 39789 🏁 Script executed: #!/bin/bash
cat rust/crates/ccusage/src/fast-multiplier-overrides.jsonLength of output: 298
1. Claude Opus 4.8 embedded offline pricing ✅In "claude-opus-4-8" → input: 5e-6, output: 25e-6, cache_create: 6.25e-6, cache_read: 0.5e-6
2. Fast-mode multipliers ✅
"normalized_prefix": {
"claude-opus-4-6": 6.0,
"claude-opus-4-7": 6.0,
"claude-opus-4-8": 2.0
}
3. Fuzzy model-key matching ✅
Concrete cases confirmed by tests:
Minor observation
Everything else looks correct. All three requirements are properly implemented and well-covered by tests. |
|
@coderabbitai Correction to my previous focus note: please specifically verify that standard Claude Opus 4.8 embedded/offline pricing is $5/$25 per MTok, cache write/read rates are $6.25/$0.50 per MTok, fast mode for Opus 4.8 is $10/$50 per MTok with a 2x multiplier, and Opus 4.6/4.7 fast mode remains $30/$150 per MTok with a 6x multiplier. Also verify that fuzzy matching allows date-suffixed aliases but does not fall back across unknown numeric model versions like claude-opus-4.8 or claude-opus-4.70 to claude-opus-4. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== Opus 4.8 and nearby entries in put_builtin_pricing ==="
rg -n "opus-4-[5678]|opus_4_[5678]|5e-6|25e-6|6\.25e-6|0\.5e-6|cache_read\|cache_create" --type rust -C4 rust/ | head -120
echo ""
echo "=== fast-multiplier-overrides.json ==="
cat rust/crates/ccusage/src/fast-multiplier-overrides.json
echo ""
echo "=== Relevant tests for pricing values ==="
rg -n "opus.4.8\|4\.8.*mult\|mult.*4\.8\|fast.*4\.[678]\|4\.[678].*fast\|10e-6\|50e-6\|30e-6\|150e-6" --type rust -C5 rust/ | head -120
echo ""
echo "=== Context limit entries for opus 4.8 ==="
rg -n "1_000_000\|context_limit\|opus-4-8" --type rust -C3 rust/ | head -60
echo ""
echo "=== Fuzzy match tests ==="
rg -n "fuzzy_match\|suffix_starts_with_numeric\|date.suffix\|20250514\|20260528\|4\.70\|4\.8.*opus" --type rust -C5 rust/ | head -100Length of output: 13344 🏁 Script executed: #!/bin/bash
echo "=== Lines 260-400 of pricing.rs ==="
sed -n '260,420p' rust/crates/ccusage/src/pricing.rs
echo ""
echo "=== Fuzzy match / suffix_starts_with_numeric function ==="
rg -n "suffix_starts_with_numeric\|fuzzy_key\|fuzzy_match\|find_key\|find_pricing" --type rust -C6 rust/ | head -150
echo ""
echo "=== Context window / token limit setup ==="
rg -n "context_window\|token_limit\|max_tokens\|1_000_000\|200_000" --type rust -C4 rust/ | head -80
echo ""
echo "=== Tests related to Opus 4.8 pricing or fuzzy ==="
rg -n "4[-_\.]8\|opus.*4.*8\|20260528\|20250514\|4\.70\|numeric_model" --type rust -C6 rust/ | head -150Length of output: 6395 🏁 Script executed: #!/bin/bash
echo "=== Full pricing.rs line count and last section ==="
wc -l rust/crates/ccusage/src/pricing.rs
sed -n '420,700p' rust/crates/ccusage/src/pricing.rs
echo ""
echo "=== context_limit / max_context entries ==="
grep -n "context\|limit\|1000000\|1_000_000" rust/crates/ccusage/src/pricing.rs | head -40
echo ""
echo "=== All test names in pricing.rs ==="
grep -n "fn \|#\[test\]" rust/crates/ccusage/src/pricing.rs | head -80Length of output: 15213
1. Claude Opus 4.8 embedded/offline pricing ✅From
2. Fast-mode multipliers ✅From "claude-opus-4-6": 6.0,
"claude-opus-4-7": 6.0,
"claude-opus-4-8": 2.0And
3. Context limit ✅
assert_eq!(pricing.context_limit("claude-opus-4.8"), Some(1_000_000));4. Fuzzy model matching ✅
Tests confirming this:
All four requirements are correctly implemented and numerically verified against the source. ✅ |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== Opus 4.8 / 4.6 / 4.7 entries in put_builtin_pricing ==="
rg -n "opus-4-[5678]|opus_4_[5678]|4-8\|4-7\|4-6" --type rust -C 6 rust/
echo ""
echo "=== fast-multiplier-overrides.json ==="
cat rust/crates/ccusage/src/fast-multiplier-overrides.json 2>/dev/null || fd "fast-multiplier" --exec cat {}
echo ""
echo "=== Test cases that verify fast-mode dollar amounts ==="
rg -n "10.*50\|50.*10\|30.*150\|150.*30\|fast.*4\\.8\|4\\.8.*fast\|fast.*opus" --type rust -C 4 | head -120
echo ""
echo "=== All embedded pricing entries for claude-opus-4 variants ==="
rg -n "claude-opus-4" --type rust -C 3 rust/ | head -200Length of output: 39486
1. Opus 4.8 standard embedded pricing ✅From
Confirmed also by 2. Fast-mode effective rates ✅
"claude-opus-4-6": 6.0,
"claude-opus-4-7": 6.0,
"claude-opus-4-8": 2.0Base rates are identical across 4.6/4.7/4.8 (
Validated by 3. Fuzzy matching ✅Two dedicated tests confirm the guard behaviour:
All three requirements pass with exact dollar amounts matching Anthropic's published pricing. |
|
Tip For best results, initiate chat on the files or code changes.
1. Claude Opus 4.8 embedded/offline pricing ✅From
2. Fast-mode multipliers ✅From "claude-opus-4-6": 6.0,
"claude-opus-4-7": 6.0,
"claude-opus-4-8": 2.0
The 3. Fuzzy model matching ✅
Tests covering these cases: All three requirements are correctly implemented and verified against the source. ✅ |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
rust/crates/ccusage/src/pricing.rs (1)
636-655: ⚡ Quick winLogic is correct; document the
8date-length heuristic.The boundary rules check out against the tests. The one snag for future maintainers is
digit_len == 8— it silently encodes "an 8-digit run is an AnthropicYYYYMMDDdate alias (allowed), anything else is a numeric model revision (blocked)". This is central to correctness but invisible at the call site. A named constant or short comment prevents an accidental future edit from breaking version boundaries.♻️ Name the date-suffix length
+/// Length of an Anthropic model date suffix (`YYYYMMDD`); treated as an alias, +/// not a distinct numeric model version. +const MODEL_DATE_SUFFIX_DIGITS: usize = 8; + fn suffix_starts_with_numeric_model_version(key: &str, suffix: &str) -> bool { if !key.as_bytes().last().is_some_and(u8::is_ascii_digit) { return false; } if !matches!(suffix.as_bytes().first(), Some(b'-' | b'.')) { return false; } let rest = &suffix[1..]; let digit_len = rest .as_bytes() .iter() .take_while(|byte| byte.is_ascii_digit()) .count(); if digit_len == 0 { return false; } let after_digits = rest.as_bytes().get(digit_len).copied(); - !(digit_len == 8 && after_digits.is_none_or(is_pricing_key_boundary)) + !(digit_len == MODEL_DATE_SUFFIX_DIGITS && after_digits.is_none_or(is_pricing_key_boundary)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/crates/ccusage/src/pricing.rs` around lines 636 - 655, The function suffix_starts_with_numeric_model_version currently treats a digit_len == 8 specially without explanation; update this by introducing a named constant (e.g., DATE_SUFFIX_LEN or ANTHROPIC_DATE_LEN) or a brief inline comment inside suffix_starts_with_numeric_model_version explaining that an 8-digit run is treated as a YYYYMMDD Anthropic date alias (allowed) while other numeric runs mark numeric model revisions (blocked). Ensure the code replaces the literal 8 with the constant (or places the comment immediately adjacent to the check) so future maintainers understand the heuristic used in the digit_len == 8 && after_digits.is_none_or(is_pricing_key_boundary) condition.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/crates/ccusage/src/pricing.rs`:
- Around line 262-278: The pricing entry for "claude-opus-4-8" must reflect
public pricing and validated cache rates: verify that the fast multiplier
resolved by fast_multiplier_overrides.multiplier_for("claude-opus-4-8") is 2.0
(so fast mode yields $10/M input and $50/M output) and, separately, confirm
Anthropic’s prompt-caching rates match the embedded cache_create: 6.25e-6,
cache_read: 0.5e-6 and cache_read_explicit: true; if the docs differ, update the
Pricing fields (input, output, cache_create, cache_read, cache_read_explicit)
for the "claude-opus-4-8" entry accordingly and ensure any override for that
model explicitly sets multiplier 2.0.
---
Nitpick comments:
In `@rust/crates/ccusage/src/pricing.rs`:
- Around line 636-655: The function suffix_starts_with_numeric_model_version
currently treats a digit_len == 8 specially without explanation; update this by
introducing a named constant (e.g., DATE_SUFFIX_LEN or ANTHROPIC_DATE_LEN) or a
brief inline comment inside suffix_starts_with_numeric_model_version explaining
that an 8-digit run is treated as a YYYYMMDD Anthropic date alias (allowed)
while other numeric runs mark numeric model revisions (blocked). Ensure the code
replaces the literal 8 with the constant (or places the comment immediately
adjacent to the check) so future maintainers understand the heuristic used in
the digit_len == 8 && after_digits.is_none_or(is_pricing_key_boundary)
condition.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 7cf341e3-b7a6-4127-b508-cd9eb4685b02
📒 Files selected for processing (2)
rust/crates/ccusage/src/fast-multiplier-overrides.jsonrust/crates/ccusage/src/pricing.rs
Address CodeRabbit feedback by replacing the raw 8 used for Anthropic YYYYMMDD model aliases with a named constant. This keeps the numeric version boundary rule unchanged while making the date-alias exception explicit in code.
|
@coderabbitai review latest push a5c1279. I addressed your date suffix nit by replacing the raw 8 with MODEL_DATE_SUFFIX_DIGITS, and the pricing/cache-rate thread has been replied to with the Anthropic pricing confirmation. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== Commit a5c1279 diff ==="
git show a5c1279 --stat
echo ""
echo "=== Full diff for a5c1279 ==="
git show a5c1279
echo ""
echo "=== Search for MODEL_DATE_SUFFIX_DIGITS in codebase ==="
rg -n "MODEL_DATE_SUFFIX_DIGITS" --type rust -C4 rust/Length of output: 3812
All the items raised in this review thread are resolved: embedded Opus 4.8 pricing ($5/$25 base, $6.25/$0.50 cache), 2× fast-mode multiplier for Opus 4.8 vs 6× for 4.6/4.7, and the numeric-version boundary guard with the named date-suffix constant. The PR is in good shape. ✅ (。•̀ᴗ-)✧ [approve] |
ccusage
@ccusage/ccusage-darwin-arm64
@ccusage/ccusage-darwin-x64
@ccusage/ccusage-linux-arm64
@ccusage/ccusage-linux-x64
@ccusage/ccusage-win32-arm64
@ccusage/ccusage-win32-x64
commit: |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
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
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
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
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
Document that the eight-digit exception in pricing-key matching corresponds to Anthropic YYYYMMDD model aliases, while other numeric suffixes are treated as distinct model versions.
|
@coderabbitai review latest push 2688af0. This is a comment-only follow-up documenting why the date suffix length is 8 (Anthropic YYYYMMDD aliases); the commit is marked [ci skip]. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== Commit 2688af0 stat ==="
git show 2688af0 --stat
echo ""
echo "=== Full diff for 2688af0 ==="
git show 2688af0Length of output: 1780
// Anthropic date-suffixed model aliases use YYYYMMDD, while other numeric
// suffixes are treated as distinct model versions.
const MODEL_DATE_SUFFIX_DIGITS: usize = 8;The comment accurately captures the intent: the 8-digit exception is specifically for Anthropic's (ᵔᴥᵔ) [approve] |
ccusage performance comparisonPR SHA: This compares the PR package against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
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
Artifact size
Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |
ccusage performance comparisonPR SHA: This compares the Rust PR release binary against the configured base package on the same CI runner. Package runner startupExecution setup measures any pre-benchmark package materialization used by the execution benchmark. Bunx temp cache measures one
Cached bunx execution performanceRuns the same large fixture through Fixtures: Claude
Package runtime diagnosticsCompares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself. Fixtures: Claude
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
Artifact sizeLower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees. |

Adds embedded Claude Opus 4.8 pricing so offline reports and pricing refresh failures use the current Opus 4.8 rates instead of falling back to deprecated Opus 4 pricing.
Also updates Claude fast-mode multipliers so Opus 4.8 uses the current 2x rate, while Opus 4.6 and 4.7 remain at 6x. Pricing-key fuzzy matching now allows date-suffixed aliases but avoids falling back across unknown numeric model versions.
Testing:
Summary by cubic
Embed Claude Opus 4.8 pricing and set the correct fast-mode rate so offline reports use current costs instead of falling back to deprecated Opus 4. Also tighten model-name matching with a named YYYYMMDD date-suffix rule to allow date aliases without crossing numeric versions.
New Features
claude-opus-4-8(input 5e-6, output 25e-6; cache create 6.25e-6; cache read 0.5e-6) and a 1,000,000 token context limit.claude-opus-4-8= 2x;claude-opus-4-6andclaude-opus-4-7remain 6x.Bug Fixes
claude-opus-4.claude-opus-4.8-20260528) via a documented 8-digit YYYYMMDD rule, and blocks cross-version fallbacks (e.g.,4.8or4.70do not match4).Written for commit 2688af0. Summary will update on new commits.
Review in cubic
Summary by CodeRabbit
New Features
Bug Fixes
Tests