Skip to content

fix: show sub-cent costs in context panel instead of rounding to $0.00#600

Closed
VJ-yadav wants to merge 2 commits intoAltimateAI:mainfrom
VJ-yadav:fix/cost-tracking
Closed

fix: show sub-cent costs in context panel instead of rounding to $0.00#600
VJ-yadav wants to merge 2 commits intoAltimateAI:mainfrom
VJ-yadav:fix/cost-tracking

Conversation

@VJ-yadav
Copy link
Copy Markdown

@VJ-yadav VJ-yadav commented Mar 30, 2026

Summary

  • The cost display used Intl.NumberFormat USD currency formatting which rounds to 2 decimal places, causing any cost below $0.005 to show as "$0.00" — making it appear cost never increases even as tokens accumulate
  • Added Locale.cost() formatter with tiered precision: 4 decimal places for sub-10-cent costs (trailing zeros stripped), standard 2 decimal places for larger amounts
  • Applied the formatter consistently across all 5 cost display points: TUI sidebar, TUI header, stats command, trace list, and trajectory table

Root Cause Analysis

A single LLM message with 1K input tokens on Claude Sonnet costs ~$0.003. The standard Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }) rounds this to $0.00. The cost IS being calculated correctly by Session.getUsage() (verified via Decimal.js multiplication of token counts × model pricing from models.dev), but the 2-decimal formatting hid it.

The trace viewer (viewer.ts line 321) already had a local fc() function with the correct 4-decimal behavior — this PR extracts the pattern into a shared Locale.cost() utility and applies it everywhere.

For free models (opencode provider with apiKey: "public"), cost is genuinely $0.00 since those models have cost: { input: 0, output: 0 } in models.dev. The formatter correctly shows "$0.00" for truly zero costs.

Test Plan

  • Locale.cost() unit tests: zero, sub-cent, under-10-cents, standard amounts, typical session costs
  • Session.getUsage() tests: non-zero cost for small token counts (5K input + 1K output on Claude Sonnet pricing), zero cost for free models
  • All 44 tests pass across locale.test.ts and compaction.test.ts

Checklist

  • Formatting examples: $0.003 (1K input on Sonnet), $0.03 (5K input + 1K output), $0.25 (multi-message), $1.23 (standard)
  • No breaking changes — only formatting output changes
  • Consistent with existing fc() in viewer.ts

Fixes #585

Summary by CodeRabbit

  • Improvements
    • Enhanced cost formatting with intelligent decimal precision across the application. Costs below $0.10 now display with four decimal places for improved visibility of small amounts, while costs $0.10 and above use standard two-decimal currency formatting for consistent and clear cost presentation throughout the interface.

The cost display in the TUI context panel (sidebar and header) used
Intl.NumberFormat with USD currency formatting, which rounds to 2
decimal places. This caused any cost below $0.005 to display as "$0.00",
making it appear that cost never increases even as tokens accumulate.

For typical LLM usage, a single message with 1K input tokens on Claude
Sonnet costs ~$0.003, which was invisibly rounded away. After several
messages the cost would eventually cross the $0.01 threshold, but for
the first many interactions it misleadingly showed $0.00.

Add Locale.cost() formatter with tiered precision:
  - $0 exactly     -> "$0.00"
  - < $0.10        -> "$0.003" (up to 4 decimals, trailing zeros stripped)
  - >= $0.10       -> "$0.12"  (standard 2 decimal places)

Apply the formatter consistently across all cost displays: TUI sidebar,
TUI header, stats command, trace list, and trajectory table.

Fixes AltimateAI#585

Co-Authored-By: Vijay Yadav <vijay@studentsucceed.com>
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions
Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Warning

Rate limit exceeded

@VJ-yadav has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 45 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 4 minutes and 45 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 4ca199f5-679b-49b4-a59d-f03c3e145699

📥 Commits

Reviewing files that changed from the base of the PR and between a14c9f8 and 3d9d767.

