From 6bec4b86efcacc60bd78ccadc1069f274c922b52 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Sat, 9 May 2026 08:32:28 -0400 Subject: [PATCH] feat(controller): Implement @property and @setter for ai_status and mma_status --- src/app_controller.py | 49 ++++++++++++++++++------------ tests/test_status_encapsulation.py | 9 ++++++ 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/app_controller.py b/src/app_controller.py index 733b466..c2e5624 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -143,6 +143,9 @@ class AppController: self._pending_tool_calls_lock: threading.Lock = threading.Lock() self._pending_history_adds_lock: threading.Lock = threading.Lock() self._pending_gui_tasks_lock: threading.Lock = threading.Lock() + self._pending_gui_tasks: List[Dict[str, Any]] = [] + self._ai_status: str = "idle" + self._mma_status: str = "idle" self._pending_dialog_lock: threading.Lock = threading.Lock() self._api_event_queue_lock: threading.Lock = threading.Lock() self.config: Dict[str, Any] = {} @@ -167,8 +170,6 @@ class AppController: self._pending_patch_files: List[str] = [] self._show_patch_modal: bool = False self._patch_error_message: Optional[str] = None - self.mma_status: str = "idle" - 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 @@ -251,8 +252,6 @@ class AppController: self._autofocus_response_tab = False self.proposed_tracks: List[Dict[str, Any]] = [] self._show_track_proposal_modal: bool = False - self.ai_status: str = 'idle' - self._ai_status: str = 'idle' self.ai_response: str = '' self.last_md: str = '' self.last_aggregate_markdown: str = '' @@ -512,6 +511,26 @@ class AppController: except Exception as e: self._inject_preview = f"Error reading file: {e}" + @property + def ai_status(self) -> str: + return self._ai_status + + @ai_status.setter + def ai_status(self, value: str) -> None: + self._ai_status = value + with self._pending_gui_tasks_lock: + self._pending_gui_tasks.append({"action": "set_ai_status", "value": value}) + + @property + def mma_status(self) -> str: + return self._mma_status + + @mma_status.setter + def mma_status(self, value: str) -> None: + self._mma_status = value + with self._pending_gui_tasks_lock: + self._pending_gui_tasks.append({"action": "set_mma_status", "value": value}) + @property def thinking_indicator(self) -> bool: return self.ai_status in ("sending...", "streaming...") @@ -654,19 +673,11 @@ class AppController: def _set_status(self, status: str) -> None: """Thread-safe update of ai_status via the GUI task queue.""" - with self._pending_gui_tasks_lock: - self._pending_gui_tasks.append({ - "action": "set_ai_status", - "payload": status - }) + self.ai_status = status def _set_mma_status(self, status: str) -> None: """Thread-safe update of mma_status via the GUI task queue.""" - with self._pending_gui_tasks_lock: - self._pending_gui_tasks.append({ - "action": "set_mma_status", - "payload": status - }) + self.mma_status = status def _set_rag_status(self, status: str) -> None: """Thread-safe update of rag_status via the GUI task queue.""" @@ -740,9 +751,9 @@ class AppController: elif action == 'set_tool_log_dirty': self._tool_log_dirty = True elif action == "set_ai_status": - self.ai_status = task.get("payload", "") + self._ai_status = task.get("value", task.get("payload", "")) elif action == "set_mma_status": - self.mma_status = task.get("payload", "") + self._mma_status = task.get("value", task.get("payload", "")) elif action == "handle_ai_response": payload = task.get("payload", {}) text = payload.get("text", "") @@ -761,13 +772,13 @@ class AppController: self._worker_status[stream_id] = "completed" if stream_id == "Tier 1": if "status" in payload: - self.ai_status = payload["status"] + self._ai_status = payload["status"] else: if is_streaming: self.ai_response += text else: self.ai_response = text - self.ai_status = payload.get("status", "done") + self._ai_status = payload.get("status", "done") self._trigger_blink = True if not stream_id: self._token_stats_dirty = True @@ -796,7 +807,7 @@ class AppController: is_active_track = True if is_active_track or not self.active_track: - self.mma_status = p.get("status", self.mma_status) + self._mma_status = p.get("status", self._mma_status) old_tier = self.active_tier self.active_tier = p.get("active_tier", self.active_tier) diff --git a/tests/test_status_encapsulation.py b/tests/test_status_encapsulation.py index fef359b..7e5b12b 100644 --- a/tests/test_status_encapsulation.py +++ b/tests/test_status_encapsulation.py @@ -6,3 +6,12 @@ def test_status_attributes_exist(): assert hasattr(controller, '_mma_status') assert controller._ai_status == 'idle' assert controller._mma_status == 'idle' + +def test_status_properties(): + controller = app_controller.AppController() + controller.ai_status = 'busy' + assert controller._ai_status == 'busy' + assert any(t.get('action') == 'set_ai_status' and t.get('value') == 'busy' for t in controller._pending_gui_tasks) + controller.mma_status = 'active' + assert controller._mma_status == 'active' + assert any(t.get('action') == 'set_mma_status' and t.get('value') == 'active' for t in controller._pending_gui_tasks)