Skip to content
Open
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
10 changes: 8 additions & 2 deletions src/copilot_usage/render_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,16 @@ def _render_active_period(
*,
target_console: Console | None = None,
) -> None:
"""Show model calls / messages / tokens since last shutdown (if active)."""
"""Show model calls / messages / tokens since last shutdown (if active).

The panel is only rendered when *summary* has prior shutdown data
(``has_shutdown_metrics=True``). For pure-active sessions the
numbers would duplicate the aggregate stats panel, and the "since
last shutdown" label would be factually wrong.
"""
out = target_console or Console()

if not summary.is_active:
if not summary.is_active or not summary.has_shutdown_metrics:
return

content = (
Expand Down
11 changes: 9 additions & 2 deletions src/copilot_usage/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,9 @@ def _render_active_section_from(

*active* must already contain only sessions where ``is_active`` is
``True``. No filtering is performed here.

The table title includes "Since Last Shutdown" only when at least one
session has prior shutdown data (``has_shutdown_metrics=True``).
"""
if not active:
console.print(
Expand All @@ -554,9 +557,13 @@ def _render_active_section_from(
)
return

table = Table(
title="🟒 Active Sessions (Since Last Shutdown)", border_style="green"
has_resumed = any(s.has_shutdown_metrics for s in active)
title = (
"🟒 Active Sessions (Since Last Shutdown)"
if has_resumed
else "🟒 Active Sessions"
)
table = Table(title=title, border_style="green")
table.add_column("Name", style="bold", max_width=40)
table.add_column("Model")
table.add_column("Model Calls", justify="right")
Expand Down
48 changes: 45 additions & 3 deletions tests/copilot_usage/test_render_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,10 +798,11 @@ class TestRenderActivePeriod:
"""Direct unit tests for _render_active_period covering active / inactive."""

def test_active_session_renders_panel(self) -> None:
"""Active session must render an 'Active Period' panel with stats."""
"""Active session with shutdown history must render an 'Active Period' panel."""
summary = SessionSummary(
session_id="active-test",
is_active=True,
has_shutdown_metrics=True,
model_calls=3,
user_messages=2,
active_model_calls=3,
Expand All @@ -822,18 +823,59 @@ def test_inactive_session_produces_no_output(self) -> None:
_render_active_period(summary, target_console=console)
assert buf.getvalue() == ""

def test_pure_active_session_no_active_period_panel(self) -> None:
"""Pure-active session (no shutdown history) must not render the panel.

When ``has_shutdown_metrics`` is ``False`` the active-period numbers
duplicate the aggregate stats and the "since last shutdown" label is
factually wrong (issue #1070).
"""
summary = SessionSummary(
session_id="pure-active",
is_active=True,
has_shutdown_metrics=False,
model_calls=4,
user_messages=2,
active_model_calls=4,
active_user_messages=2,
active_output_tokens=800,
)
buf, console = _buf_console()
_render_active_period(summary, target_console=console)
assert buf.getvalue() == ""

def test_resumed_session_shows_active_period_panel(self) -> None:
"""Resumed session (has_shutdown_metrics=True) must render the panel."""
summary = SessionSummary(
session_id="resumed",
is_active=True,
has_shutdown_metrics=True,
model_calls=10,
user_messages=5,
active_model_calls=3,
active_user_messages=1,
active_output_tokens=500,
)
buf, console = _buf_console()
_render_active_period(summary, target_console=console)
output = _strip_ansi(buf.getvalue())
assert "Active Period" in output
assert "3 model calls" in output
assert "1 user messages" in output


class TestRenderSessionDetailActivePeriod:
"""Integration test: render_session_detail with is_active=True must
render the Active Period panel (issue #879)."""

def test_active_session_shows_active_period_panel(self) -> None:
"""render_session_detail with is_active=True must include the
Active Period panel in its output."""
"""render_session_detail with is_active=True and has_shutdown_metrics=True
must include the Active Period panel in its output."""
summary = SessionSummary(
session_id="active-e2e",
start_time=datetime(2026, 4, 1, 10, 0, 0, tzinfo=UTC),
is_active=True,
has_shutdown_metrics=True,
model_calls=5,
user_messages=3,
active_model_calls=5,
Expand Down
55 changes: 55 additions & 0 deletions tests/copilot_usage/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -6405,3 +6405,58 @@ def spy(session: SessionSummary) -> int:
"total_output_tokens should not be called for resumed sessions "
"with model_metrics"
)


# ---------------------------------------------------------------------------
# Issue #1070 β€” active section title reflects shutdown history
# ---------------------------------------------------------------------------


class TestActiveSectionTitle:
"""The active-section table title must say 'Since Last Shutdown' only
when at least one active session has prior shutdown data."""

def test_pure_active_session_active_section_title(self) -> None:
"""Pure-active sessions β†’ title must NOT contain 'Since Last Shutdown'."""
session = SessionSummary(
session_id="pure-active-title",
name="PureActive",
model="gpt-5-mini",
start_time=datetime(2026, 4, 1, 10, 0, tzinfo=UTC),
is_active=True,
has_shutdown_metrics=False,
model_calls=5,
user_messages=3,
active_model_calls=5,
active_user_messages=3,
active_output_tokens=1000,
)
output = _capture_full_summary([session])
assert "Active Sessions" in output
assert "Since Last Shutdown" not in output

def test_resumed_session_active_section_title(self) -> None:
"""Resumed session β†’ title must contain 'Since Last Shutdown'."""
session = SessionSummary(
session_id="resumed-title",
name="Resumed",
model="gpt-5-mini",
start_time=datetime(2026, 4, 1, 10, 0, tzinfo=UTC),
is_active=True,
has_shutdown_metrics=True,
total_premium_requests=5,
total_api_duration_ms=100,
model_calls=10,
user_messages=5,
active_model_calls=3,
active_user_messages=1,
active_output_tokens=500,
model_metrics={
"gpt-5-mini": ModelMetrics(
requests=RequestMetrics(count=7, cost=0),
usage=TokenUsage(outputTokens=2000),
)
},
)
output = _capture_full_summary([session])
assert "Since Last Shutdown" in output
Loading