diff --git a/src/copilot_usage/parser.py b/src/copilot_usage/parser.py index bd2f551..b5399b9 100644 --- a/src/copilot_usage/parser.py +++ b/src/copilot_usage/parser.py @@ -8,6 +8,7 @@ from __future__ import annotations import json +from datetime import UTC, datetime from pathlib import Path from loguru import logger @@ -29,6 +30,16 @@ _DEFAULT_BASE: Path = Path.home() / ".copilot" / "session-state" _CONFIG_PATH: Path = Path.home() / ".copilot" / "config.json" +_RESUME_INDICATOR_TYPES: frozenset[str] = frozenset( + { + EventType.SESSION_RESUME, + EventType.USER_MESSAGE, + EventType.ASSISTANT_MESSAGE, + } +) + +_EPOCH: datetime = datetime.min.replace(tzinfo=UTC) + def _infer_model_from_metrics(metrics: dict[str, ModelMetrics]) -> str | None: """Pick a model name from *metrics* when ``currentModel`` is absent. @@ -234,12 +245,6 @@ def build_session_summary( name = _extract_session_name(session_dir) if session_dir else None # --- Detect resumed session (events after last shutdown) -------------- - _RESUME_INDICATOR_TYPES: set[str] = { - EventType.SESSION_RESUME, - EventType.USER_MESSAGE, - EventType.ASSISTANT_MESSAGE, - } - session_resumed = False post_shutdown_output_tokens = 0 post_shutdown_turn_starts = 0 @@ -365,10 +370,8 @@ def get_all_sessions(base_path: Path | None = None) -> list[SessionSummary]: summary.events_path = events_path summaries.append(summary) - def _sort_key(s: SessionSummary) -> str: - if s.start_time is None: - return "" - return s.start_time.isoformat() + def _sort_key(s: SessionSummary) -> datetime: + return s.start_time if s.start_time is not None else _EPOCH summaries.sort(key=_sort_key, reverse=True) return summaries diff --git a/src/copilot_usage/pricing.py b/src/copilot_usage/pricing.py index 03ef94a..24d9f0b 100644 --- a/src/copilot_usage/pricing.py +++ b/src/copilot_usage/pricing.py @@ -83,6 +83,7 @@ def _tier_from_multiplier(m: float) -> PricingTier: "gpt-5.3-codex": 1.0, "gpt-5.1-codex-max": 1.0, "gpt-5.1-codex-mini": 0.33, + "gpt-5.4-mini": 0.0, "gpt-5-mini": 0.0, "gpt-4.1": 0.0, # Gemini ----------------------------------------------------------------- diff --git a/tests/copilot_usage/test_pricing.py b/tests/copilot_usage/test_pricing.py index 0c59c28..f79d864 100644 --- a/tests/copilot_usage/test_pricing.py +++ b/tests/copilot_usage/test_pricing.py @@ -51,6 +51,7 @@ def test_registry_not_empty(self) -> None: ("gpt-5.1-codex-max", 1.0), ("gpt-4.1", 0.0), ("gpt-5-mini", 0.0), + ("gpt-5.4-mini", 0.0), ("gemini-3-pro-preview", 1.0), ], ) @@ -64,6 +65,7 @@ def test_known_multipliers(self, model: str, expected_mult: float) -> None: ("claude-sonnet-4.6", PricingTier.STANDARD), ("claude-haiku-4.5", PricingTier.LIGHT), ("gpt-5-mini", PricingTier.LIGHT), + ("gpt-5.4-mini", PricingTier.LIGHT), ], ) def test_known_tiers(self, model: str, expected_tier: PricingTier) -> None: