Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/copilot_usage/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,15 @@ def _estimate_premium_cost(model: str | None, calls: int) -> str:

Uses :func:`lookup_model_pricing` to look up the multiplier for *model*
and multiplies by *calls*. Returns ``"—"`` when *model* is ``None``.

Warnings from :func:`lookup_model_pricing` (e.g. unknown models) are
suppressed so that normal CLI rendering never emits noise on stderr.
"""
if model is None:
return "—"
pricing = lookup_model_pricing(model)
with warnings.catch_warnings():
warnings.simplefilter("ignore", UserWarning)
pricing = lookup_model_pricing(model)
cost = round(calls * pricing.multiplier)
return f"~{cost}"

Expand Down Expand Up @@ -914,8 +919,8 @@ def render_cost_view(
"""Render per-session, per-model cost breakdown.

Filters sessions by date range when *since* and/or *until* are given.
For active sessions, appends a "↳ Since last shutdown" row with N/A
for premium and the active model calls / output tokens.
For active sessions, appends a "↳ Since last shutdown" row with an
estimated premium cost and the active model calls / output tokens.
"""
console = target_console or Console()
filtered = _filter_sessions(sessions, since, until)
Expand Down
51 changes: 51 additions & 0 deletions tests/copilot_usage/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from copilot_usage.report import (
_aggregate_model_metrics,
_build_event_details,
_estimate_premium_cost,
_event_type_label,
_filter_sessions,
_format_detail_duration,
Expand Down Expand Up @@ -1963,6 +1964,56 @@ def test_pure_active_never_shutdown_cost_falls_back(self) -> None:
f"Output Tokens in active row should be 0, got '{cols[6]}'"
)

def test_active_session_unknown_model_no_warning(self) -> None:
"""Active session with an unknown model must not emit UserWarning."""
session = SessionSummary(
session_id="unknown-model-1234",
name="Unknown Model",
model="experimental-model-42",
start_time=datetime(2025, 1, 15, 10, 0, tzinfo=UTC),
is_active=True,
model_calls=4,
user_messages=2,
active_model_calls=2,
active_output_tokens=300,
)
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", UserWarning)
output = _capture_cost_view([session])
assert "Since last shutdown" in output
assert len(caught) == 0, (
f"Expected no UserWarning, got {[str(w.message) for w in caught]}"
)


# ---------------------------------------------------------------------------
# _estimate_premium_cost tests
# ---------------------------------------------------------------------------


class TestEstimatePremiumCost:
"""Tests for _estimate_premium_cost helper."""

def test_none_model_returns_dash(self) -> None:
assert _estimate_premium_cost(None, 5) == "—"

def test_known_model_returns_estimate(self) -> None:
# claude-opus-4.6 has a 3× multiplier → 3 calls × 3.0 = ~9
assert _estimate_premium_cost("claude-opus-4.6", 3) == "~9"

def test_unknown_model_no_warning(self) -> None:
"""Unknown model degrades to 1× multiplier without emitting warnings."""
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", UserWarning)
result = _estimate_premium_cost("totally-unknown-model-xyz", 7)
assert result == "~7" # 7 calls × 1.0 = ~7
assert len(caught) == 0, (
f"Expected no UserWarning, got {[str(w.message) for w in caught]}"
)

def test_zero_calls_returns_zero(self) -> None:
assert _estimate_premium_cost("claude-sonnet-4", 0) == "~0"


class TestRenderFullSummaryHelperReuse:
"""Verify _render_historical_section delegates to shared table helpers."""
Expand Down
Loading