📒 Files selected for processing (2)
  • packages/opencode/src/util/locale.ts
  • packages/opencode/test/util/locale.test.ts
📝 Walkthrough

Walkthrough

A new Locale.cost() utility function is introduced to standardize USD cost formatting with tiered precision across the application. All hardcoded cost formatting throughout CLI commands and TUI components is replaced with calls to this centralized utility, including comprehensive test coverage.

Changes

Cohort / File(s) Summary
CLI Command Cost Formatting
packages/opencode/src/cli/cmd/stats.ts, packages/opencode/src/cli/cmd/trace.ts, packages/opencode/src/cli/cmd/trajectory.ts
Replaced manual cost formatting (toFixed(), $ prefix concatenation) with Locale.cost() for "Total Cost", "Avg Cost/Day", and per-model cost rendering.
TUI Component Cost Formatting
packages/opencode/src/cli/cmd/tui/routes/session/header.tsx, packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
Replaced hardcoded Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }) with Locale.cost() for cost display in session header and sidebar components.
Locale Utility Implementation
packages/opencode/src/util/locale.ts
Added new Locale.cost(amount: number): string function implementing tiered precision: 4 decimal places for amounts < $0.10 (with trailing zero stripping), standard 2 decimal places for amounts ≥ $0.10.
Test Coverage
packages/opencode/test/util/locale.test.ts, packages/opencode/test/session/compaction.test.ts
Added comprehensive test suite for Locale.cost() covering zero values, sub-cent precision, boundary cases, and standard currency formatting; added cost calculation assertions for session usage.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • AltimateAI/altimate-code#369: Modifies the same Locale utility module with overlapping changes to cost formatting and related test coverage.

Suggested labels

contributor

Poem

🐰 Costs were scattered, now consolidated tight,
From stats to traces, they all format right,
Locale.cost() hops in with precision so keen,
Four decimals for pennies, two for the green!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: introducing a formatter that displays sub-cent costs instead of rounding them to $0.00.
Description check ✅ Passed The description covers all required sections: summary of changes and root cause, test plan with specific test cases, and checklist with all items completed.
Linked Issues check ✅ Passed The PR directly addresses issue #585 by implementing a cost formatter that displays sub-cent values, fixing the issue where costs appeared to never increase due to 2-decimal rounding.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing and applying the Locale.cost() formatter across cost display locations, with supporting test coverage—no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/src/util/locale.ts`:
- Around line 101-111: The special sub-$0.10 formatting branch currently
triggers for any amount < 0.10, incorrectly handling negative values; update the
conditional in the block that checks amount (the "if (amount < 0.10)" branch) to
only apply to positive sub-cent amounts (e.g., amount > 0 && amount < 0.10) so
negative amounts fall through to the standard currency/Intl formatting path;
verify behavior for zero if desired and adjust condition to include/exclude 0
accordingly.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 13fd3048-acff-4f9c-828e-8c49eb0ad3f3

📥 Commits

Reviewing files that changed from the base of the PR and between 5d0ada3 and a14c9f8.

📒 Files selected for processing (8)
  • packages/opencode/src/cli/cmd/stats.ts
  • packages/opencode/src/cli/cmd/trace.ts
  • packages/opencode/src/cli/cmd/trajectory.ts
  • packages/opencode/src/cli/cmd/tui/routes/session/header.tsx
  • packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx
  • packages/opencode/src/util/locale.ts
  • packages/opencode/test/session/compaction.test.ts
  • packages/opencode/test/util/locale.test.ts

Address CodeRabbit review: negative amounts were routed through the
sub-cent branch instead of Intl.NumberFormat. Changed condition from
`amount < 0.10` to `amount > 0 && amount < 0.10`. Added test for
negative amounts.

Co-Authored-By: Vijay Yadav <vijay@studentsucceed.com>
@anandgupta42
Copy link
Copy Markdown
Contributor

Working as expected. Check the issue details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cost never increases

2 participants