From d6cdbf21d75810d073b7482d4c4f391f9fbc6b11 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 7 Mar 2026 11:11:57 -0500 Subject: [PATCH] fix(gui): move heavy processing from render loop to controller - gui only visualizes state --- src/app_controller.py | 12 ++++++++++++ src/gui_2.py | 37 ++++++++++--------------------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/app_controller.py b/src/app_controller.py index c10a12d..39178b9 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -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 diff --git a/src/gui_2.py b/src/gui_2.py index 12a5630..684f644 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -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