fix(cli): align wide and combining Unicode cost labels

This commit is contained in:
Tin Chi Lo 2026-09-14 23:45:48 -07:00
parent bebc76316c
commit 4fca818f34
2 changed files with 45 additions and 2 deletions

View file

@ -28,6 +28,7 @@ import os
import sys
import tempfile
import time
import unicodedata
import urllib.error
import urllib.request
from collections.abc import Callable, Mapping
@ -301,6 +302,14 @@ def _bar(fraction: float, color: str, width: int, use_color: bool) -> str:
return f"{color}{BAR_FULL * filled}{DIM}{BAR_EMPTY * (width - filled)}{RESET}"
def _display_width(label: str) -> int:
return sum(
2 if unicodedata.east_asian_width(character) in ("W", "F") else 1
for character in label
if unicodedata.category(character) not in ("Mn", "Me")
)
def render(model: str, session: Session | None, config_dir: Path, use_color: bool, bar_width: int = BAR_WIDTH) -> str:
def paint(code: str, text: str) -> str:
return f"{code}{text}{RESET}" if use_color else text
@ -315,13 +324,14 @@ def render(model: str, session: Session | None, config_dir: Path, use_color: boo
pct: Final = (session.baseline_spend - session.spend) / session.baseline_spend * 100
delta: Final = paint(LITELLM_COLOR, f"{'-' if pct >= 0 else '+'}{abs(round(pct))}% vs {reference}")
peak: Final = max(session.spend, session.baseline_spend)
label_width: Final = max(len(session.router_name), len(reference))
label_width: Final = max(_display_width(session.router_name), _display_width(reference))
rows: Final = (
(session.router_name, session.spend, LITELLM_COLOR),
(reference, session.baseline_spend, BASELINE_COLOR),
)
lines: Final = (
f"{paint(DIM, label.ljust(label_width))} {_bar(amount / peak, color, bar_width, use_color)} "
f"{paint(DIM, label + ' ' * (label_width - _display_width(label)))} "
f"{_bar(amount / peak, color, bar_width, use_color)} "
f"{paint(DIM, f'${amount:.2f}')}"
for label, amount, color in rows
)

View file

@ -265,6 +265,39 @@ class TestRender:
"Claude Opus 5 ██████████ $0.38",
]
@pytest.mark.parametrize(
("router_name", "baseline_name", "router_padding", "baseline_padding"),
(
("路由-router", "Claude Opus 5", 3, 1),
("智能模型路由器", "Claude Opus 5", 1, 2),
("-router", "Claude Opus 5", 1, 1),
("cafe\u0301-router", "Claude Opus 5", 3, 1),
("a\u20dd-router", "Claude Opus 5", 6, 1),
("\u3099-router", "Claude Opus 5", 5, 1),
("auto", "基準モデル", 7, 1),
("auto", "cafe\u0301", 1, 1),
),
)
@pytest.mark.parametrize("use_color", (False, True))
def test_unicode_labels_align_cost_bars_by_terminal_columns(
self,
config_dir: Path,
router_name: str,
baseline_name: str,
router_padding: int,
baseline_padding: int,
use_color: bool,
) -> None:
(config_dir / "cache" / "gateway-models.json").write_text(
json.dumps({"models": [{"id": "claude-opus-5", "display_name": baseline_name}]})
)
session: Final = RECORDED._replace(router_name=router_name)
text: Final = ANSI.sub("", render("claude-sonnet-5", session, config_dir, use_color, bar_width=10))
assert text.splitlines()[1:] == [
f"{router_name}{' ' * router_padding}████░░░░░░ $0.14",
f"{baseline_name}{' ' * baseline_padding}██████████ $0.38",
]
def test_control_characters_in_any_externally_sourced_label_never_reach_the_terminal(self, tmp_path, config_dir):
# The transcript, the proxy payload and Claude Code's model cache all feed labels straight into a
# terminal, and none is under this script's control. Only the control bytes are dropped (ESC, BEL,