diff --git a/src/claude_monitor/core/models.py b/src/claude_monitor/core/models.py index 39ac75b0..708fc691 100644 --- a/src/claude_monitor/core/models.py +++ b/src/claude_monitor/core/models.py @@ -167,6 +167,8 @@ def normalize_model_name(model: str) -> str: if "3.5" in model_lower or "3-5" in model_lower: return "claude-3-5-haiku" return "claude-3-haiku" + if "fable" in model_lower: + return model_lower return model diff --git a/src/claude_monitor/ui/progress_bars.py b/src/claude_monitor/ui/progress_bars.py index 845455d2..aaabd0b2 100644 --- a/src/claude_monitor/ui/progress_bars.py +++ b/src/claude_monitor/ui/progress_bars.py @@ -268,6 +268,7 @@ class ModelUsageBar(BaseProgressBar): _FAMILY_STYLES: Final[dict[str, str]] = { "Sonnet": "info", "Opus": "warning", + "Fable": "highlight", "Haiku": "success", "Other": "dim", } @@ -279,6 +280,8 @@ def _family_for(model_name: str) -> str: return "Sonnet" if "opus" in name: return "Opus" + if "fable" in name: + return "Fable" if "haiku" in name: return "Haiku" return "Other" diff --git a/src/tests/test_formatting.py b/src/tests/test_formatting.py index d322aadd..f405bfa2 100644 --- a/src/tests/test_formatting.py +++ b/src/tests/test_formatting.py @@ -441,6 +441,10 @@ def test_normalize_model_name(self) -> None: assert normalize_model_name("Claude 3.5 Sonnet") == "claude-3-5-sonnet" assert normalize_model_name("claude-3-5-haiku") == "claude-3-5-haiku" + # Test Claude 5 models + assert normalize_model_name("claude-fable-5") == "claude-fable-5" + assert normalize_model_name("Claude-Fable-5") == "claude-fable-5" + # Test empty/None inputs assert normalize_model_name("") == "" assert normalize_model_name(None) == "" diff --git a/src/tests/test_progress_bars.py b/src/tests/test_progress_bars.py index c2297756..177f0583 100644 --- a/src/tests/test_progress_bars.py +++ b/src/tests/test_progress_bars.py @@ -34,6 +34,20 @@ def test_render_lists_every_present_family() -> None: assert family in out +def test_render_fable_family_recognized_not_other() -> None: + """Fable 5 usage shows under its own family name, not as 'Other'.""" + bar = ModelUsageBar(width=50) + out = bar.render( + { + "claude-fable-5": _tokens(70), + "claude-sonnet-4-5": _tokens(30), + } + ) + assert "Fable" in out and "70.0%" in out + assert "Sonnet" in out and "30.0%" in out + assert "Other" not in out + + def test_render_unknown_family_shown_as_other_not_dropped() -> None: """An unmapped family still appears (as 'Other'); its share is not silently lost.""" bar = ModelUsageBar(width=50)