feat(token-viz): Phase 1 — token budget panel with color bar and breakdown table

This commit is contained in:
2026-03-02 11:16:32 -05:00
parent 80ebc9c4b1
commit 5bfb20f06f
5 changed files with 206 additions and 24 deletions

View File

@@ -296,6 +296,8 @@ class App:
self._token_budget_current = 0
self._token_budget_limit = 0
self._gemini_cache_text = ""
self._last_stable_md: str = ''
self._token_stats: dict = {}
self.ui_disc_truncate_pairs: int = 2
self.ui_auto_scroll_comms = True
self.ui_auto_scroll_tool_calls = True
@@ -552,6 +554,7 @@ class App:
start_time = time.time()
try:
md, path, file_items, stable_md, disc_text = self._do_generate()
self._last_stable_md = stable_md
self.last_md = md
self.last_md_path = path
self.last_file_items = file_items
@@ -1222,6 +1225,7 @@ class App:
"""Logic for the 'Gen + Send' action."""
try:
md, path, file_items, stable_md, disc_text = self._do_generate()
self._last_stable_md = stable_md
self.last_md = md
self.last_md_path = path
self.last_file_items = file_items
@@ -1373,6 +1377,7 @@ class App:
self._token_budget_pct = stats.get("percentage", 0.0) / 100.0
self._token_budget_current = stats.get("current", 0)
self._token_budget_limit = stats.get("limit", 0)
self._token_stats = stats
except Exception:
pass
threading.Thread(target=fetch_stats, daemon=True).start()
@@ -2720,11 +2725,47 @@ class App:
if usage["cache_read_input_tokens"]:
imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}")
imgui.text("Token Budget:")
imgui.progress_bar(self._token_budget_pct, imgui.ImVec2(-1, 0), f"{self._token_budget_current:,} / {self._token_budget_limit:,}")
imgui.separator()
imgui.text("Token Budget")
self._render_token_budget_panel()
if self._gemini_cache_text:
imgui.text_colored(C_SUB, self._gemini_cache_text)
def _render_message_panel(self) -> None:
def _render_token_budget_panel(self) -> None:
stats = self._token_stats
if not stats:
imgui.text_disabled("Token stats unavailable")
return
pct = stats.get("utilization_pct", 0.0)
current = stats.get("estimated_prompt_tokens", 0)
limit = stats.get("max_prompt_tokens", 0)
headroom = stats.get("headroom_tokens", 0)
if pct < 50.0:
color = imgui.ImVec4(0.2, 0.8, 0.2, 1.0)
elif pct < 80.0:
color = imgui.ImVec4(1.0, 0.8, 0.0, 1.0)
else:
color = imgui.ImVec4(1.0, 0.2, 0.2, 1.0)
imgui.push_style_color(imgui.Col_.plot_histogram, color)
imgui.progress_bar(pct / 100.0, imgui.ImVec2(-1, 0), f"{pct:.1f}%")
imgui.pop_style_color()
imgui.text_disabled(f"{current:,} / {limit:,} tokens ({headroom:,} remaining)")
sys_tok = stats.get("system_tokens", 0)
tool_tok = stats.get("tools_tokens", 0)
hist_tok = stats.get("history_tokens", 0)
total_tok = sys_tok + tool_tok + hist_tok or 1
if imgui.begin_table("token_breakdown", 3, imgui.TableFlags_.borders_inner_h | imgui.TableFlags_.sizing_fixed_fit):
imgui.table_setup_column("Component")
imgui.table_setup_column("Tokens")
imgui.table_setup_column("Pct")
imgui.table_headers_row()
for lbl, tok in [("System", sys_tok), ("Tools", tool_tok), ("History", hist_tok)]:
imgui.table_next_row()
imgui.table_set_column_index(0); imgui.text(lbl)
imgui.table_set_column_index(1); imgui.text(f"{tok:,}")
imgui.table_set_column_index(2); imgui.text(f"{tok / total_tok * 100:.0f}%")
imgui.end_table()
# LIVE indicator
is_live = self.ai_status in ["running powershell...", "fetching url...", "searching web...", "powershell done, awaiting AI..."]
if is_live: