fix(gui): move heavy processing from render loop to controller - gui only visualizes state

This commit is contained in:
2026-03-07 11:11:57 -05:00
parent c14f63fa26
commit d6cdbf21d7
2 changed files with 22 additions and 27 deletions

View File

@@ -146,6 +146,7 @@ class AppController:
self.mma_status: str = "idle"
self._tool_log: List[Dict[str, Any]] = []
self._tool_stats: Dict[str, Dict[str, Any]] = {} # {tool_name: {"count": 0, "total_time_ms": 0.0, "failures": 0}}
self._cached_cache_stats: Dict[str, Any] = {} # Pre-computed cache stats for GUI
self._comms_log: List[Dict[str, Any]] = []
self.session_usage: Dict[str, Any] = {
"input_tokens": 0,
@@ -1740,6 +1741,17 @@ class AppController:
count = cache_stats.get("cache_count", 0)
size_bytes = cache_stats.get("total_size_bytes", 0)
self._gemini_cache_text = f"Gemini Caches: {count} ({size_bytes / 1024:.1f} KB)"
self._update_cached_stats()
def _update_cached_stats(self) -> None:
import ai_client
self._cached_cache_stats = ai_client.get_gemini_cache_stats()
self._cached_tool_stats = dict(self._tool_stats)
def clear_cache(self) -> None:
import ai_client
ai_client.cleanup()
self._update_cached_stats()
def _flush_to_project(self) -> None:
proj = self.project

View File

@@ -1433,38 +1433,22 @@ class App:
imgui.text_disabled(f" [{role}] ~{toks:,} tokens")
shown += 1
imgui.separator()
if ai_client._provider == "gemini":
if ai_client._gemini_cache is not None:
age = time.time() - (ai_client._gemini_cache_created_at or time.time())
ttl = ai_client._GEMINI_CACHE_TTL
imgui.text_colored(C_LBL, f"Gemini Cache: ACTIVE | Age: {age:.0f}s / {ttl}s | Renews at: {ttl * 0.9:.0f}s")
else:
imgui.text_disabled("Gemini Cache: INACTIVE")
elif ai_client._provider == "anthropic":
with ai_client._anthropic_history_lock:
turns = len(ai_client._anthropic_history)
cache_reads = 0
for entry in reversed(ai_client.get_comms_log()):
if entry.get("kind") == "response":
cache_reads = (entry.get("payload") or {}).get("usage", {}).get("cache_read_input_tokens") or 0
break
imgui.text_disabled("Anthropic: 4-breakpoint ephemeral caching (auto-managed)")
imgui.text_disabled(f" {turns} history turns | Cache reads last call: {cache_reads:,}")
cache_stats = getattr(self.controller, '_cached_cache_stats', {})
if cache_stats.get("cache_exists"):
age = cache_stats.get("cache_age_seconds", 0)
ttl = cache_stats.get("ttl_seconds", 3600)
imgui.text_colored(C_LBL, f"Gemini Cache: ACTIVE | Age: {age:.0f}s / {ttl}s | Renews at: {ttl * 0.9:.0f}s")
else:
imgui.text_disabled("Gemini Cache: INACTIVE")
def _render_cache_panel(self) -> None:
if self.current_provider != "gemini":
return
if not imgui.collapsing_header("Cache Analytics"):
return
now = time.time()
if not hasattr(self, '_cache_stats_cache_time') or now - self._cache_stats_cache_time > 1.0:
self._cached_cache_stats = ai_client.get_gemini_cache_stats()
self._cache_stats_cache_time = now
stats = self._cached_cache_stats
stats = getattr(self.controller, '_cached_cache_stats', {})
if not stats.get("cache_exists"):
imgui.text_disabled("No active cache")
if imgui.button("Force Cache"):
pass
return
age_sec = stats.get("cache_age_seconds", 0)
ttl_remaining = stats.get("ttl_remaining", 0)
@@ -1483,7 +1467,7 @@ class App:
imgui.progress_bar(ttl_pct / 100.0, imgui.ImVec2(-1, 0), f"{ttl_pct:.0f}%")
imgui.pop_style_color()
if imgui.button("Clear Cache"):
ai_client.cleanup()
self.controller.clear_cache()
self._cache_cleared_timestamp = time.time()
if hasattr(self, '_cache_cleared_timestamp') and time.time() - self._cache_cleared_timestamp < 5:
imgui.text_colored(imgui.ImVec4(0.2, 1.0, 0.2, 1.0), "Cache cleared - will rebuild on next request")
@@ -1494,8 +1478,7 @@ class App:
now = time.time()
if not hasattr(self, '_tool_stats_cache_time') or now - self._tool_stats_cache_time > 1.0:
self._cached_tool_stats = getattr(self.controller, '_tool_stats', {})
self._tool_stats_cache_time = now
tool_stats = getattr(self, '_cached_tool_stats', {})
tool_stats = getattr(self.controller, '_cached_tool_stats', {})
if not tool_stats:
imgui.text_disabled("No tool usage data")
return