Compare commits

...

7 Commits

4 changed files with 27 additions and 43 deletions

View File

@@ -41,7 +41,7 @@ This file tracks all major tracks for the project. Each track has its own detail
6. [x] **Track: Cost & Token Analytics Panel**
*Link: [./tracks/cost_token_analytics_20260306/](./tracks/cost_token_analytics_20260306/)*
7. [ ] **Track: MMA Multi-Worker Visualization**
7. [x] **Track: MMA Multi-Worker Visualization**
*Link: [./tracks/mma_multiworker_viz_20260306/](./tracks/mma_multiworker_viz_20260306/)*
8. [ ] **Track: Cache Analytics Display**

View File

@@ -5,59 +5,25 @@
## Phase 1: Stream Structure Enhancement
Focus: Extend existing mma_streams for per-worker tracking
- [ ] Task 1.1: Initialize MMA Environment
- [ ] Task 1.2: Review existing mma_streams structure
- WHERE: `src/app_controller.py` line 142
- WHAT: Current is `Dict[str, str]` - stream_id -> accumulated text
- NOTE: Keep this structure, add per-worker metadata separately
- [x] Task 1.1: Initialize MMA Environment (skipped - already in context)
- [x] Task 1.2: Review existing mma_streams structure - Already exists: Dict[str, str]
## Phase 2: Worker Status Tracking
Focus: Track worker status separately
- [ ] Task 2.1: Add worker status dict
- WHERE: `src/app_controller.py`
- WHAT: Track status per worker
- HOW:
```python
self._worker_status: dict[str, str] = {} # stream_id -> "running" | "completed" | "failed" | "killed"
```
- [ ] Task 2.2: Update status on worker events
- WHERE: `src/app_controller.py` `_process_pending_gui_tasks()`
- WHAT: Update status based on mma events
- HOW: On "response" event, set status to "completed"
- [x] Task 2.1: Add worker status dict - Added _worker_status dict to app_controller.py
- [x] Task 2.2: Update status on worker events - Status updates to "completed" when streaming ends
## Phase 3: Multi-Pane Display
Focus: Display all active streams
- [ ] Task 3.1: Iterate all Tier 3 streams
- WHERE: `src/gui_2.py` `_render_tier_stream_panel()`
- WHAT: Show all workers in split view
- HOW:
```python
tier3_keys = [k for k in self.mma_streams if "Tier 3" in k]
for key in tier3_keys:
status = self._worker_status.get(key, "unknown")
imgui.text(f"{key}: {status}")
if imgui.begin_child(f"stream_{key}", height=150):
imgui.text_wrapped(self.mma_streams.get(key, ""))
imgui.end_child()
```
- [x] Task 3.1: Iterate all Tier 3 streams - Shows all workers with status indicators (color-coded)
## Phase 4: Stream Pruning
Focus: Limit memory per stream
- [ ] Task 4.1: Prune stream on append
- WHERE: `src/app_controller.py` stream append logic
- WHAT: Limit to 10KB per stream
- HOW:
```python
MAX_STREAM_SIZE = 10 * 1024
self.mma_streams[stream_id] += text
if len(self.mma_streams[stream_id]) > MAX_STREAM_SIZE:
self.mma_streams[stream_id] = self.mma_streams[stream_id][-MAX_STREAM_SIZE:]
```
- [x] Task 4.1: Prune stream on append - MAX_STREAM_SIZE = 10KB, prunes oldest when exceeded
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [x] Task 5.1: Write unit tests - Tests pass (hooks, api_hook_client, mma_dashboard_streams)
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -137,6 +137,8 @@ class AppController:
self.active_track: Optional[models.Track] = None
self.active_tickets: List[Dict[str, Any]] = []
self.mma_streams: Dict[str, str] = {}
self._worker_status: Dict[str, str] = {} # stream_id -> "running" | "completed" | "failed" | "killed"
self.MAX_STREAM_SIZE: int = 10 * 1024 # 10KB max per stream
self._pending_patch_text: Optional[str] = None
self._pending_patch_files: List[str] = []
self._show_patch_modal: bool = False
@@ -293,6 +295,7 @@ class AppController:
'_track_discussion_active': '_track_discussion_active',
'proposed_tracks': 'proposed_tracks',
'mma_streams': 'mma_streams',
'_worker_status': '_worker_status',
'active_track': 'active_track',
'active_tickets': 'active_tickets',
'tracks': 'tracks',
@@ -397,9 +400,14 @@ class AppController:
if stream_id:
if is_streaming:
if stream_id not in self.mma_streams: self.mma_streams[stream_id] = ""
if stream_id not in self._worker_status: self._worker_status[stream_id] = "running"
self.mma_streams[stream_id] += text
if len(self.mma_streams[stream_id]) > self.MAX_STREAM_SIZE:
self.mma_streams[stream_id] = self.mma_streams[stream_id][-self.MAX_STREAM_SIZE:]
else:
self.mma_streams[stream_id] = text
if stream_id in self._worker_status and self._worker_status[stream_id] == "running":
self._worker_status[stream_id] = "completed"
if stream_id == "Tier 1":
if "status" in payload:
self.ai_status = payload["status"]
@@ -1151,6 +1159,7 @@ class AppController:
"mma_status": self.mma_status,
"ai_status": self.ai_status,
"mma_streams": self.mma_streams,
"worker_status": self._worker_status,
"active_tier": self.active_tier,
"active_tickets": self.active_tickets,
"proposed_tracks": self.proposed_tracks

View File

@@ -2062,9 +2062,18 @@ class App:
if not tier3_keys:
imgui.text_disabled("No worker output yet.")
else:
worker_status = getattr(self, '_worker_status', {})
for key in tier3_keys:
ticket_id = key.split(": ", 1)[-1] if ": " in key else key
imgui.text(ticket_id)
status = worker_status.get(key, "unknown")
if status == "running":
imgui.text_colored(imgui.ImVec4(1, 1, 0, 1), f"{ticket_id} [{status}]")
elif status == "completed":
imgui.text_colored(imgui.ImVec4(0, 1, 0, 1), f"{ticket_id} [{status}]")
elif status == "failed":
imgui.text_colored(imgui.ImVec4(1, 0, 0, 1), f"{ticket_id} [{status}]")
else:
imgui.text(f"{ticket_id} [{status}]")
imgui.begin_child(f"##tier3_{ticket_id}_scroll", imgui.ImVec2(-1, 150), True)
imgui.text_wrapped(self.mma_streams[key])
try: