From d27c9a1d5d00adedd32d8badd446ecaaa52d109a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Mar 2026 06:12:51 +0000 Subject: [PATCH 1/5] fix: render_live_sessions shows active fields for resumed sessions (#139) For resumed sessions (with active_user_messages or active_output_tokens), render_live_sessions now uses the post-resume active_* fields instead of the historical totals from model_metrics/user_messages. This matches the pattern already used by _render_active_section. Pure-active sessions (never shut down) remain unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/copilot_usage/report.py | 13 +++++++-- tests/copilot_usage/test_report.py | 42 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/copilot_usage/report.py b/src/copilot_usage/report.py index a38fbe0..6d16605 100644 --- a/src/copilot_usage/report.py +++ b/src/copilot_usage/report.py @@ -155,8 +155,17 @@ def render_live_sessions(sessions: list[SessionSummary]) -> None: name = s.name or "—" model = s.model or "—" running = _format_session_running_time(s) - messages = str(s.user_messages) - tokens = format_tokens(_estimated_output_tokens(s)) + + if s.active_user_messages or s.active_output_tokens: + # Resumed session: show post-resume stats + messages = str(s.active_user_messages) + output_tok = s.active_output_tokens + else: + # Pure-active (never shut down): totals are already in model_metrics + messages = str(s.user_messages) + output_tok = _estimated_output_tokens(s) + + tokens = format_tokens(output_tok) cwd = s.cwd or "—" table.add_row( diff --git a/tests/copilot_usage/test_report.py b/tests/copilot_usage/test_report.py index 30e8e2a..97134aa 100644 --- a/tests/copilot_usage/test_report.py +++ b/tests/copilot_usage/test_report.py @@ -275,6 +275,48 @@ def test_last_resume_time_used_over_start_time(self) -> None: # Should show minutes (from last_resume_time), NOT days (from start_time) assert "2d" not in output and "48h" not in output + def test_resumed_session_shows_active_fields(self) -> None: + """Resumed session should show active_user_messages and active_output_tokens.""" + now = datetime.now(tz=UTC) + session = SessionSummary( + session_id="resumed_12345678", + name="Resumed Heavy", + model="claude-sonnet-4", + is_active=True, + start_time=now - timedelta(hours=3), + last_resume_time=now - timedelta(minutes=10), + # Historical totals (from shutdown events) + user_messages=50, + model_metrics={ + "claude-sonnet-4": ModelMetrics( + usage=TokenUsage(outputTokens=200_000), + ) + }, + # Post-resume activity + active_user_messages=7, + active_output_tokens=35_000, + active_model_calls=12, + ) + output = _capture_output([session]) + # Should show the active-period values, not historical totals + assert "7" in output # active_user_messages, not 50 + assert "35.0K" in output # active_output_tokens, not 200K + assert "50" not in output # historical total should NOT appear + assert "200.0K" not in output # historical tokens should NOT appear + + def test_pure_active_session_uses_totals(self) -> None: + """Pure-active session (no prior shutdown) should still use totals.""" + now = datetime.now(tz=UTC) + session = _make_session( + user_messages=12, + output_tokens=8_000, + start_time=now - timedelta(minutes=5), + ) + # active_user_messages and active_output_tokens default to 0 + output = _capture_output([session]) + assert "12" in output # user_messages + assert "8.0K" in output # from model_metrics + # --------------------------------------------------------------------------- # Helpers for session detail tests From 6506bb667d4c31450c644d8d75e5fbf3a1ceeefb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Mar 2026 06:26:06 +0000 Subject: [PATCH 2/5] fix: address review comments Harden test_resumed_session_shows_active_fields assertions: - Use a session_id without digits that could match test values - Use more distinctive numeric values (91, 263) for messages - Use word-boundary regex for integer assertions to prevent false positives from substring matches in other columns Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_report.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/copilot_usage/test_report.py b/tests/copilot_usage/test_report.py index 97134aa..67604db 100644 --- a/tests/copilot_usage/test_report.py +++ b/tests/copilot_usage/test_report.py @@ -4,6 +4,7 @@ from __future__ import annotations +import re from datetime import UTC, datetime, timedelta from io import StringIO from unittest.mock import patch @@ -279,29 +280,33 @@ def test_resumed_session_shows_active_fields(self) -> None: """Resumed session should show active_user_messages and active_output_tokens.""" now = datetime.now(tz=UTC) session = SessionSummary( - session_id="resumed_12345678", - name="Resumed Heavy", + session_id="aabbccdd-eeee-ffff-aaaa-bbbbbbbbbbbb", + name="Resumed Task", model="claude-sonnet-4", is_active=True, start_time=now - timedelta(hours=3), last_resume_time=now - timedelta(minutes=10), # Historical totals (from shutdown events) - user_messages=50, + user_messages=263, model_metrics={ "claude-sonnet-4": ModelMetrics( usage=TokenUsage(outputTokens=200_000), ) }, # Post-resume activity - active_user_messages=7, + active_user_messages=91, active_output_tokens=35_000, active_model_calls=12, ) output = _capture_output([session]) - # Should show the active-period values, not historical totals - assert "7" in output # active_user_messages, not 50 - assert "35.0K" in output # active_output_tokens, not 200K - assert "50" not in output # historical total should NOT appear + # Should show the active-period values, not historical totals. + # Use word-boundary regex so assertions are not fooled by + # substring matches in session IDs, names, or other columns. + assert re.search(r"\b91\b", output), "active_user_messages (91) not found" + assert "35.0K" in output # active_output_tokens + assert not re.search(r"\b263\b", output), ( + "historical total (263) should not appear" + ) assert "200.0K" not in output # historical tokens should NOT appear def test_pure_active_session_uses_totals(self) -> None: From 25c4c058d2c2775bae57c1e5b1badeda4ebbdbd5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Mar 2026 07:14:56 +0000 Subject: [PATCH 3/5] fix: address review comments - Use last_resume_time to detect resumed sessions instead of truthiness check on active_user_messages/active_output_tokens, fixing the edge case where a resumed session with zero post-resume activity would incorrectly show historical totals. - Fix test_pure_active_session_uses_totals: use a clean session_id and word-boundary regex to prevent false positives from substring matches. - Add test_resumed_session_zero_activity_shows_zeros for the zero- activity resumed session edge case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/copilot_usage/report.py | 4 ++-- tests/copilot_usage/test_report.py | 31 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/copilot_usage/report.py b/src/copilot_usage/report.py index 6d16605..608e1f9 100644 --- a/src/copilot_usage/report.py +++ b/src/copilot_usage/report.py @@ -156,8 +156,8 @@ def render_live_sessions(sessions: list[SessionSummary]) -> None: model = s.model or "—" running = _format_session_running_time(s) - if s.active_user_messages or s.active_output_tokens: - # Resumed session: show post-resume stats + if s.last_resume_time is not None: + # Resumed session: show post-resume stats (even when 0) messages = str(s.active_user_messages) output_tok = s.active_output_tokens else: diff --git a/tests/copilot_usage/test_report.py b/tests/copilot_usage/test_report.py index 67604db..b397b99 100644 --- a/tests/copilot_usage/test_report.py +++ b/tests/copilot_usage/test_report.py @@ -313,15 +313,44 @@ def test_pure_active_session_uses_totals(self) -> None: """Pure-active session (no prior shutdown) should still use totals.""" now = datetime.now(tz=UTC) session = _make_session( + session_id="pure_active_session", user_messages=12, output_tokens=8_000, start_time=now - timedelta(minutes=5), ) # active_user_messages and active_output_tokens default to 0 output = _capture_output([session]) - assert "12" in output # user_messages + assert re.search(r"\b12\b", output) # user_messages assert "8.0K" in output # from model_metrics + def test_resumed_session_zero_activity_shows_zeros(self) -> None: + """Resumed session with zero post-resume activity shows 0, not historical totals.""" + now = datetime.now(tz=UTC) + session = SessionSummary( + session_id="aabbccdd-eeee-ffff-aaaa-cccccccccccc", + name="Just Resumed", + model="claude-sonnet-4", + is_active=True, + start_time=now - timedelta(hours=1), + last_resume_time=now - timedelta(seconds=30), + user_messages=150, + model_metrics={ + "claude-sonnet-4": ModelMetrics( + usage=TokenUsage(outputTokens=100_000), + ) + }, + # Zero post-resume activity + active_user_messages=0, + active_output_tokens=0, + active_model_calls=0, + ) + output = _capture_output([session]) + # Should show 0 for messages (active), not 150 (historical) + assert not re.search(r"\b150\b", output), ( + "historical total (150) should not appear" + ) + assert "100.0K" not in output # historical tokens should NOT appear + # --------------------------------------------------------------------------- # Helpers for session detail tests From 733ea4624bea873f04bf9d64d627fbd7049944bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 20 Mar 2026 16:24:44 +0000 Subject: [PATCH 4/5] fix: address review comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_report.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/copilot_usage/test_report.py b/tests/copilot_usage/test_report.py index b397b99..4397998 100644 --- a/tests/copilot_usage/test_report.py +++ b/tests/copilot_usage/test_report.py @@ -350,6 +350,16 @@ def test_resumed_session_zero_activity_shows_zeros(self) -> None: "historical total (150) should not appear" ) assert "100.0K" not in output # historical tokens should NOT appear + # And should explicitly render zeros for the active period + session_line = next( + (line for line in output.splitlines() if "Just Resumed" in line), + "", + ) + # Expect at least two whole-word zeros on the session row (Messages and Output Tokens) + zeros_on_row = re.findall(r"\b0\b", session_line) + assert len(zeros_on_row) >= 2, ( + "resumed session row should show 0 for both messages and output tokens" + ) # --------------------------------------------------------------------------- From 918625bcbb6a852d1a6136463845a53b76c58afc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 21 Mar 2026 01:50:48 +0000 Subject: [PATCH 5/5] fix: address review comments Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/copilot_usage/report.py | 9 +++++++-- tests/copilot_usage/test_report.py | 31 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/copilot_usage/report.py b/src/copilot_usage/report.py index 608e1f9..62e67f4 100644 --- a/src/copilot_usage/report.py +++ b/src/copilot_usage/report.py @@ -156,8 +156,13 @@ def render_live_sessions(sessions: list[SessionSummary]) -> None: model = s.model or "—" running = _format_session_running_time(s) - if s.last_resume_time is not None: - # Resumed session: show post-resume stats (even when 0) + has_active_stats = ( + s.last_resume_time is not None + or s.active_user_messages > 0 + or s.active_output_tokens > 0 + ) + if has_active_stats: + # Resumed/active session with post-resume stats (even when 0) messages = str(s.active_user_messages) output_tok = s.active_output_tokens else: diff --git a/tests/copilot_usage/test_report.py b/tests/copilot_usage/test_report.py index 4397998..754528a 100644 --- a/tests/copilot_usage/test_report.py +++ b/tests/copilot_usage/test_report.py @@ -309,6 +309,37 @@ def test_resumed_session_shows_active_fields(self) -> None: ) assert "200.0K" not in output # historical tokens should NOT appear + def test_active_session_without_last_resume_time_shows_active_fields(self) -> None: + """Active session with active_* but no last_resume_time should use active fields.""" + now = datetime.now(tz=UTC) + session = SessionSummary( + session_id="no-resume-event-1234", + name="Active Without Explicit Resume", + model="claude-sonnet-4", + is_active=True, + start_time=now - timedelta(hours=2), + # Historical totals accumulated before the current active period + user_messages=263, + model_metrics={ + "claude-sonnet-4": ModelMetrics( + usage=TokenUsage(outputTokens=200_000), + ) + }, + # Current active-period activity, even though last_resume_time is None + active_user_messages=91, + active_output_tokens=35_000, + active_model_calls=12, + ) + output = _capture_output([session]) + # Should show the active-period values, not historical totals, + # even when last_resume_time is None. + assert re.search(r"\b91\b", output), "active_user_messages (91) not found" + assert "35.0K" in output # active_output_tokens + assert not re.search(r"\b263\b", output), ( + "historical total (263) should not appear" + ) + assert "200.0K" not in output # historical tokens should NOT appear + def test_pure_active_session_uses_totals(self) -> None: """Pure-active session (no prior shutdown) should still use totals.""" now = datetime.now(tz=UTC)