Skip to content

feat(cost): show USD cost in REPL + TUI status bars - #193

Merged
agentforce314 merged 1 commit into
mainfrom
advisor/status-bar-cost
May 21, 2026
Merged

feat(cost): show USD cost in REPL + TUI status bars#193
agentforce314 merged 1 commit into
mainfrom
advisor/status-bar-cost

Conversation

@agentforce314

Copy link
Copy Markdown
Owner

Summary

The status bar already shows token counts split by worker vs advisor (from PR #191). This PR adds the dollar cost segment — same split, summed into one display number.

Display

```
REPL: ... tokens: 5400 in / 320 out (advisor: 1326 in / 282 out) · cost $0.021
TUI: ... tokens 5720 · advisor 1326/282 · cost $0.021
```

Hidden when zero — either no API turns yet, or the worker/advisor model isn't in our known-pricing list (see critic C1 fix below).

Pricing tiers — mirror of TS modelCost.ts

Tier $/Mtok input $/Mtok output Models
HAIKU_45 1 5 haiku-4-5, 3-5-haiku
3_15 3 15 sonnet-4-6, sonnet-4-5, sonnet-4, 3-7-sonnet, 3-5-sonnet
5_25 5 25 opus-4-7, opus-4-6, opus-4-5
15_75 15 75 opus-4-0, opus-4-1 (legacy)

Lookup: exact match → strip openrouter <vendor>/ prefix → family prefix → None.

Critic-driven fixes (one round, all addressed)

  • C1 (critical): DEFAULT_PRICING was Sonnet 3/15 — would silently misprice DeepSeek/Gemini/GPT-5 by ~10×. Now unknowns return None and the cost segment is suppressed. Honesty over false precision.
  • C2 (critical): bare claude-opus-4 prefix would have routed future variants (e.g. claude-opus-4-9) onto the legacy 15/75 tier. Dropped.
  • C3 (critical): dead claude-haiku-3-5 prefix removed (canonical form is claude-3-5-haiku-…).
  • S5: unified status bar to cost \$X.XXX (space-separated) on both REPL and TUI — was inconsistent.

Files

File Change
src/services/pricing.py Rewrote with TS-mirrored tiers, modern models, family prefixes, openrouter vendor-prefix handling. New get_pricing returns dict or None. New helpers is_known_pricing, compute_session_cost, format_cost_usd.
src/services/cost_tracker.py Legacy facade now get_pricing(model) or DEFAULT_PRICING — preserves always-charge-something contract while the new path sees None.
src/repl/core.py _bottom_toolbar appends cost segment.
src/tui/widgets/status_line.py _compose_text appends cost segment to right_bits.
tests/test_pricing_status_bar.py New, 24 tests.

Tests

  • 658 passed across the full advisor + adapter + TUI + smoke + cost_tracker + new pricing suites.
  • Live helper output (your config: haiku-4-5 worker + opus-4-7 advisor):
    • typical session: $0.021 total
    • heavy session: $3.150 total

Honest caveat

Cost reflects upstream Anthropic list prices. Routes through litellm/openrouter/bedrock may bill differently (your actual invoice could be a markup or a discount). The displayed number is a directional estimate, not your invoice.

🤖 Generated with Claude Code

The status bar already showed token counts and (after the multi-provider
rewrite) split them by worker vs advisor. This PR adds the dollar
cost segment so users can see the spend at a glance — separately for
worker and advisor accumulators, summed to one display number.

## Display

Both surfaces append a `cost $X.XXX` segment after the token counts:

```
REPL: ... tokens: 5400 in / 320 out (advisor: 1326 in / 282 out) · cost $0.021
TUI:  ... tokens 5720 · advisor 1326/282 · cost $0.021
```

Hidden when zero (no API turns or no known pricing).

## Pricing

Mirrors `typescript/src/utils/modelCost.ts` byte-for-byte:

* haiku-4-5: $1 in / $5 out per Mtok (HAIKU_45 tier)
* sonnet-4-6 + family: $3 in / $15 out (3_15 tier)
* opus-4-5/4-6/4-7: $5 in / $25 out (5_25 tier)
* opus-4-0/4-1 (legacy): $15 in / $75 out (15_75 tier)
* Cache pricing: 1.25× input for creation, ~1/10 input for read

Per-model exact match → strip openrouter `<vendor>/` prefix → family
prefix → None. Critic-driven: returning None for unknowns (instead of
silently mispricing as Sonnet-3/15 like the old default did) prevents
10× errors on non-Claude models like DeepSeek ($0.27 vs $3).

## Files

| File | Change |
|---|---|
| `src/services/pricing.py` | Rewrote with TS-mirrored tiers, modern model table, family-prefix list, openrouter vendor-prefix handling. New `get_pricing(model) → dict\|None`, `is_known_pricing`, `compute_session_cost`, `format_cost_usd` helpers. `compute_cost` returns 0 for unknowns instead of falling to default. |
| `src/services/cost_tracker.py` | Legacy facade now uses `get_pricing(model) or DEFAULT_PRICING` to preserve always-charge-something contract while letting the new path see None. |
| `src/repl/core.py` | `_bottom_toolbar` appends `· cost $X.XXX` segment. |
| `src/tui/widgets/status_line.py` | `_compose_text` appends `cost $X.XXX` to right_bits. |
| `tests/test_pricing_status_bar.py` | New, 24 tests covering get_pricing/compute_cost/compute_session_cost/format_cost_usd + boundary cases (1¢ cutoff, $10 cutoff) + critic-flagged regression tests (unknown returns None, no bare opus-4 prefix). |

## Critic-driven fixes (one round, all addressed)

* **C1** (critical): `DEFAULT_PRICING` was Sonnet 3/15 — silently mispricing
  DeepSeek/Gemini/GPT-5 by ~10×. Now unknowns return None and the
  status segment is suppressed. Honesty over false precision.
* **C2** (critical): `claude-opus-4` bare prefix would have routed future
  variants (claude-opus-4-9-…) onto the legacy 15/75 tier. Dropped
  the bare entry so future Opus variants fall through to None.
* **C3** (critical): dead `claude-haiku-3-5` prefix (canonical name is
  `claude-3-5-haiku-…`). Dropped.
* **S5**: REPL had `cost: $X.XXX` (colon) while TUI had `cost $X.XXX`
  (space). Unified to space-separated on both surfaces.

## Tests

* **658 passed** across the full advisor + adapter + TUI + smoke +
  cost_tracker + new pricing suites.
* Live helper output sanity-check:
  - typical (haiku-4-5 worker + opus-4-7 advisor): $0.021 total
  - heavy session: $3.150 total
  Matches Anthropic list prices to the digit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@agentforce314
agentforce314 merged commit 21d6a24 into main May 21, 2026
singlaamitesh pushed a commit to singlaamitesh/clawcodex that referenced this pull request Jul 7, 2026
…s-bar-cost

feat(cost): show USD cost in REPL + TUI status bars
singlaamitesh pushed a commit to singlaamitesh/clawcodex that referenced this pull request Jul 7, 2026
…fficient /advisor)

Two new entries at the top of the README News section:

1. Codebase stats: 890 files / 183,768 lines (up from 894 / 177,428
   on 2026-05-16; net +6.3k lines / -4 files in five days). The file
   delta is the agent_loop.py consolidation; the line additions are
   the /advisor multi-provider rewrite + status-bar cost work.

2. /advisor mode as a token-efficient coding agent — narrates the
   PR agentforce314#181agentforce314#193 arc as one story:
   - Cheap worker (haiku-4-5) + expensive reviewer (opus-4-7) only
     at decision points ≈ 6× cheaper than opus-only on typical sessions
   - Explicit <provider>:<model> syntax (agentforce314#192)
   - Cross-provider routing verified (deepseek worker + opus advisor
     via litellm, agentforce314#182/agentforce314#184/agentforce314#192)
   - Reviewer-quality prompt (agentforce314#188) — Gaps/Risks/Do-next format
   - Live cost + token visibility in status bar (agentforce314#190/agentforce314#191/agentforce314#193)
   - /advisor slash command + dedicated TUI row (agentforce314#181)

Docs-only — no code or test changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant