feat(usage): multi-provider equivalent cost table

This commit is contained in:
claude
2026-08-22 01:06:02 +00:00
parent 979c93bdbb
commit 33e4c16782
2 changed files with 115 additions and 26 deletions
+50 -13
View File
@@ -91,6 +91,14 @@ STYLE_DEFAULTS: dict[str, tuple[int, str]] = {
# (env) or `.pr-review.json:cost_target` (per repo).
DEFAULT_PRICE_TARGET = "claude-sonnet-5"
# Default roster of paid providers shown in the equivalent-cost table when
# `.pr-review.json` does not pin `compare_against`. The pilot is free-tier only,
# so this list is the operator's budgeting signal — it answers "what would this
# have cost on a mainstream paid API?". Override per-repo via
# `.pr-review.json:compare_against` (capped at 12 entries; unknown keys are
# dropped with a stderr line at parse time).
DEFAULT_COMPARE_AGAINST = ("claude-sonnet-5", "gpt-5", "gemini-2.5-pro", "grok-4.5")
SYSTEM_PROMPT = """You are a senior, pragmatic code reviewer. Review the pull request diff below.
Report ONLY real, actionable issues: correctness bugs, security problems, risky
@@ -1211,9 +1219,13 @@ def findings_table(findings: list[dict]) -> str:
def _render_collapsible_usage(usage: dict | None, model: str, config: dict | None) -> str:
"""Render the telemetry as a collapsible ``<details>`` block.
Empty string when `usage` is None. The cost-equivalent line is always
shown (it's the operator's budgeting signal). The `actual` line is shown
but the FREE-TIER note is collapsed into a single short clause.
Empty string when `usage` is None. The equivalent-cost table is the
operator's budgeting signal — the pilot runs on a free tier, so the
`actual` line is $0.00; the table shows what the same measured tokens
would bill on mainstream paid APIs (configurable via `compare_against`,
defaulting to ``DEFAULT_COMPARE_AGAINST``). The row matching `cost_target`
is bolded so the price target stands out. The whole table is omitted when
every row would be $0 (no work done).
"""
if not usage:
return ""
@@ -1222,15 +1234,34 @@ def _render_collapsible_usage(usage: dict | None, model: str, config: dict | Non
actual = usage.get("cost") or 0.0
actual_s = f"${actual:.4f}" if actual else "$0.00"
actual_note = " (headroom glm-5.2:cloud — free tier)" if not actual else ""
price_key, price_err = _resolve_price_target(config)
from cost_model import PRICES
eq = equivalent_cost(usage, price_key)
eq_s = f"${eq:.4f}" if eq else "$0.00"
eq_label = PRICES[price_key].name
eq_note = (
f" _(price target: `{price_key}`; {price_err})_"
if price_err else ""
)
cost_target, price_err = _resolve_price_target(config)
if price_err:
# Surface config typos loudly but do not pollute the posted summary
# body — typos at the table-row level would render as English
# mid-table and look like a model error.
print(f"pragent: {price_err}", file=sys.stderr, flush=True)
# Lazy: cost_model has no dep on ai_review, and the ollama path
# never reaches this branch.
from cost_model import PRICES as _PRICES
cfg = config or {}
compare: list[str] = list(cfg.get("compare_against") or DEFAULT_COMPARE_AGAINST)
# Always include the resolved cost_target (env + config), even when the
# operator pinned a different `compare_against` roster — the price target
# row is the one maintainers eyeball against. Skip silently if the key
# isn't a known Price (e.g. a typo that slipped past stderr earlier).
if cost_target in _PRICES and cost_target not in compare:
compare.append(cost_target)
eq_rows: list[str] = []
for key in compare:
if key not in _PRICES:
continue
c = equivalent_cost(usage, key)
if c <= 0:
continue
label = _PRICES[key].name
cost_str = f"${c:.4f}" if c < 0.01 else f"${c:.2f}"
bold = "**" if key == cost_target else ""
eq_rows.append(f"| {bold}{label}{bold} | {cost_str} |")
in_tok = usage.get("input", 0)
out_tok = usage.get("output", 0)
reason_tok = usage.get("reasoning", 0)
@@ -1251,10 +1282,16 @@ def _render_collapsible_usage(usage: dict | None, model: str, config: dict | Non
f"- **Total Tokens**: {fmt_tokens(in_tok)} in / {fmt_tokens(out_tok)} out "
f"({fmt_tokens(reason_tok)} reasoning, cache {fmt_tokens(cache_r)} read / "
f"{fmt_tokens(cache_w)} write, {fmt_tokens(total)} total)",
f"- **Est. cost on {eq_label}**: {eq_s}{eq_note}",
f"- **Actual**: {actual_s}{actual_note}",
f"- **Scope**: {scope}",
]
if eq_rows:
lines.append("")
lines.append("- **Equivalent cost on paid providers** (this run's tokens):")
lines.append("")
lines.append("| Provider | Cost |")
lines.append("|---|---:|")
lines.extend(eq_rows)
# Multi-lens fan-out: surface the lens roster + summed steps so the user
# can see which lenses contributed (and that triage didn't drop them all).
lenses = usage.get("lenses")