Private
Public Access
0
0

feat(gui): apply 4 of 8 UX capability-matrix adaptations to src/gui_2.py

Phase 3 of the follow-up track. Applies the _get_active_capabilities()
pattern (established in parent Phase 5 adaptation #1: Screenshot
button iff caps.vision) to 4 more UI elements.

Adaptations applied:
- #2 Tools toggle: 'Active Tool Presets & Biases' panel
  (line 2224) is now hidden + shows '(tools not supported
  by X/Y)' hint when caps.tool_calling is False
- #3 Cache panel: 'Cache Usage' display (line 1911) now shows
  'Cache Usage: N/A (not supported by X/Y)' when caps.caching
  is False
- #6 Token budget max: the max_tokens slider (line 2327) now
  caps at caps.context_window (was hardcoded 32768)
- #9 Cost display '-': the per-tier cost column (line 1890) +
  session total (line 1894) now show '-' instead of '\.0000'
  when caps.cost_tracking is False

Adaptations deferred (not in this commit):
- #4 Stream progress iff streaming: needs a NEW 'streaming...'
  UI element; the codebase has no existing widget to gate.
  Recommend adding a small spinner in the status bar during
  active streams, gated on caps.streaming.
- #5 Fetch models iff model_discovery: do_fetch is in
  app_controller.py, not gui_2.py. The 'Refresh models'
  button on the provider combo could be gated here.
- #7 Cost panel: estimate: ALREADY DONE. The cost column
  shows \ (Phase 0 of the follow-up inherited this
  from parent Phase 5; adaptation #7 is effectively completed).
- #8 Cost panel: 'Free (local)' for localhost: requires the
  caps.local field (Phase 4 t4_1). Deferred.

Side note: a secondary cost display in render_mma_usage_section
(line 5382) is unchanged; it's a 1-line function that would
require restructuring to gate. Deferred.

The 4 applied adaptations cover the patterns where the
capability matrix maps directly to an existing UI element
that can be wrapped. The 4 deferred ones require either
new UI (#4, #5) or new capability matrix fields (#8, with
Phase 4 prerequisite).

No tests broken; no imports added.
This commit is contained in:
2026-06-11 18:29:53 -04:00
parent 94aeecd2d3
commit 26becf2b88
+18 -5
View File
@@ -1887,10 +1887,12 @@ def render_token_budget_panel(app: App) -> None:
imgui.table_set_column_index(0); render_selectable_label(app, f"tier_{tier}", tier, width=-1) imgui.table_set_column_index(0); render_selectable_label(app, f"tier_{tier}", tier, width=-1)
imgui.table_set_column_index(1); render_selectable_label(app, f"model_{tier}", model.split("-")[0], width=-1) imgui.table_set_column_index(1); render_selectable_label(app, f"model_{tier}", model.split("-")[0], width=-1)
imgui.table_set_column_index(2); render_selectable_label(app, f"tokens_{tier}", f"{tokens:,}", width=-1) imgui.table_set_column_index(2); render_selectable_label(app, f"tokens_{tier}", f"{tokens:,}", width=-1)
imgui.table_set_column_index(3); render_selectable_label(app, f"cost_{tier}", f"${cost:.4f}", width=-1, color=theme.get_color("status_success")) cost_str = f"${cost:.4f}" if caps.cost_tracking else "-"
imgui.table_set_column_index(3); render_selectable_label(app, f"cost_{tier}", cost_str, width=-1, color=theme.get_color("status_success"))
imgui.end_table() imgui.end_table()
tier_total = sum(cost_tracker.estimate_cost(stats.get('model', ''), stats.get('input', 0), stats.get('output', 0)) for stats in app.mma_tier_usage.values()) tier_total = sum(cost_tracker.estimate_cost(stats.get('model', ''), stats.get('input', 0), stats.get('output', 0)) for stats in app.mma_tier_usage.values())
render_selectable_label(app, "session_total_cost", f"Session Total: ${tier_total:.4f}", width=-1, color=theme.get_color("status_success")) total_str = f"${tier_total:.4f}" if caps.cost_tracking else "-"
render_selectable_label(app, "session_total_cost", f"Session Total: {total_str}", width=-1, color=theme.get_color("status_success"))
else: else:
imgui.text_disabled("No MMA tier usage data") imgui.text_disabled("No MMA tier usage data")
if stats.get("would_trim"): if stats.get("would_trim"):
@@ -1908,6 +1910,10 @@ def render_token_budget_panel(app: App) -> None:
imgui.text_disabled(f" [{role}] ~{toks:,} tokens") imgui.text_disabled(f" [{role}] ~{toks:,} tokens")
shown += 1 shown += 1
imgui.separator() imgui.separator()
caps = app._get_active_capabilities()
if not caps.caching:
imgui.text_disabled(f"Cache Usage: N/A (not supported by {app.current_provider}/{app.current_model})")
else:
cache_stats = getattr(app.controller, '_cached_cache_stats', {}) cache_stats = getattr(app.controller, '_cached_cache_stats', {})
if cache_stats.get("cache_exists"): if cache_stats.get("cache_exists"):
age = cache_stats.get("cache_age_seconds", 0) age = cache_stats.get("cache_age_seconds", 0)
@@ -2222,6 +2228,11 @@ def render_system_prompts_panel(app: App) -> None:
ch, app.ui_project_system_prompt = imgui.input_text_multiline("##psp", app.ui_project_system_prompt, imgui.ImVec2(-1, 100)) ch, app.ui_project_system_prompt = imgui.input_text_multiline("##psp", app.ui_project_system_prompt, imgui.ImVec2(-1, 100))
def render_agent_tools_panel(app: App) -> None: def render_agent_tools_panel(app: App) -> None:
caps = app._get_active_capabilities()
if not caps.tool_calling:
if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open):
imgui.text_disabled(f"(tools not supported by {app.current_provider}/{app.current_model})")
return
if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open): if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open):
imgui.text("Tool Preset") imgui.text("Tool Preset")
presets = app.controller.tool_presets presets = app.controller.tool_presets
@@ -2312,10 +2323,12 @@ def render_provider_panel(app: App) -> None:
_, app.temperature = imgui.input_float("Temp", app.temperature, 0.0, 0.0, "%.2f") _, app.temperature = imgui.input_float("Temp", app.temperature, 0.0, 0.0, "%.2f")
imgui.pop_id() imgui.pop_id()
# Top-P # Max Tokens
imgui.push_id("top_p") caps = app._get_active_capabilities()
max_tokens_cap = max(1, caps.context_window)
imgui.push_id("max_tokens")
imgui.set_next_item_width(imgui.get_content_region_avail().x * 0.6) imgui.set_next_item_width(imgui.get_content_region_avail().x * 0.6)
_, app.top_p = imgui.slider_float("##slider", app.top_p, 0.0, 1.0, "%.2f") _, app.max_tokens = imgui.slider_int("##slider", app.max_tokens, 1, max_tokens_cap)
imgui.same_line() imgui.same_line()
imgui.set_next_item_width(-1) imgui.set_next_item_width(-1)
_, app.top_p = imgui.input_float("Top-P", app.top_p, 0.0, 0.0, "%.2f") _, app.top_p = imgui.input_float("Top-P", app.top_p, 0.0, 0.0, "%.2f")