hopefully done refining

This commit is contained in:
2026-03-06 16:14:31 -05:00
parent 88e27ae414
commit 1294104f7f
20 changed files with 1736 additions and 734 deletions

View File

@@ -2,37 +2,26 @@
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Foundation & Research ## Phase 1: Verify Existing Infrastructure
Focus: Verify existing infrastructure and set up panel structure Focus: Confirm ai_client.get_gemini_cache_stats() works
- [ ] Task 1.1: Initialize MMA Environment - [ ] Task 1.1: Initialize MMA Environment
- Run `activate_skill mma-orchestrator` before starting - [ ] Task 1.2: Verify get_gemini_cache_stats()
- WHERE: `src/ai_client.py`
- [ ] Task 1.2: Verify ai_client.get_gemini_cache_stats() - WHAT: Confirm function exists and returns expected dict
- WHERE: `src/ai_client.py` lines ~200-230
- WHAT: Confirm function exists and returns expected dict structure
- HOW: Use `manual-slop_py_get_definition` on `get_gemini_cache_stats` - HOW: Use `manual-slop_py_get_definition` on `get_gemini_cache_stats`
- OUTPUT: Document exact return dict structure in task notes
- [ ] Task 1.3: Verify ai_client.cleanup()
- WHERE: `src/ai_client.py` line ~220
- WHAT: Confirm function clears `_gemini_cache`
- HOW: Use `manual-slop_py_get_definition` on `cleanup`
- SAFETY: Note that cleanup() also clears other resources - document side effects
## Phase 2: Panel Implementation ## Phase 2: Panel Implementation
Focus: Create the GUI panel structure Focus: Create cache panel in GUI
- [ ] Task 2.1: Add cache panel state variables - [ ] Task 2.1: Add cache panel state (if needed)
- WHERE: `src/gui_2.py` in `App.__init__` (around line 170) - WHERE: `src/gui_2.py` `App.__init__`
- WHAT: Add minimal state if needed (likely none - read directly from ai_client) - WHAT: Minimal state for display
- HOW: Follow existing state initialization pattern - HOW: Likely none needed - read directly from ai_client
- CODE STYLE: 1-space indentation
- SAFETY: No locks needed - read-only access to ai_client globals
- [ ] Task 2.2: Create _render_cache_panel() method - [ ] Task 2.2: Create _render_cache_panel() method
- WHERE: `src/gui_2.py` after other `_render_*_panel()` methods - WHERE: `src/gui_2.py` after other render methods
- WHAT: New method that displays cache statistics - WHAT: Display cache statistics
- HOW: - HOW:
```python ```python
def _render_cache_panel(self) -> None: def _render_cache_panel(self) -> None:
@@ -41,104 +30,50 @@ Focus: Create the GUI panel structure
if not imgui.collapsing_header("Cache Analytics"): if not imgui.collapsing_header("Cache Analytics"):
return return
stats = ai_client.get_gemini_cache_stats() stats = ai_client.get_gemini_cache_stats()
# Render stats... if not stats.get("cache_exists"):
imgui.text("No active cache")
return
imgui.text(f"Age: {self._format_age(stats.get('cache_age_seconds', 0))}")
imgui.text(f"TTL: {stats.get('ttl_remaining', 0):.0f}s remaining")
# Progress bar for TTL
ttl_pct = stats.get('ttl_remaining', 0) / stats.get('ttl_seconds', 3600)
imgui.progress_bar(ttl_pct)
``` ```
- CODE STYLE: 1-space indentation, NO COMMENTS
- [ ] Task 2.3: Integrate panel into main GUI - [ ] Task 2.3: Add helper for age formatting
- WHERE: `src/gui_2.py` in `_gui_func()` method - WHERE: `src/gui_2.py`
- WHAT: Call `_render_cache_panel()` in appropriate location
- HOW: Add near token budget panel or in settings area
- SAFETY: Ensure not called during modal dialogs
## Phase 3: Statistics Display
Focus: Implement the visual statistics rendering
- [ ] Task 3.1: Implement cache status display
- WHERE: `src/gui_2.py` in `_render_cache_panel()`
- WHAT: Show cache existence and age
- HOW: - HOW:
- `imgui.text(f"Cache Active: {stats['cache_exists']}")` ```python
- `imgui.text(f"Age: {format_age(stats['cache_age_seconds'])}")` def _format_age(self, seconds: float) -> str:
- HELPER: Create `format_age(seconds: float) -> str` helper if seconds < 60:
- CODE STYLE: 1-space indentation return f"{seconds:.0f}s"
elif seconds < 3600:
return f"{seconds/60:.0f}m {seconds%60:.0f}s"
else:
return f"{seconds/3600:.0f}h {(seconds%3600)/60:.0f}m"
```
- [ ] Task 3.2: Implement TTL countdown display ## Phase 3: Manual Controls
- WHERE: `src/gui_2.py` in `_render_cache_panel()` Focus: Add cache clear button
- WHAT: Show remaining TTL with percentage
- HOW:
- `remaining = stats['ttl_remaining']`
- `percentage = (remaining / stats['ttl_seconds']) * 100`
- Use `imgui.progress_bar()` for visual
- VISUAL: Warning color when percentage < 20% (use `vec4` colors defined at top of file)
- [ ] Task 3.3: Implement requests counter (optional enhancement) - [ ] Task 3.1: Add clear cache button
- WHERE: `src/gui_2.py` in `_render_cache_panel()` - WHERE: `src/gui_2.py` `_render_cache_panel()`
- WHAT: Show estimated "requests while cache active"
- HOW: Add `self._cache_request_count: int = 0` state, increment on send
- SAFETY: This requires hooking into send flow - may skip if complex
## Phase 4: Manual Controls
Focus: Implement the cache clear functionality
- [ ] Task 4.1: Add clear cache button
- WHERE: `src/gui_2.py` in `_render_cache_panel()`
- WHAT: Button that clears the Gemini cache
- HOW: - HOW:
```python ```python
if imgui.button("Clear Cache"): if imgui.button("Clear Cache"):
ai_client.cleanup() ai_client.cleanup()
# Optionally set a flag to show "Cache cleared" message self._cache_cleared = True
if getattr(self, '_cache_cleared', False):
imgui.text_colored(vec4(100, 255, 100, 255), "Cache cleared - will rebuild on next request")
``` ```
- SAFETY: `cleanup()` clears ALL caches, not just Gemini - document this
- [ ] Task 4.2: Add clear confirmation/feedback ## Phase 4: Integration
- WHERE: `src/gui_2.py` in `_render_cache_panel()` Focus: Add panel to main GUI
- WHAT: Show feedback after clear
- HOW: Add `self._cache_just_cleared: bool = False` flag, show message, auto-clear after 3s - [ ] Task 4.1: Integrate panel into layout
- CODE STYLE: 1-space indentation - WHERE: `src/gui_2.py` `_gui_func()`
- WHAT: Call `_render_cache_panel()` in settings or token budget area
## Phase 5: Testing ## Phase 5: Testing
Focus: Verify all functionality works correctly - [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification
- [ ] Task 5.1: Write unit tests for cache panel
- WHERE: `tests/test_cache_panel.py` (new file)
- WHAT: Test panel visibility, stats display, clear button
- HOW: Use `mock_app` or `app_instance` fixture from `conftest.py`
- PATTERN: Follow `test_gui_phase4.py` as reference
- CODE STYLE: 1-space indentation
- [ ] Task 5.2: Write integration test with live_gui
- WHERE: `tests/test_cache_panel.py`
- WHAT: Test with actual Gemini provider (or mock)
- HOW: Use `live_gui` fixture, set provider to 'gemini', verify panel shows
- ARTIFACTS: Write to `tests/artifacts/`
- [ ] Task 5.3: Conductor - Phase Verification
- Run targeted tests: `uv run pytest tests/test_cache_panel.py -v`
- Verify no lint errors in modified files
- Manual visual verification in GUI
## Implementation Notes
### Thread Safety Analysis
- `ai_client.get_gemini_cache_stats()` reads `_gemini_cache` and `_gemini_cache_created_at`
- These are set on the asyncio worker thread during `_send_gemini()`
- Reading from GUI thread is safe (atomic types) but values may be slightly stale
- No locks required for display purposes
### Code Style Checklist
- [ ] 1-space indentation throughout
- [ ] CRLF line endings on Windows
- [ ] No comments unless explicitly documenting complex logic
- [ ] Type hints on all new functions
- [ ] Follow existing `vec4` color naming pattern
### Files Modified
- `src/gui_2.py`: Add `_render_cache_panel()`, integrate into `_gui_func()`
- `tests/test_cache_panel.py`: New test file
### Dependencies
- Existing: `src/ai_client.py::get_gemini_cache_stats()`
- Existing: `src/ai_client.py::cleanup()`
- Existing: `imgui_bundle::imgui`

View File

@@ -1,29 +1,66 @@
# Implementation Plan: Kill/Abort Workers (kill_abort_workers_20260306) # Implementation Plan: Kill/Abort Running Workers (kill_abort_workers_20260306)
## Phase 1: Kill Mechanism > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Add thread termination
- WHERE: src/multi_agent_conductor.py
- WHAT: Kill specific worker thread
- HOW: threading.Event or similar
- SAFETY: Clean resource release
## Phase 2: UI Integration ## Phase 1: Thread Tracking
- [ ] Task: Add kill buttons Focus: Track active worker threads
- WHERE: src/gui_2.py
- WHAT: Button per worker
- HOW: In worker panel
- [ ] Task: Add confirmation dialog
- WHERE: src/gui_2.py
- WHAT: Confirm before kill
- HOW: imgui popup
## Phase 3: Status Updates - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Update worker status - [ ] Task 1.2: Add worker tracking dict to ConductorEngine
- WHERE: src/gui_2.py - WHERE: `src/multi_agent_conductor.py` `ConductorEngine.__init__`
- WHAT: Reflect killed state - WHAT: Dict to track active workers
- HOW: Status variable - HOW:
```python
self._active_workers: dict[str, threading.Thread] = {}
self._abort_events: dict[str, threading.Event] = {}
```
## Phase 4: Verification ## Phase 2: Abort Mechanism
- [ ] Task: Test kill functionality Focus: Add abort signal to workers
- [ ] Task: Conductor - Phase Verification
- [ ] Task 2.1: Create abort event per ticket
- WHERE: `src/multi_agent_conductor.py` before spawning worker
- WHAT: Create threading.Event for abort
- HOW: `self._abort_events[ticket.id] = threading.Event()`
- [ ] Task 2.2: Check abort in worker lifecycle
- WHERE: `src/multi_agent_conductor.py` `run_worker_lifecycle()`
- WHAT: Check abort event between operations
- HOW:
```python
abort_event = engine._abort_events.get(ticket.id)
if abort_event and abort_event.is_set():
ticket.status = "killed"
return
```
## Phase 3: Kill Button UI
Focus: Add kill button to GUI
- [ ] Task 3.1: Add kill button per worker
- WHERE: `src/gui_2.py` MMA dashboard
- WHAT: Button to kill specific worker
- HOW:
```python
for ticket_id, thread in engine._active_workers.items():
if thread.is_alive():
if imgui.button(f"Kill {ticket_id}"):
engine.kill_worker(ticket_id)
```
- [ ] Task 3.2: Implement kill_worker method
- WHERE: `src/multi_agent_conductor.py`
- WHAT: Set abort event and wait for termination
- HOW:
```python
def kill_worker(self, ticket_id: str) -> None:
if ticket_id in self._abort_events:
self._abort_events[ticket_id].set()
if ticket_id in self._active_workers:
self._active_workers[ticket_id].join(timeout=2.0)
del self._active_workers[ticket_id]
```
## Phase 4: Testing
- [ ] Task 4.1: Write unit tests
- [ ] Task 4.2: Conductor - Phase Verification

View File

@@ -1,32 +1,58 @@
# Implementation Plan: Manual Block/Unblock Control (manual_block_control_20260306) # Implementation Plan: Manual Block/Unblock Control (manual_block_control_20260306)
## Phase 1: Block Mechanism > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Add manual block field
- WHERE: src/models.py
- WHAT: Add manual_block_reason to Ticket
- HOW: Optional[str]
- [ ] Task: Add block/unblock methods
- WHERE: src/models.py
- WHAT: mark_blocked, mark_unblocked
- HOW: Set/unset flag
## Phase 2: UI Controls ## Phase 1: Add Manual Block Fields
- [ ] Task: Add block button Focus: Add manual_block flag to Ticket
- WHERE: src/gui_2.py
- WHAT: Block selected ticket
- HOW: Button with input
- [ ] Task: Add unblock button
- WHERE: src/gui_2.py
- WHAT: Remove block
- HOW: Button
## Phase 3: Visualization - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Show block status - [ ] Task 1.2: Add manual_block field to Ticket
- WHERE: src/gui_2.py - WHERE: `src/models.py` `Ticket` dataclass
- WHAT: Visual indicator for blocked - WHAT: Add `manual_block: bool = False`
- HOW: Different color/icon - HOW:
```python
manual_block: bool = False
```
## Phase 4: Verification - [ ] Task 1.3: Add mark_manual_block method
- [ ] Test block/unblock - WHERE: `src/models.py` `Ticket`
- [ ] Conductor - Phase Verification - WHAT: Method to set manual block with reason
- HOW:
```python
def mark_manual_block(self, reason: str) -> None:
self.status = "blocked"
self.blocked_reason = f"[MANUAL] {reason}"
self.manual_block = True
```
## Phase 2: Block/Unblock UI
Focus: Add block buttons to ticket display
- [ ] Task 2.1: Add block button
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Button to block with reason input
- HOW: Modal with text input for reason
- [ ] Task 2.2: Add unblock button
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Button to clear manual block
- HOW:
```python
if ticket.manual_block and ticket.status == "blocked":
if imgui.button("Unblock"):
ticket.status = "todo"
ticket.blocked_reason = None
ticket.manual_block = False
```
## Phase 3: Cascade Integration
Focus: Trigger cascade on block/unblock
- [ ] Task 3.1: Call cascade_blocks after manual block
- WHERE: `src/gui_2.py` or `src/multi_agent_conductor.py`
- WHAT: Update downstream tickets
- HOW: `self.dag.cascade_blocks()`
## Phase 4: Testing
- [ ] Task 4.1: Write unit tests
- [ ] Task 4.2: Conductor - Phase Verification

View File

@@ -1,202 +1,141 @@
# Implementation Plan: Manual Skeleton Context Injection (manual_skeleton_injection_20260306) # Implementation Plan: Manual Skeleton Context Injection (manual_skeleton_injection_20260306)
## Phase 1: File Selection UI > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Implement file picker
- WHERE: src/gui_2.py
- WHAT: Browse files for skeleton
- HOW: imgui.file_picker or custom
- SAFETY: Path validation
## Phase 2: Skeleton Preview ## Phase 1: UI Foundation
- [ ] Task: Generate preview Focus: Add file injection button and state
- WHERE: src/gui_2.py
- WHAT: Show skeleton before inject
- HOW: Call skeleton generation
- SAFETY: Handle large files
- [ ] Task: Implement inject button
- WHERE: src/gui_2.py
- WHAT: Inject into discussion
- HOW: Append to context
## Phase 3: Full Read Option - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Add full read toggle - Run `activate_skill mma-orchestrator` before starting
- WHERE: src/gui_2.py
- WHAT: Option for full file
- HOW: Checkbox/switch
## Phase 4: Verification - [ ] Task 1.2: Add injection state variables
- [ ] Task: Test injection flow - WHERE: `src/gui_2.py` `App.__init__`
- [ ] Task: Conductor - Phase Verification - WHAT: State for injection UI
## Phase 1: Skeleton Preview - HOW:
- [ ] Task: Implement inject button ```python
- WHERE: src/gui_2.py discussion panel self._inject_file_path: str = ""
- how: Call ASTParser.get_skeleton() for preview self._inject_mode: str = "skeleton" # "skeleton" | "full"
- Display preview self._inject_preview: str = ""
- on preview change, regenerate skeleton via `get_skeleton()` self._show_inject_modal: bool = False
```
- CODE STYLE: 1-space indentation
- Show "Skeleton" or "Full" toggle in preview - [ ] Task 1.3: Add inject button to discussion panel
- on "Inject", append to discussion input - WHERE: `src/gui_2.py` discussion panel
- [ ] Task: Add toggle logic - WHAT: Button to open injection modal
- where: src/gui_2.py - HOW:
- how: imgui.checkbox to toggle between skeleton/full file ```python
- On toggle change, regenerate skeleton if imgui.button("Inject File"):
- else: self._show_inject_modal = True
self._skeleton_mode = True ```
self._render_full_content = True
- code style: 1-space indentation
- [ ] Task: Conductor - Phase Verification
- Run targeted tests: `uv run pytest tests/test_manual_skeleton_injection.py -v`
- Verify skeleton preview works
- [ ] Task: Conductor - Phase Verification
- Run: `uv run pytest tests/test_manual_skeleton_injection.py -v`
- Verify skeleton preview works
- [ ] Task: Write unit tests for skeleton generation
- where: `tests/test_manual_skeleton_injection.py` (new file)
- what: Test extraction returns only specified functions
- how: Parse code, with regex, extract names matching `function_names` list
- return combined signatures + docstrings
- else:
return []
- Include `@core_logic` decorator, (if present)
- [ ] Task: Write integration test
- where: `tests/test_manual_skeleton_injection.py` (new file)
- what: Test targeted extraction returns only specified functions
- how: Use existing `AST.parse via `tree_sitter_python`
- Return extracted nodes
- Also add curated view (hot paths) and
- In `run_worker_lifecycle`,: check if ticket is in context_requirements and call `get_curated_view()` for full content (hot paths).
- [ ] Task: Write integration test
- where: `tests/test_context_pruning.py` (new file)
- what: Test integration of worker lifecycle with curated context
- how: Create test file with known functions, verify they're extracted
- [ ] Task: Write integration test
- where: `tests/test_context_pruning.py` (new file)
- what: Test integration of curated view
- how: Use `aggregate.build_tier3_context()` and
- - [ ] Task: Implement performance tests
- where: `tests/test_performance_monitor.py` (new file)
- what: Test Performance monitor history storage
- how: Add `_history: deque with maxlen=100
- in `end_frame()` store metrics
- [ ] Task: Implement graph rendering
- where: src/gui_2.py diagnostics panel
- how: Get CPU/RAM data from `performance_monitor.get_history()`
- Render graphs using imgui.plot_lines() or imgui.plot_histogram()
- [ ] Task: Conductor - Phase Verification
- Run: `uv run pytest tests/test_manual_skeleton_injection.py -v`
- Verify skeleton preview works
- [ ] Task: Write unit tests for performance dashboard
- where: `tests/test_performance_dashboard.py` (new file)
- what: Test performance dashboard
- how: Test history storage limits
- [x] Performance_monitor.add_history() if value is None: self._history = deque(maxlen=100)
self._history = data
imgui.plot_lines("CPU", data)
imgui.plot_histogram("Frame Time", data)
imgui.text("History: N points")
imgui.end()
imgui.text("Session Stats")
imgui.text(f"Total: ${self._session_cost_total:.2f}")
imgui.end_child()
# Token timeline ## Phase 2: File Selection
time.sleep(0.5) # Check for slow operations Focus: File picker and path validation
time.sleep(0.5)
for i, range(len(tickets): - [ ] Task 2.1: Create file selection modal
t = t. completed - WHERE: `src/gui_2.py`
t.status = "completed" - WHAT: Modal for selecting project file
- HOW:
```python
if self._show_inject_modal:
imgui.open_popup("Inject File")
if imgui.begin_popup_modal("Inject File"):
# File list from project files
for file_path in self.project.get("files", {}).get("paths", []):
if imgui.selectable(file_path, self._inject_file_path == file_path):
self._inject_file_path = file_path
self._update_inject_preview()
imgui.end_popup()
```
- [ ] Task 2.2: Validate selected path
- WHERE: `src/gui_2.py`
- WHAT: Ensure path is within project
- HOW: Check against `files.base_dir`
## Phase 3: Preview Generation
Focus: Generate and display skeleton/full preview
- [ ] Task 3.1: Implement preview update function
- WHERE: `src/gui_2.py`
- WHAT: Generate preview based on mode
- HOW:
```python
def _update_inject_preview(self) -> None:
if not self._inject_file_path:
self._inject_preview = ""
return
base_dir = self.project.get("files", {}).get("base_dir", ".")
full_path = Path(base_dir) / self._inject_file_path
try:
content = full_path.read_text(encoding="utf-8")
if self._inject_mode == "skeleton":
parser = ASTParser("python")
self._inject_preview = parser.get_skeleton(content)
else: else:
t.status = "in_progress" self._inject_preview = content
# Truncate to 500 lines
lines = self._inject_preview.split("\n")[:500]
self._inject_preview = "\n".join(lines)
if len(lines) >= 500:
self._inject_preview += "\n... (truncated)"
except Exception as e:
self._inject_preview = f"Error reading file: {e}"
```
# Session stats header - [ ] Task 3.2: Add mode toggle
if imgui.collapsing_header("Session Statistics"): - WHERE: `src/gui_2.py` inject modal
imgui.text_wrapped(f"Tokens: {sum(t['input'] + t['output']):,}") - WHAT: Radio buttons for skeleton/full
imgui.text(f"Cost projection: ${cost_tracker.estimate_cost(t['model'], t['input'], t['output']) * 1.0:.4f}") - HOW:
```python
# Cost projection if imgui.radio_button("Skeleton", self._inject_mode == "skeleton"):
burn_rate = tokens_per minute * sum(t['input'] / t['output'] * 60) self._inject_mode = "skeleton"
time.sleep =(session - now) self._update_inject_preview()
projected_remaining = time = now() - remaining_time
else:
imgui.text(f"Projected cost: ${projected_cost(t['model'], t['input'], t['output']) * 1.0:.4f}")
imgui.end_child()
# Efficiency Score
efficiency_score = tokens_per useful change ratio (if > 0 else 0)
efficiency_text = summary
imgui.text_wrapped(f"Efficiency Score: {efficiency_score:.2f}")
imgui.end_child()
# Session summary
if imgui.collapsing_header("Session Summary"):
imgui.text_wrapped("## Session")
- **Total**:** tokens
- **Completed:** status: {len(completed)} tickets
- **Blocked:** tickets marked as blocked with reason: {reason}
for t_status in self.track.tickets:
if t.blocked_reason:
imgui.text_wrapped(f" Blocked: {reason}")
imgui.text(f"Tickets blocked: {len(blocked)} tickets")
imgui.end()
# Controls
imgui.separator()
imgui.text("Controls")
# Per-ticket block controls
imgui.combo with options: block, execute, skip
block
else:
imgui.text("Unblocked")
imgui.indent_same_indent()
# Priority field
imgui.combo("priority", options: high/medium/low)
if imgui.begin_combo("Priority", item=0):
imgui.end_combo()
elif ticket.status == "completed":
imgui.text_wrapped(f" Completed")
elif ticket.status == "blocked":
imgui.text_wrapped(f" blocked: {reason}")
imgui.indent_same_indent()
imgui.end()
# Footer
imgui.text_wrapped("Session Stats")
# Tier Usage table (if imgui.begin_table("Tier Usage"))
{
imgui.table_next_row()
for tier in ["Tier 1", "Tier 2", "Tier 3", "Tier 4"]:
imgui.table_set_column_index(1)
imgui.text(f"Tier {tier}")
imgui.table_next_row()
for ticket in tickets:
imgui.text(f" {ticket.id}")
imgui.text(f" {ticket.status}")
imgui.text(f" {ticket.priority}")
imgui.text("")
imgui.end_table()
imgui.text_wrapped(f"Session total: ${self._session_cost_total:.2f}")
imgui.end_child()
t.end_table()
imgui.text_wrapped("## Ticket Queue Management")
imgui.text("Priority")
imgui.combo("priority", options: high/medium/low)
imgui.same_line() imgui.same_line()
imgui.text_wrapped(f" {priority}") if imgui.radio_button("Full File", self._inject_mode == "full"):
imgui.end() self._inject_mode = "full"
# Drag-drop reordering self._update_inject_preview()
imgui.combo("Reorder", options: top/bottom/after") ```
imgui.text("Top")
imgui.text("Bottom") - [ ] Task 3.3: Display preview
else - WHERE: `src/gui_2.py` inject modal
imgui.text("Bulk Actions") - WHAT: Scrollable preview area
imgui.text("Apply to: execute/skip/block") - HOW:
```python
imgui.begin_child("preview", height=300)
imgui.text_wrapped(self._inject_preview)
imgui.end_child() imgui.end_child()
```
## Phase 4: Inject Action
Focus: Append to discussion input
- [ ] Task 4.1: Implement inject button
- WHERE: `src/gui_2.py` inject modal
- WHAT: Button to inject content
- HOW:
```python
if imgui.button("Inject"):
formatted = f"\n## File: {self._inject_file_path}\n```python\n{self._inject_preview}\n```\n"
self.ui_input_text += formatted
self._show_inject_modal = False
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel"):
self._show_inject_modal = False
imgui.close_current_popup()
```
## Phase 5: Testing
Focus: Verify all functionality
- [ ] Task 5.1: Write unit tests
- WHERE: `tests/test_skeleton_injection.py` (new file)
- WHAT: Test preview generation, truncation
- HOW: Create test files, verify skeleton output
- [ ] Task 5.2: Conductor - Phase Verification
- Run: `uv run pytest tests/test_skeleton_injection.py -v`
- Manual: Verify inject modal works in GUI
# Footer # Footer
imgui.end_table() imgui.end_table()

View File

@@ -1,36 +1,113 @@
# Track Specification: Manual Skeleton Context Injection (manual_skeleton_injection_20260306) # Track Specification: Manual Skeleton Context Injection (manual_skeleton_injection_20260306)
## Overview ## Overview
Add UI controls to manually flag files for skeleton injection in discussions. Allow agent to request full file reads or specific def/class definitions on-demand. Add UI controls to manually inject file skeletons into discussions. Allow user to preview skeleton content before sending to AI, with option to toggle between skeleton and full file.
## Current State Audit ## Current State Audit
### Already Implemented (DO NOT re-implement) ### Already Implemented (DO NOT re-implement)
- **`file_cache.ASTParser.get_skeleton()`**: Returns Python skeleton
- **`mcp_client.py_get_skeleton()`**: MCP tool for skeleton generation
- **`aggregate.py`**: Builds file items context
### Gaps to Fill #### ASTParser (src/file_cache.py)
- No UI to flag files for skeleton vs full - **`ASTParser` class**: Uses tree-sitter for Python parsing
- No preview of skeleton before injection - **`get_skeleton(code: str) -> str`**: Returns file skeleton (signatures/docstrings preserved, function bodies replaced with `...`)
- No on-demand definition lookup - **`get_curated_view(code: str) -> str`**: Returns curated view preserving `@core_logic` and `# [HOT]` decorated function bodies
#### MCP Tools (src/mcp_client.py)
- **`py_get_skeleton(path, language)`**: Tool #15 - generates skeleton
- **`py_get_definition(path, name)`**: Tool #18 - gets specific definition
- **Both available to AI during discussion**
#### Context Building (src/aggregate.py)
- **`build_file_items()`**: Creates file items from project config
- **`build_tier*_context()`**: Tier-specific context builders already use skeleton logic
### Gaps to Fill (This Track's Scope)
- No UI for manual skeleton preview/injection
- No toggle between skeleton and full file
- No inject-to-discussion button
## Architectural Constraints
### Non-Blocking Preview
- Skeleton generation MUST NOT block UI
- Use existing `ASTParser.get_skeleton()` - already fast (<100ms)
### Preview Size Limit
- Truncate preview at 500 lines
- Show "... (truncated)" notice if exceeded
## Architecture Reference
### Key Integration Points
| File | Lines | Purpose |
|------|-------|---------|
| `src/gui_2.py` | ~1300-1400 | Discussion panel - add injection UI |
| `src/file_cache.py` | 30-80 | `ASTParser.get_skeleton()` |
| `src/aggregate.py` | 119-145 | `build_file_items()` |
### UI Integration Pattern
```python
# In discussion panel:
if imgui.button("Inject File"):
# Open file picker
self._inject_file_path = selected_path
self._inject_mode = "skeleton" # or "full"
# Preview in child window
preview = ASTParser("python").get_skeleton(content) if skeleton_mode else content
# Inject button appends to input text
```
## Functional Requirements ## Functional Requirements
- File picker UI in discussion panel
- Skeleton preview before injection
- Toggle: skeleton vs full file
- Uses existing `py_get_skeleton()` tool
## Key Integration Points ### FR1: File Selection
| File | Purpose | - Button "Inject File" in discussion panel
|-----|---------| - Opens file browser limited to project files
| `src/gui_2.py` | File picker, injection UI | - Path validation against project's `files.base_dir`
| `src/mcp_client.py` | `py_get_skeleton()` |
| `src/file_cache.py` | `ASTParser` | ### FR2: Mode Toggle
- Radio buttons: "Skeleton" / "Full File"
- Default: Skeleton
- Switching regenerates preview
### FR3: Preview Display
- Child window showing preview content
- Monospace font
- Scrollable, max 500 lines displayed
- Line numbers optional
### FR4: Inject Action
- Button "Inject to Discussion"
- Appends content to input text area
- Format: `## File: {path}\n\`\`\`python\n{content}\n\`\`\``
## Non-Functional Requirements
| Requirement | Constraint |
|-------------|------------|
| Preview Time | <100ms for typical file |
| Memory | Preview limited to 50KB |
## Testing Requirements
### Unit Tests
- Test skeleton generation for sample files
- Test truncation at 500 lines
### Integration Tests
- Inject file, verify appears in discussion
- Toggle modes, verify preview updates
## Out of Scope
- Definition lookup (separate track: on_demand_def_lookup)
- Multi-file injection
- Custom skeleton configuration
## Acceptance Criteria ## Acceptance Criteria
- [ ] File picker UI functional - [ ] "Inject File" button in discussion panel
- [ ] Skeleton preview displays - [ ] File browser limits to project files
- [ ] Manual refresh button works - [ ] Skeleton/Full toggle works
- [ ] Full read option available - [ ] Preview displays correctly
- [ ] 1-space indentation - [ ] Inject appends to input
- [ ] Large file truncation works
- [ ] 1-space indentation maintained

View File

@@ -1,31 +1,63 @@
# Implementation Plan: MMA Multi-Worker Visualization (mma_multiworker_viz_20260306) # Implementation Plan: MMA Multi-Worker Visualization (mma_multiworker_viz_20260306)
## Phase 1: Layout Design > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Design multi-pane layout
- WHERE: src/gui_2.py
- WHAT: Split view for workers
- HOW: imgui.columns or child windows
- SAFETY: Handle 0 workers
## Phase 2: Worker Tracking ## Phase 1: Stream Structure Enhancement
- [ ] Task: Track worker status Focus: Extend existing mma_streams for per-worker tracking
- WHERE: src/multi_agent_conductor.py
- WHAT: Per-worker status
- HOW: Dictionary of worker states
- SAFETY: Thread-safe updates
## Phase 3: Controls - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Add kill buttons - [ ] Task 1.2: Review existing mma_streams structure
- WHERE: src/gui_2.py - WHERE: `src/app_controller.py` line 142
- WHAT: Button per worker to kill - WHAT: Current is `Dict[str, str]` - stream_id -> accumulated text
- HOW: Signal worker thread - NOTE: Keep this structure, add per-worker metadata separately
- SAFETY: Graceful termination
- [ ] Task: Add restart buttons
- WHERE: src/gui_2.py
- WHAT: Respawn killed worker
- HOW: Re-submit ticket
## Phase 4: Verification ## Phase 2: Worker Status Tracking
- [ ] Task: Test multi-worker display Focus: Track worker status separately
- [ ] Task: Conductor - Phase Verification
- [ ] 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"
## 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()
```
## 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:]
```
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,27 +1,107 @@
# Implementation Plan: Native Orchestrator (native_orchestrator_20260306) # Implementation Plan: Native Orchestrator (native_orchestrator_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Plan File Operations ## Phase 1: Plan File Operations
- [ ] Task: Initialize MMA Environment Focus: Native plan.md read/write
- [ ] Task: Implement plan.md read/write
- WHERE: src/orchestrator_pm.py or new module
- WHAT: Parse and write plan.md
- HOW: toml/tomllib for parsing
- SAFETY: Preserve formatting
## Phase 2: Metadata Management - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Implement metadata.json operations - [ ] Task 1.2: Implement read_plan function
- WHERE: src/orchestrator_pm.py - WHERE: `src/orchestrator_pm.py` or new `src/native_orchestrator.py`
- WHAT: Read/write track metadata - WHAT: Parse plan.md content
- HOW: json load/dump - HOW:
- SAFETY: Atomic writes ```python
def read_plan(track_id: str, base_dir: str = ".") -> str:
plan_path = Path(base_dir) / "conductor" / "tracks" / track_id / "plan.md"
if not plan_path.exists():
return ""
return plan_path.read_text(encoding="utf-8")
```
## Phase 3: Tier Delegation - [ ] Task 1.3: Implement write_plan function
- [ ] Task: Implement in-process delegation - WHERE: Same as above
- WHERE: src/multi_agent_conductor.py - WHAT: Write plan.md content
- WHAT: Replace subprocess calls with direct function calls - HOW:
- HOW: Import and call tier functions directly ```python
- SAFETY: Proper error propagation def write_plan(track_id: str, content: str, base_dir: str = ".") -> None:
plan_path = Path(base_dir) / "conductor" / "tracks" / track_id / "plan.md"
plan_path.parent.mkdir(parents=True, exist_ok=True)
plan_path.write_text(content, encoding="utf-8")
```
## Phase 4: Verification - [ ] Task 1.4: Parse task checkboxes
- [ ] Task: Test plan operations - WHERE: Same as above
- [ ] Task: Conductor - Phase Verification - WHAT: Extract task status from plan
- HOW:
```python
def parse_plan_tasks(content: str) -> list[dict]:
tasks = []
for line in content.split("\n"):
if line.strip().startswith("- ["):
checked = "[x]" in line
tasks.append({"text": line, "completed": checked})
return tasks
```
## Phase 2: Metadata Operations
Focus: Native metadata.json management
- [ ] Task 2.1: Implement read_metadata
- WHERE: Same as above
- HOW:
```python
def read_metadata(track_id: str, base_dir: str = ".") -> dict:
meta_path = Path(base_dir) / "conductor" / "tracks" / track_id / "metadata.json"
if not meta_path.exists():
return {}
return json.loads(meta_path.read_text(encoding="utf-8"))
```
- [ ] Task 2.2: Implement write_metadata
- WHERE: Same as above
- HOW:
```python
def write_metadata(track_id: str, data: dict, base_dir: str = ".") -> None:
meta_path = Path(base_dir) / "conductor" / "tracks" / track_id / "metadata.json"
meta_path.parent.mkdir(parents=True, exist_ok=True)
meta_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
```
## Phase 3: In-Process Tier Delegation
Focus: Replace subprocess calls with direct function calls
- [ ] Task 3.1: Create NativeOrchestrator class
- WHERE: `src/native_orchestrator.py` (new file)
- WHAT: Class with tier methods
- HOW:
```python
class NativeOrchestrator:
def __init__(self, base_dir: str = "."):
self.base_dir = Path(base_dir)
def generate_tickets(self, brief: str) -> list[Ticket]:
return conductor_tech_lead.generate_tickets(brief, ...)
def execute_ticket(self, ticket: Ticket, context: str) -> str:
return ai_client.send(context, ticket.description, ...)
def analyze_error(self, error: str) -> str:
return ai_client.run_tier4_analysis(error)
```
- [ ] Task 3.2: Integrate with ConductorEngine
- WHERE: `src/multi_agent_conductor.py`
- WHAT: Use NativeOrchestrator instead of subprocess
- HOW: Import and call methods directly
## Phase 4: CLI Fallback
Focus: Maintain mma_exec.py compatibility
- [ ] Task 4.1: Update mma_exec.py to use NativeOrchestrator
- WHERE: `scripts/mma_exec.py`
- WHAT: Thin wrapper around native module
- HOW: Import NativeOrchestrator and call methods
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,30 +1,67 @@
# Implementation Plan: On-Demand Definition Lookup (on_demand_def_lookup_20260306) # Implementation Plan: On-Demand Definition Lookup (on_demand_def_lookup_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Symbol Parsing ## Phase 1: Symbol Parsing
- [ ] Task: Initialize MMA Environment Focus: Parse @symbol syntax from user input
- [ ] Task: Implement @syntax parsing
- WHERE: src/gui_2.py - [ ] Task 1.1: Initialize MMA Environment
- WHAT: Detect @symbol in input - [ ] Task 1.2: Implement @symbol regex parser
- HOW: Regex or string match - WHERE: `src/gui_2.py` in `_send_callback()`
- SAFETY: Handle edge cases - WHAT: Extract @SymbolName patterns
- HOW:
```python
import re
def parse_symbols(text: str) -> list[str]:
return re.findall(r'@(\w+(?:\.\w+)*)', text)
```
## Phase 2: Definition Retrieval ## Phase 2: Definition Retrieval
- [ ] Task: Integrate py_get_definition Focus: Use existing MCP tool to get definitions
- WHERE: src/gui_2.py
- WHAT: Get definition from outline_tool - [ ] Task 2.1: Integrate py_get_definition
- HOW: Call existing function - WHERE: `src/gui_2.py`
- SAFETY: Handle not found - WHAT: Call MCP tool for each symbol
- HOW:
```python
from src import mcp_client
def get_symbol_definition(symbol: str, files: list[str]) -> tuple[str, str] | None:
for file_path in files:
result = mcp_client.py_get_definition(file_path, symbol)
if result and "not found" not in result.lower():
return (file_path, result)
return None
```
## Phase 3: Inline Display ## Phase 3: Inline Display
- [ ] Task: Render inline Focus: Display definition in discussion
- WHERE: src/gui_2.py
- WHAT: Show definition in discussion
- HOW: imgui.text with formatting
- [ ] Task: Implement navigation
- WHERE: src/gui_2.py
- WHAT: Click to jump to source
- HOW: Store file/line refs
## Phase 4: Verification - [ ] Task 3.1: Inject definition as context
- [ ] Task: Test lookup flow - WHERE: `src/gui_2.py` `_send_callback()`
- [ ] Task: Conductor - Phase Verification - WHAT: Append definition to message
- HOW:
```python
symbols = parse_symbols(user_message)
for symbol in symbols:
result = get_symbol_definition(symbol, self.project_files)
if result:
file_path, definition = result
user_message += f"\n\n[Definition: {symbol} from {file_path}]\n```python\n{definition}\n```"
```
## Phase 4: Click Navigation
Focus: Allow clicking definition to open file
- [ ] Task 4.1: Store file/line metadata with definition
- WHERE: Discussion entry structure
- WHAT: Track source location
- HOW: Add to discussion entry dict
- [ ] Task 4.2: Add click handler
- WHERE: `src/gui_2.py` discussion rendering
- WHAT: On click, scroll to definition
- HOW: Use selectable text with callback
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests for parsing
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,32 +1,82 @@
# Implementation Plan: Per-Ticket Model Override (per_ticket_model_20260306) # Implementation Plan: Per-Ticket Model Override (per_ticket_model_20260306)
## Phase 1: Model Field > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Add override field
- WHERE: src/models.py
- WHAT: model_override on Ticket
- HOW: Optional[str]
- [ ] Task: Update ticket creation
- WHERE: src/conductor_tech_lead.py
- WHAT: Pass override to ticket
- HOW: Include in ticket dict
## Phase 2: UI Controls ## Phase 1: Model Override Field
- [ ] Task: Add model dropdown Focus: Add field to Ticket dataclass
- WHERE: src/gui_2.py
- WHAT: Select model per ticket
- HOW: imgui.combo with model list
- [ ] Task: Add override indicator
- WHERE: src/gui_2.py
- WHAT: Show override is active
- HOW: Different style
## Phase 3: Execution Integration - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Use override at runtime - [ ] Task 1.2: Add model_override to Ticket
- WHERE: src/multi_agent_conductor.py - WHERE: `src/models.py` `Ticket` dataclass
- WHAT: Add optional model override field
- HOW:
```python
@dataclass
class Ticket:
# ... existing fields ...
model_override: Optional[str] = None
```
- [ ] Task 1.3: Update serialization
- WHERE: `src/models.py` `Ticket.to_dict()` and `from_dict()`
- WHAT: Include model_override
- HOW: Add field to dict conversion
## Phase 2: Model Dropdown UI
Focus: Add model selection to ticket display
- [ ] Task 2.1: Get available models list
- WHERE: `src/gui_2.py` or from cost_tracker
- WHAT: List of available models
- HOW:
```python
AVAILABLE_MODELS = ["gemini-2.5-flash-lite", "gemini-2.5-flash", "gemini-3.1-pro-preview", "claude-3-5-sonnet", "deepseek-v3"]
```
- [ ] Task 2.2: Add dropdown to ticket UI
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Combo for model selection
- HOW:
```python
current_model = ticket.model_override or "Default"
if imgui.begin_combo("Model", current_model):
if imgui.selectable("Default", ticket.model_override is None):
ticket.model_override = None
for model in AVAILABLE_MODELS:
if imgui.selectable(model, ticket.model_override == model):
ticket.model_override = model
imgui.end_combo()
```
## Phase 3: Visual Indicator
Focus: Show when override is active
- [ ] Task 3.1: Color-code override tickets
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Visual distinction for override
- HOW:
```python
if ticket.model_override:
imgui.text_colored(vec4(255, 200, 100, 255), f"[{ticket.model_override}]")
```
## Phase 4: Execution Integration
Focus: Use override in worker execution
- [ ] Task 4.1: Check override in ConductorEngine.run()
- WHERE: `src/multi_agent_conductor.py` `run()`
- WHAT: Use ticket.model_override if set - WHAT: Use ticket.model_override if set
- HOW: Check and apply - HOW:
```python
if ticket.model_override:
model_name = ticket.model_override
else:
# Use existing escalation logic
models = ["gemini-2.5-flash-lite", "gemini-2.5-flash", "gemini-3.1-pro-preview"]
model_idx = min(ticket.retry_count, len(models) - 1)
model_name = models[model_idx]
```
## Phase 4: Verification ## Phase 5: Testing
- [ ] Test override works - [ ] Task 5.1: Write unit tests
- [ ] Conductor - Phase Verification - [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,26 +1,87 @@
# Implementation Plan: Performance Dashboard (performance_dashboard_20260306) # Implementation Plan: Performance Dashboard (performance_dashboard_20260306)
## Phase 1: Metrics Collection > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Verify performance_monitor
- WHERE: src/performance_monitor.py
- WHAT: Check existing metrics
- HOW: Review get_metrics() output
## Phase 2: Historical Data ## Phase 1: Historical Data Storage
- [ ] Task: Implement metrics history Focus: Add history buffer to PerformanceMonitor
- WHERE: src/performance_monitor.py
- [ ] Task 1.1: Initialize MMA Environment
- [ ] Task 1.2: Add history deque to PerformanceMonitor
- WHERE: `src/performance_monitor.py` `PerformanceMonitor.__init__`
- WHAT: Rolling window of metrics - WHAT: Rolling window of metrics
- HOW: deque with maxlen - HOW:
- SAFETY: Memory bounded ```python
from collections import deque
self._history: deque = deque(maxlen=100)
```
## Phase 3: Visualization - [ ] Task 1.3: Store metrics each frame
- [ ] Task: Render graphs - WHERE: `src/performance_monitor.py` `end_frame()`
- WHERE: src/gui_2.py - WHAT: Append current metrics to history
- WHAT: Line graphs for CPU/RAM/frame time - HOW:
- HOW: imgui.plot_lines or custom ```python
- SAFETY: 60fps during rendering def end_frame(self) -> None:
# ... existing code ...
self._history.append({
"fps": self._fps, "frame_time_ms": self._frame_time_ms,
"cpu_percent": self._cpu_percent, "input_lag_ms": self._input_lag_ms
})
```
## Phase 4: Verification - [ ] Task 1.4: Add get_history method
- [ ] Task: Test graph rendering - WHERE: `src/performance_monitor.py`
- [ ] Task: Conductor - Phase Verification - HOW:
```python
def get_history(self) -> list[dict]:
return list(self._history)
```
## Phase 2: CPU Graph
Focus: Render CPU usage over time
- [ ] Task 2.1: Extract CPU values from history
- WHERE: `src/gui_2.py` diagnostics panel
- WHAT: Get CPU% array for plotting
- HOW:
```python
history = self.perf_monitor.get_history()
cpu_values = [h["cpu_percent"] for h in history]
```
- [ ] Task 2.2: Render line graph
- WHERE: `src/gui_2.py`
- WHAT: imgui.plot_lines for CPU
- HOW:
```python
if imgui.collapsing_header("CPU Usage"):
imgui.plot_lines("##cpu", cpu_values, scale_min=0, scale_max=100)
imgui.text(f"Current: {cpu_values[-1]:.1f}%" if cpu_values else "N/A")
```
## Phase 3: Frame Time Histogram
Focus: Show frame time distribution
- [ ] Task 3.1: Bucket frame times
- WHERE: `src/gui_2.py`
- WHAT: Categorize into 0-16ms, 16-33ms, 33+ms
- HOW:
```python
buckets = [0, 0, 0] # <16ms, 16-33ms, 33+ms
for h in history:
ft = h["frame_time_ms"]
if ft < 16: buckets[0] += 1
elif ft < 33: buckets[1] += 1
else: buckets[2] += 1
```
- [ ] Task 3.2: Render histogram
- WHERE: `src/gui_2.py`
- HOW:
```python
imgui.plot_histogram("##frametime", buckets)
imgui.text("<16ms: {} 16-33ms: {} >33ms: {}".format(*buckets))
```
## Phase 4: Testing
- [ ] Task 4.1: Write unit tests
- [ ] Task 4.2: Conductor - Phase Verification

View File

@@ -1,32 +1,68 @@
# Implementation Plan: Pipeline Pause/Resume (pipeline_pause_resume_20260306) # Implementation Plan: Pipeline Pause/Resume (pipeline_pause_resume_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Pause Mechanism ## Phase 1: Pause Mechanism
- [ ] Task: Initialize MMA Environment Focus: Add pause event to ConductorEngine
- [ ] Task: Add pause state
- WHERE: src/multi_agent_conductor.py
- WHAT: Global pause flag
- HOW: threading.Event
- [ ] Task: Implement pause
- WHERE: src/multi_agent_conductor.py
- WHAT: Stop worker spawning
- HOW: Check pause flag
## Phase 2: Resume Mechanism - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Implement resume - [ ] Task 1.2: Add pause event to ConductorEngine
- WHERE: src/multi_agent_conductor.py - WHERE: `src/multi_agent_conductor.py` `ConductorEngine.__init__`
- WHAT: Continue from pause - WHAT: Threading event for pause control
- HOW: Clear flag, restart workers - HOW:
```python
self._pause_event: threading.Event = threading.Event()
```
## Phase 3: UI - [ ] Task 1.3: Check pause in run loop
- [ ] Task: Add pause button - WHERE: `src/multi_agent_conductor.py` `run()`
- WHERE: src/gui_2.py - WHAT: Wait while paused
- WHAT: Toggle pause state - HOW:
- HOW: imgui.button ```python
- [ ] Task: Add visual indicator while True:
- WHERE: src/gui_2.py if self._pause_event.is_set():
- WHAT: Show paused status time.sleep(0.5)
- HOW: Banner or icon continue
# Normal processing...
```
## Phase 4: Verification ## Phase 2: Pause/Resume Methods
- [ ] Test pause/resume Focus: Add control methods
- [ ] Conductor - Phase Verification
- [ ] Task 2.1: Add pause method
- WHERE: `src/multi_agent_conductor.py`
- HOW: `self._pause_event.set()`
- [ ] Task 2.2: Add resume method
- WHERE: `src/multi_agent_conductor.py`
- HOW: `self._pause_event.clear()`
## Phase 3: UI Controls
Focus: Add pause/resume buttons
- [ ] Task 3.1: Add pause/resume button
- WHERE: `src/gui_2.py` MMA dashboard
- WHAT: Toggle button for pause state
- HOW:
```python
is_paused = engine._pause_event.is_set()
label = "Resume" if is_paused else "Pause"
if imgui.button(label):
if is_paused:
engine.resume()
else:
engine.pause()
```
- [ ] Task 3.2: Add visual indicator
- WHERE: `src/gui_2.py`
- WHAT: Banner or color when paused
- HOW:
```python
if engine._pause_event.is_set():
imgui.text_colored(vec4(255, 200, 100, 255), "PIPELINE PAUSED")
```
## Phase 4: Testing
- [ ] Task 4.1: Write unit tests
- [ ] Task 4.2: Conductor - Phase Verification

View File

@@ -1,28 +1,94 @@
# Implementation Plan: Session Insights (session_insights_20260306) # Implementation Plan: Session Insights (session_insights_20260306)
## Phase 1: Session Data > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Review session_logger
- WHERE: src/session_logger.py
- WHAT: Check existing data
## Phase 2: Metrics Calculation ## Phase 1: Token Timeline Data
- [ ] Task: Implement token timeline Focus: Collect token usage over session
- WHERE: src/gui_2.py
- WHAT: Token usage over time
- HOW: Graph from history
- [ ] Task: Implement cost projection
- WHERE: src/gui_2.py
- WHAT: Estimate remaining budget
- HOW: Linear extrapolation
## Phase 3: UI - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Render insights panel - [ ] Task 1.2: Add token history state
- WHERE: src/gui_2.py - WHERE: `src/gui_2.py` or `src/app_controller.py`
- WHAT: Timeline, projection, summary - WHAT: Track tokens per API call
- HOW: imgui widgets - HOW:
- SAFETY: Handle zero session ```python
self._token_history: list[dict] = [] # [{"time": t, "input": n, "output": n, "model": s}, ...]
```
## Phase 4: Verification - [ ] Task 1.3: Record on each API response
- [ ] Task: Test insights - WHERE: `src/gui_2.py` in response handler
- [ ] Task: Conductor - Phase Verification - WHAT: Append to history
- HOW:
```python
# After API call
self._token_history.append({
"time": time.time(), "input": input_tokens, "output": output_tokens, "model": model
})
```
## Phase 2: Token Timeline Visualization
Focus: Render token usage graph
- [ ] Task 2.1: Extract cumulative tokens
- WHERE: `src/gui_2.py`
- WHAT: Calculate running totals
- HOW:
```python
cumulative_input = 0
cumulative_output = 0
input_values = []
output_values = []
for entry in self._token_history:
cumulative_input += entry["input"]
cumulative_output += entry["output"]
input_values.append(cumulative_input)
output_values.append(cumulative_output)
```
- [ ] Task 2.2: Render timeline
- WHERE: `src/gui_2.py` session insights panel
- HOW:
```python
if imgui.collapsing_header("Token Timeline"):
imgui.plot_lines("Input", input_values)
imgui.plot_lines("Output", output_values)
imgui.text(f"Total: {cumulative_input + cumulative_output:,} tokens")
```
## Phase 3: Cost Projection
Focus: Estimate remaining cost
- [ ] Task 3.1: Calculate burn rate
- WHERE: `src/gui_2.py`
- WHAT: Tokens per minute
- HOW:
```python
if len(self._token_history) >= 2:
elapsed = self._token_history[-1]["time"] - self._token_history[0]["time"]
total_tokens = sum(e["input"] + e["output"] for e in self._token_history)
burn_rate = total_tokens / (elapsed / 60) if elapsed > 0 else 0
```
- [ ] Task 3.2: Display projection
- WHERE: `src/gui_2.py`
- HOW:
```python
imgui.text(f"Burn rate: {burn_rate:.0f} tokens/min")
imgui.text(f"Session cost: ${session_cost:.4f}")
```
## Phase 4: Efficiency Score
Focus: Calculate tokens per useful change
- [ ] Task 4.1: Define efficiency metric
- WHERE: `src/gui_2.py`
- WHAT: Ratio of tokens to completed tickets
- HOW:
```python
completed_tickets = sum(1 for t in self.track.tickets if t.status == "completed")
total_tokens = sum(e["input"] + e["output"] for e in self._token_history)
efficiency = total_tokens / completed_tickets if completed_tickets > 0 else 0
```
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,33 +1,131 @@
# Implementation Plan: Manual Ticket Queue Management (ticket_queue_mgmt_20260306) # Implementation Plan: Manual Ticket Queue Management (ticket_queue_mgmt_20260306)
## Phase 1: UI Framework > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Add drag-drop support
- WHERE: src/gui_2.py
- WHAT: Enable ticket reordering via drag
- HOW: imgui drag-drop or custom handling
- SAFETY: Validate after drop
## Phase 2: Priority System ## Phase 1: Priority Field
- [ ] Task: Add priority field Focus: Add priority to Ticket model
- WHERE: src/models.py
- WHAT: Add priority to Ticket
- HOW: Enum (high/med/low)
- [ ] Task: Add priority UI
- WHERE: src/gui_2.py
- WHAT: Dropdown or buttons
- HOW: imgui.combo
## Phase 3: Bulk Operations - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Implement multi-select - Run `activate_skill mma-orchestrator` before starting
- WHERE: src/gui_2.py
- WHAT: Checkbox per ticket
- HOW: imgui.checkbox
- [ ] Task: Implement bulk actions
- WHERE: src/gui_2.py
- WHAT: Execute/skip/block buttons
- HOW: Apply to selected
## Phase 4: Verification - [ ] Task 1.2: Add priority field to Ticket
- [ ] Task: Test operations - WHERE: `src/models.py` `Ticket` dataclass
- [ ] Task: Conductor - Phase Verification - WHAT: Add `priority: str = "medium"` field
- HOW:
```python
@dataclass
class Ticket:
# ... existing fields ...
priority: str = "medium" # "high" | "medium" | "low"
```
- CODE STYLE: 1-space indentation
- [ ] Task 1.3: Update Ticket serialization
- WHERE: `src/models.py` `Ticket.to_dict()` and `from_dict()`
- WHAT: Include priority in serialization
- HOW: Add `priority` to dict conversion
## Phase 2: Priority UI
Focus: Add priority dropdown to ticket display
- [ ] Task 2.1: Add priority dropdown
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Dropdown for priority selection
- HOW:
```python
priorities = ["high", "medium", "low"]
current_idx = priorities.index(ticket.priority) if ticket.priority in priorities else 1
if imgui.begin_combo("Priority", priorities[current_idx]):
for i, p in enumerate(priorities):
if imgui.selectable(p, i == current_idx):
ticket.priority = p
imgui.end_combo()
```
- [ ] Task 2.2: Add color coding
- WHERE: `src/gui_2.py` ticket rendering
- WHAT: Color-code priority display
- HOW:
```python
priority_colors = {"high": vec4(255, 100, 100, 255), "medium": vec4(255, 200, 100, 255), "low": vec4(150, 150, 150, 255)}
imgui.text_colored(priority_colors.get(ticket.priority, vec4(200, 200, 200, 255)), f"[{ticket.priority.upper()}]")
```
## Phase 3: Multi-Select
Focus: Enable ticket selection for bulk operations
- [ ] Task 3.1: Add selection state
- WHERE: `src/gui_2.py` or `src/app_controller.py`
- WHAT: Track selected ticket IDs
- HOW:
```python
self._selected_tickets: set[str] = set()
```
- [ ] Task 3.2: Add checkbox per ticket
- WHERE: `src/gui_2.py` ticket list rendering
- WHAT: Checkbox for selection
- HOW:
```python
selected = ticket.id in self._selected_tickets
if imgui.checkbox(f"##select_{ticket.id}", selected):
if selected:
self._selected_tickets.discard(ticket.id)
else:
self._selected_tickets.add(ticket.id)
imgui.same_line()
```
- [ ] Task 3.3: Add select all/none buttons
- WHERE: `src/gui_2.py` ticket list header
- WHAT: Buttons to select/deselect all
- HOW:
```python
if imgui.button("Select All"):
self._selected_tickets = {t.id for t in self.track.tickets}
imgui.same_line()
if imgui.button("Select None"):
self._selected_tickets.clear()
```
## Phase 4: Bulk Actions
Focus: Execute bulk operations on selected tickets
- [ ] Task 4.1: Add bulk action buttons
- WHERE: `src/gui_2.py` ticket list area
- WHAT: Execute, Skip, Block buttons
- HOW:
```python
if imgui.button("Bulk Execute"):
for tid in self._selected_tickets:
self.engine.approve_task(tid)
imgui.same_line()
if imgui.button("Bulk Skip"):
for tid in self._selected_tickets:
self.engine.update_task_status(tid, "completed")
imgui.same_line()
if imgui.button("Bulk Block"):
for tid in self._selected_tickets:
self.engine.update_task_status(tid, "blocked")
```
## Phase 5: Drag-Drop (Optional)
Focus: Allow ticket reordering
- [ ] Task 5.1: Implement drag-drop reordering
- WHERE: `src/gui_2.py` ticket list
- WHAT: Drag tickets to reorder
- HOW: Use imgui drag-drop API
- SAFETY: Validate DAG after reorder (no dependency violations)
## Phase 6: Testing
Focus: Verify all functionality
- [ ] Task 6.1: Write unit tests
- WHERE: `tests/test_ticket_queue.py` (new file)
- WHAT: Test priority serialization, bulk operations
- HOW: Create mock tickets, verify state changes
- [ ] Task 6.2: Conductor - Phase Verification
- Run: `uv run pytest tests/test_ticket_queue.py -v`
- Manual: Verify UI controls work

View File

@@ -1,41 +1,112 @@
# Track Specification: Manual Ticket Queue Management (ticket_queue_mgmt_20260306) # Track Specification: Manual Ticket Queue Management (ticket_queue_mgmt_20260306)
## Overview ## Overview
Allow user to manually reorder, prioritize, or requeue tickets. Add drag-drop, priority tags, bulk selection. Allow user to manually reorder, prioritize, or requeue tickets in the DAG. Add drag-drop reordering, priority tags, and bulk selection for execute/skip/block operations.
## Current State Audit ## Current State Audit
### Already Implemented ### Already Implemented (DO NOT re-implement)
- **`models.Ticket`**: No priority field
- **`dag_engine.py`**: `get_ready_tasks()` returns in order
- **GUI**: Linear ticket list display
### Gaps to Fill #### Ticket Model (src/models.py)
- No priority field on Ticket - **`Ticket` dataclass**: Has `status`, `depends_on`, but no `priority` field
- No drag-drop reordering - **`mark_blocked(reason)`**: Sets status to blocked with reason
- No bulk selection/operations - **`mark_complete()`**: Sets status to completed
## Functional Requirements #### DAG Engine (src/dag_engine.py)
- Add `priority: str = "medium"` to Ticket (high/medium/low) - **`TrackDAG`**: Manages ticket dependency graph
- Drag-drop reordering in ticket list - **`get_ready_tasks()`**: Returns tasks with satisfied dependencies
- Multi-select for bulk operations - **`update_task_status()`**: Updates ticket status
- Bulk execute/skip/block - **`has_cycle()`**: Validates DAG
## Key Integration Points ### Gaps to Fill (This Track's Scope)
| File | Purpose | - No `priority` field on Ticket
|-----|---------| - No drag-drop reordering in GUI
| `src/models.py` | Add priority field | - No multi-select for bulk operations
| `src/gui_2.py` | Drag-drop, bulk UI | - No bulk execute/skip/block actions
| `src/dag_engine.py` | Priority-aware ordering |
## Architectural Constraints ## Architectural Constraints
- DAG validity maintained after reorder
- Dependency order cannot be violated ### DAG Validity
- Reordering MUST NOT violate dependencies
- Cannot move ticket before its dependencies
- `depends_on` relationships preserved
### Atomic Operations
- Bulk operations apply to all selected tickets atomically
- Partial failure rolls back all changes
## Architecture Reference
### Key Integration Points
| File | Lines | Purpose |
|------|-------|---------|
| `src/models.py` | 30-50 | `Ticket` - add priority field |
| `src/gui_2.py` | 2650-2750 | Ticket display - add drag-drop |
| `src/dag_engine.py` | 50-80 | Status updates |
### Proposed Ticket Enhancement
```python
@dataclass
class Ticket:
# ... existing fields ...
priority: str = "medium" # "high" | "medium" | "low"
```
## Functional Requirements
### FR1: Priority Field
- Add `priority: str = "medium"` to Ticket dataclass
- Values: "high", "medium", "low"
- Persist in track state
### FR2: Priority UI
- Dropdown or button group per ticket
- Color-coded: high=red, medium=yellow, low=gray
- Save to state on change
### FR3: Drag-Drop Reordering
- Drag ticket to reorder in list
- Drop validates DAG (no dependency violation)
- Show error if invalid position
### FR4: Multi-Select
- Checkbox per ticket for selection
- Select all / deselect all buttons
- Track selected ticket IDs
### FR5: Bulk Actions
- Execute: Mark all selected as ready
- Skip: Mark all selected as completed
- Block: Mark all selected as blocked
## Non-Functional Requirements
| Requirement | Constraint |
|-------------|------------|
| Response Time | <100ms for drag-drop validation |
| Persistence | Priority saved to state.toml |
## Testing Requirements
### Unit Tests
- Test priority field serialization
- Test DAG validation on reorder
### Integration Tests
- Drag-drop tickets, verify order changes
- Bulk block tickets, verify all blocked
## Out of Scope
- Automatic priority assignment
- Priority-based auto-scheduling
- Cross-track ticket movement
## Acceptance Criteria ## Acceptance Criteria
- [ ] Drag-drop reordering works - [ ] Priority field added to Ticket
- [ ] Priority tags display and save - [ ] Priority dropdown works in UI
- [ ] Multi-select functional - [ ] Drag-drop reordering functional
- [ ] Bulk actions apply correctly - [ ] DAG validity enforced on drop
- [ ] DAG validity maintained - [ ] Multi-select with checkboxes
- [ ] 1-space indentation - [ ] Bulk execute/skip/block works
- [ ] 1-space indentation maintained

View File

@@ -1,25 +1,123 @@
# Implementation Plan: Tier 4 Auto-Patching (tier4_auto_patching_20260306) # Implementation Plan: Tier 4 Auto-Patching (tier4_auto_patching_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Patch Generation ## Phase 1: Patch Generation
- [ ] Task: Initialize MMA Environment Focus: Generate unified diff on test failure
- [ ] Task: Extend Tier 4 to generate patches
- WHERE: src/multi_agent_conductor.py
- WHAT: Add patch generation on test failure
- HOW: Use difflib to generate unified diff
- SAFETY: Only generate, don't apply
## Phase 2: Diff Viewer - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Implement GUI diff viewer - [ ] Task 1.2: Extend Tier 4 prompt for patch generation
- WHERE: src/gui_2.py - WHERE: `src/mma_prompts.py` or inline in `ai_client.py`
- WHAT: Side-by-side diff display - WHAT: Prompt to generate unified diff
- HOW: Custom ImGui rendering or third-party - HOW:
- SAFETY: Read-only preview ```python
- [ ] Task: Implement apply button TIER4_PATCH_PROMPT = """
- WHERE: src/gui_2.py Analyze the error and generate a unified diff patch to fix it.
- WHAT: Apply patch to working directory Output format:
- HOW: subprocess.run(['patch', '-p1']) --- a/path/to/file.py
- SAFETY: Backup before apply +++ b/path/to/file.py
@@ -line,count +line,count @@
context
-removed line
+added line
context
"""
```
## Phase 3: Tests & Verification - [ ] Task 1.3: Add patch generation function
- [ ] Task: Write patch tests - WHERE: `src/ai_client.py`
- [ ] Task: Conductor - Phase Verification - WHAT: Generate patch from error
- HOW:
```python
def run_tier4_patch_generation(error: str, file_context: str) -> str:
prompt = TIER4_PATCH_PROMPT + f"\n\nError:\n{error}\n\nFiles:\n{file_context}"
return send(prompt, model="gemini-2.5-flash-lite")
```
## Phase 2: Diff Viewer UI
Focus: Display side-by-side diff
- [ ] Task 2.1: Parse unified diff
- WHERE: `src/gui_2.py` or new `src/diff_viewer.py`
- WHAT: Parse diff into hunks
- HOW:
```python
def parse_diff(diff_text: str) -> list[dict]:
hunks = []
current_hunk = None
for line in diff_text.split("\n"):
if line.startswith("@@"):
if current_hunk: hunks.append(current_hunk)
current_hunk = {"header": line, "lines": []}
elif current_hunk:
current_hunk["lines"].append(line)
if current_hunk: hunks.append(current_hunk)
return hunks
```
- [ ] Task 2.2: Render diff viewer
- WHERE: `src/gui_2.py`
- WHAT: Color-coded diff display
- HOW:
```python
for hunk in hunks:
for line in hunk["lines"]:
if line.startswith("+"):
imgui.text_colored(vec4(100, 255, 100, 255), line)
elif line.startswith("-"):
imgui.text_colored(vec4(255, 100, 100, 255), line)
else:
imgui.text(line)
```
## Phase 3: Patch Application
Focus: Apply patch with backup
- [ ] Task 3.1: Create backup before apply
- WHERE: `src/gui_2.py` or `src/mcp_client.py`
- WHAT: Backup file to .backup
- HOW:
```python
import shutil
backup_path = file_path.with_suffix(file_path.suffix + ".backup")
shutil.copy(file_path, backup_path)
```
- [ ] Task 3.2: Apply patch
- WHERE: `src/gui_2.py`
- WHAT: Use patch command or difflib
- HOW:
```python
import subprocess
result = subprocess.run(["patch", "-p1"], input=diff_text, capture_output=True, text=True)
```
- [ ] Task 3.3: Restore on failure
- WHERE: `src/gui_2.py`
- WHAT: Restore from backup if patch fails
- HOW: `shutil.copy(backup_path, file_path)`
## Phase 4: Modal UI
Focus: Approval modal for patches
- [ ] Task 4.1: Create patch approval modal
- WHERE: `src/gui_2.py`
- WHAT: Modal with diff preview and Apply/Reject buttons
- HOW:
```python
if self._show_patch_modal:
imgui.open_popup("Apply Patch?")
if imgui.begin_popup_modal("Apply Patch?"):
# Render diff
if imgui.button("Apply"):
self._apply_current_patch()
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Reject"):
imgui.close_current_popup()
imgui.end_popup()
```
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification

View File

@@ -1,25 +1,107 @@
# Implementation Plan: Tool Usage Analytics (tool_usage_analytics_20260306) # Implementation Plan: Tool Usage Analytics (tool_usage_analytics_20260306)
## Phase 1: Data Collection > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
- [ ] Task: Initialize MMA Environment
- [ ] Task: Verify tool_log_callback
- WHERE: src/ai_client.py
- WHAT: Check existing logging
## Phase 2: Aggregation ## Phase 1: Data Collection
- [ ] Task: Implement usage aggregation Focus: Add tool execution tracking
- WHERE: src/gui_2.py or new module
- WHAT: Count tools, avg times, failures - [ ] Task 1.1: Initialize MMA Environment
- HOW: Process tool_log entries - Run `activate_skill mma-orchestrator` before starting
- SAFETY: Efficient data structures
- [ ] Task 1.2: Add tool stats state
- WHERE: `src/app_controller.py` or `src/gui_2.py`
- WHAT: Add `_tool_stats: dict[str, dict]` state
- HOW:
```python
self._tool_stats: dict[str, dict] = {}
# Structure: {tool_name: {"count": 0, "total_time_ms": 0, "failures": 0}}
```
- CODE STYLE: 1-space indentation
- [ ] Task 1.3: Hook into tool execution
- WHERE: `src/ai_client.py` in tool execution path
- WHAT: Track tool name, time, success/failure
- HOW:
```python
start_time = time.time()
try:
result = mcp_client.dispatch(name, args)
success = True
except Exception:
success = False
finally:
elapsed_ms = (time.time() - start_time) * 1000
# Update stats via callback or direct update
```
- SAFETY: Don't impact tool execution performance
## Phase 2: Aggregation Logic
Focus: Calculate derived metrics
- [ ] Task 2.1: Implement stats update function
- WHERE: `src/app_controller.py`
- WHAT: Function to update tool stats
- HOW:
```python
def _update_tool_stats(self, tool_name: str, elapsed_ms: float, success: bool) -> None:
if tool_name not in self._tool_stats:
self._tool_stats[tool_name] = {"count": 0, "total_time_ms": 0.0, "failures": 0}
self._tool_stats[tool_name]["count"] += 1
self._tool_stats[tool_name]["total_time_ms"] += elapsed_ms
if not success:
self._tool_stats[tool_name]["failures"] += 1
```
- [ ] Task 2.2: Calculate average time and failure rate
- WHERE: `src/gui_2.py` in render function
- WHAT: Derive avg_time and failure_rate from stats
- HOW:
```python
for tool, stats in self._tool_stats.items():
count = stats["count"]
avg_time = stats["total_time_ms"] / count if count > 0 else 0
failure_rate = (stats["failures"] / count * 100) if count > 0 else 0
```
## Phase 3: Visualization ## Phase 3: Visualization
- [ ] Task: Render analytics Focus: Display analytics in GUI
- WHERE: src/gui_2.py
- WHAT: Charts and tables
- HOW: imgui tables, plot_lines
- SAFETY: Handle empty data
## Phase 4: Verification - [ ] Task 3.1: Add analytics panel
- [ ] Task: Test analytics - WHERE: `src/gui_2.py` in MMA Dashboard or Operations
- [ ] Task: Conductor - Phase Verification - WHAT: Table showing tool stats
- HOW:
```python
if imgui.collapsing_header("Tool Usage Analytics"):
if imgui.begin_table("tool_stats", 4):
imgui.table_setup_column("Tool")
imgui.table_setup_column("Count")
imgui.table_setup_column("Avg Time (ms)")
imgui.table_setup_column("Failure %")
imgui.table_headers_row()
for tool, stats in sorted(self._tool_stats.items(), key=lambda x: -x[1]["count"]):
imgui.table_next_row()
imgui.table_set_column_index(0)
imgui.text(tool)
# ... other columns
imgui.end_table()
```
## Phase 4: Reset on Session Clear
Focus: Clear stats on new session
- [ ] Task 4.1: Clear stats on session reset
- WHERE: `src/gui_2.py` or `src/app_controller.py` reset handler
- WHAT: Clear `_tool_stats` dict
- HOW: `self._tool_stats.clear()`
## Phase 5: Testing
Focus: Verify all functionality
- [ ] Task 5.1: Write unit tests
- WHERE: `tests/test_tool_analytics.py` (new file)
- WHAT: Test stats accumulation, avg calculation
- HOW: Mock tool execution, verify stats update
- [ ] Task 5.2: Conductor - Phase Verification
- Run: `uv run pytest tests/test_tool_analytics.py -v`
- Manual: Verify analytics panel displays in GUI

View File

@@ -1,35 +1,99 @@
# Track Specification: Tool Usage Analytics (tool_usage_analytics_20260306) # Track Specification: Tool Usage Analytics (tool_usage_analytics_20260306)
## Overview ## Overview
Analytics panel showing most-used tools, average execution time, failure rates. Analytics panel showing most-used tools, average execution time, and failure rates. Uses existing tool execution data from ai_client.
## Current State Audit ## Current State Audit
### Already Implemented ### Already Implemented (DO NOT re-implement)
- **`ai_client.tool_log_callback`**: Called when tool executes
- **`mcp_client.dispatch()`**: Routes tool calls
- **No aggregation or storage**
### Gaps to Fill #### Tool Execution (src/ai_client.py)
- No tool usage tracking - **Tool dispatch in `_execute_tool_calls_concurrently()`**: Executes tools via `mcp_client.dispatch()`
- No execution time tracking - **`pre_tool_callback`**: Optional callback before tool execution
- **No built-in tracking or aggregation**
#### MCP Client (src/mcp_client.py)
- **`dispatch(name, args)`**: Routes tool calls to implementations
- **26 tools available** (run_powershell, read_file, py_get_skeleton, etc.)
- **`MUTATING_TOOLS`**: Set of tools that modify files
### Gaps to Fill (This Track's Scope)
- No tool usage tracking (count per tool)
- No execution time tracking per tool
- No failure rate tracking - No failure rate tracking
- No analytics display in GUI
## Architectural Constraints
### Efficient Aggregation
- Track tool stats in lightweight data structure
- Don't impact tool execution performance
- Use dict: `{tool_name: {count, total_time, failures}}`
### Memory Bounds
- Only track stats, not full history
- Reset on session reset
## Architecture Reference
### Key Integration Points
| File | Lines | Purpose |
|------|-------|---------|
| `src/ai_client.py` | ~500-550 | Tool execution - add tracking |
| `src/gui_2.py` | ~2700-2800 | Analytics panel |
### Proposed Tracking Structure
```python
# In AppController or App:
self._tool_stats: dict[str, dict] = {}
# Structure: {"read_file": {"count": 10, "total_time_ms": 150, "failures": 0}, ...}
```
## Functional Requirements ## Functional Requirements
- Track tool name, execution time, success/failure
- Aggregate by tool name
- Display ranking by usage count
- Show average time per tool
- Show failure percentage
## Key Integration Points ### FR1: Tool Usage Tracking
| File | Purpose | - Track tool name, execution time, success/failure
|-----|---------| - Store in `_tool_stats` dict
| `src/ai_client.py` | Hook into tool_log_callback | - Update on each tool execution
| `src/gui_2.py` | Analytics panel rendering |
### FR2: Aggregation by Tool
- Count total calls per tool
- Calculate average execution time
- Track failure count and rate
### FR3: Analytics Display
- Table showing tool name, count, avg time, failure rate
- Sort by usage count (most used first)
- Show in MMA Dashboard or Operations panel
## Non-Functional Requirements
| Requirement | Constraint |
|-------------|------------|
| Tracking Overhead | <1ms per tool call |
| Memory | <1KB for stats dict |
## Testing Requirements
### Unit Tests
- Test tracking updates correctly
- Test failure rate calculation
### Integration Tests
- Execute tools, verify stats accumulate
- Reset session, verify stats cleared
## Out of Scope
- Historical analytics across sessions
- Export to file
- Per-ticket tool breakdown
## Acceptance Criteria ## Acceptance Criteria
- [ ] Tool ranking displayed - [ ] Tool execution tracked
- [ ] Average times accurate - [ ] Count per tool accurate
- [ ] Failure rates tracked - [ ] Average time calculated
- [ ] 1-space indentation - [ ] Failure rate shown
- [ ] Display in GUI panel
- [ ] Reset on session clear
- [ ] 1-space indentation maintained

View File

@@ -1,32 +1,95 @@
# Implementation Plan: Track Progress Visualization (track_progress_viz_20260306) # Implementation Plan: Track Progress Visualization (track_progress_viz_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Progress Calculation ## Phase 1: Progress Calculation
- [ ] Task: Initialize MMA Environment Focus: Calculate progress metrics from ticket states
- [ ] Task: Implement progress calculation
- WHERE: src/gui_2.py or app_controller
- WHAT: Calculate % from ticket states
- HOW: Count completed vs total
## Phase 2: Visualization - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Render progress bar - Run `activate_skill mma-orchestrator` before starting
- WHERE: src/gui_2.py
- WHAT: Visual progress bar
- HOW: imgui.progress_bar
- [ ] Task: Render percentage text
- WHERE: src/gui_2.py
- WHAT: Numeric % display
- HOW: imgui.text
## Phase 3: Additional Features - [ ] Task 1.2: Implement progress calculation function
- [ ] Task: Implement ticket counts - WHERE: `src/gui_2.py` or helper in `src/project_manager.py`
- WHERE: src/gui_2.py - WHAT: Calculate completion percentage from tickets
- WHAT: Completed/remaining counts - HOW:
- HOW: Text display ```python
- [ ] Task: Implement ETA def calculate_track_progress(tickets: list[Ticket]) -> dict:
- WHERE: src/gui_2.py total = len(tickets)
- WHAT: Time estimate if total == 0:
- HOW: Average time per ticket return {"percentage": 0, "completed": 0, "total": 0, "in_progress": 0, "blocked": 0, "todo": 0}
completed = sum(1 for t in tickets if t.status == "completed")
in_progress = sum(1 for t in tickets if t.status == "in_progress")
blocked = sum(1 for t in tickets if t.status == "blocked")
todo = sum(1 for t in tickets if t.status == "todo")
percentage = (completed / total) * 100
return {"percentage": percentage, "completed": completed, "total": total,
"in_progress": in_progress, "blocked": blocked, "todo": todo}
```
## Phase 4: Verification ## Phase 2: Progress Bar Rendering
- [ ] Task: Test progress display Focus: Display visual progress bar
- [ ] Task: Conductor - Phase Verification
- [ ] Task 2.1: Add progress bar to MMA Dashboard
- WHERE: `src/gui_2.py` `_render_mma_dashboard()`
- WHAT: Visual progress bar with percentage
- HOW:
```python
progress = calculate_track_progress(self.track.tickets)
imgui.text(f"Progress: {progress['completed']}/{progress['total']} tickets")
imgui.progress_bar(progress['percentage'] / 100.0, size=(300, 20))
imgui.same_line()
imgui.text(f"{progress['percentage']:.1f}%")
```
- SAFETY: Handle empty ticket list
## Phase 3: Ticket Breakdown Display
Focus: Show status breakdown
- [ ] Task 3.1: Add status breakdown text
- WHERE: `src/gui_2.py` `_render_mma_dashboard()`
- WHAT: Show counts per status
- HOW:
```python
imgui.text(f"Completed: {progress['completed']}")
imgui.text(f"In Progress: {progress['in_progress']}")
imgui.text(f"Blocked: {progress['blocked']}")
imgui.text(f"Todo: {progress['todo']}")
```
## Phase 4: ETA Estimation
Focus: Estimate time remaining
- [ ] Task 4.1: Track ticket completion times
- WHERE: `src/gui_2.py` or `src/app_controller.py`
- WHAT: Track average time per completed ticket
- HOW:
```python
self._ticket_start_times: dict[str, float] = {}
self._avg_ticket_time: float = 0.0
self._completed_count: int = 0
# On ticket start: self._ticket_start_times[ticket.id] = time.time()
# On ticket complete: elapsed = time.time() - start; update average
```
- [ ] Task 4.2: Calculate and display ETA
- WHERE: `src/gui_2.py`
- WHAT: Show estimated time remaining
- HOW:
```python
remaining = progress['total'] - progress['completed']
eta_seconds = self._avg_ticket_time * remaining
eta_minutes = int(eta_seconds / 60)
imgui.text(f"ETA: ~{eta_minutes}m ({remaining} tickets remaining)")
```
## Phase 5: Testing
Focus: Verify all functionality
- [ ] Task 5.1: Write unit tests for progress calculation
- WHERE: `tests/test_progress_viz.py` (new file)
- WHAT: Test percentage calculation, edge cases
- HOW: Create mock tickets with various statuses
- [ ] Task 5.2: Conductor - Phase Verification
- Run: `uv run pytest tests/test_progress_viz.py -v`
- Manual: Verify progress bar displays correctly

View File

@@ -1,34 +1,111 @@
# Track Specification: Track Progress Visualization (track_progress_viz_20260306) # Track Specification: Track Progress Visualization (track_progress_viz_20260306)
## Overview ## Overview
Progress bars and percentage completion for active tracks and tickets. Progress bars and percentage completion for active tracks and tickets. Better visualization of DAG execution state.
## Current State Audit ## Current State Audit
### Already Implemented ### Already Implemented (DO NOT re-implement)
- **`models.Track`**: Has tickets list
- **`project_manager.get_all_tracks()`**: Returns track progress
- **GUI**: Shows ticket status but no progress bar
### Gaps to Fill #### Track Model (src/models.py)
- No visual progress bar - **`Track` dataclass**: Has `tickets: list[Ticket]` field
- **`Ticket.status`**: "todo" | "in_progress" | "completed" | "blocked"
#### Track Listing (src/project_manager.py)
- **`get_all_tracks()`**: Returns list of track metadata with progress
- **Progress calculation exists**: Counts completed vs total tickets
#### DAG Engine (src/dag_engine.py)
- **`TrackDAG`**: Manages ticket dependency graph
- **Status tracking via `update_task_status()`**
### Gaps to Fill (This Track's Scope)
- No visual progress bar in GUI
- No percentage completion display - No percentage completion display
- No ETA estimation - No ETA estimation
- No ticket breakdown display
## Architectural Constraints
### Accurate State
- Progress MUST reflect actual ticket status
- Count completed, in_progress, blocked, todo separately
### Efficient Updates
- Status changes trigger immediate UI update
- No polling - event-driven via MMA state updates
## Architecture Reference
### Key Integration Points
| File | Lines | Purpose |
|------|-------|---------|
| `src/gui_2.py` | 2650-2750 | MMA Dashboard - add progress display |
| `src/project_manager.py` | 289-320 | `get_all_tracks()` - progress data |
| `src/dag_engine.py` | 50-80 | Status tracking |
### Progress Calculation
```python
def calculate_progress(tickets: list[Ticket]) -> dict:
total = len(tickets)
completed = sum(1 for t in tickets if t.status == "completed")
in_progress = sum(1 for t in tickets if t.status == "in_progress")
blocked = sum(1 for t in tickets if t.status == "blocked")
todo = sum(1 for t in tickets if t.status == "todo")
percentage = (completed / total * 100) if total > 0 else 0
return {
"total": total, "completed": completed, "in_progress": in_progress,
"blocked": blocked, "todo": todo, "percentage": percentage
}
```
## Functional Requirements ## Functional Requirements
- Progress bar showing % complete
- Ticket count: X/Y completed
- ETA estimation based on average time per ticket
## Key Integration Points ### FR1: Progress Bar
| File | Purpose | - Visual progress bar using `imgui.progress_bar()`
|-----|---------| - Show 0-100% completion
| `src/gui_2.py` | Progress bar rendering | - Color based on progress (red < 25%, yellow < 75%, green >= 75%)
| `src/dag_engine.py` | Completion calculation |
### FR2: Percentage Text
- Display "X% complete" below bar
- Show "X/Y tickets completed"
### FR3: Ticket Breakdown
- Show counts: completed, in_progress, blocked, todo
- Use colored indicators per status
### FR4: ETA Estimation
- Track average time per completed ticket
- Estimate remaining time: `avg_time * remaining_tickets`
- Display as "ETA: ~Xm"
## Non-Functional Requirements
| Requirement | Constraint |
|-------------|------------|
| Update Latency | <100ms after status change |
| Memory | <100 bytes for ETA state |
## Testing Requirements
### Unit Tests
- Test progress calculation accuracy
- Test ETA estimation logic
### Integration Tests
- Complete tickets, verify progress updates
- Verify ETA recalculates
## Out of Scope
- Historical progress tracking
- Progress export
- Multi-track comparison
## Acceptance Criteria ## Acceptance Criteria
- [ ] Progress bar renders - [ ] Progress bar renders correctly
- [ ] Percentage accurate - [ ] Percentage accurate (X/Y completed)
- [ ] Counts match actual tickets - [ ] Ticket breakdown displayed
- [ ] ETA calculation works - [ ] ETA estimation works
- [ ] 1-space indentation - [ ] Updates on ticket status change
- [ ] 1-space indentation maintained

View File

@@ -1,29 +1,102 @@
# Implementation Plan: Visual DAG Ticket Editing (visual_dag_ticket_editing_20260306) # Implementation Plan: Visual DAG Ticket Editing (visual_dag_ticket_editing_20260306)
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 1: Node Editor Setup ## Phase 1: Node Editor Setup
- [ ] Task: Initialize MMA Environment Focus: Verify ImGui Bundle node editor
- [ ] Task: Verify ImGui Bundle node editor available
- WHERE: requirements.txt
- WHAT: Ensure imgui-bundle with node editor
- HOW: pip install
## Phase 2: Implementation - [ ] Task 1.1: Initialize MMA Environment
- [ ] Task: Implement ticket node rendering - [ ] Task 1.2: Verify imgui_bundle node editor available
- WHERE: src/gui_2.py - WHERE: Check imports
- WHAT: Render tickets as nodes - HOW: `import imgui_bundle.node_editor as ed`
- HOW: imgui.node_editor with custom drawing
- SAFETY: 60fps target
- [ ] Task: Implement drag-drop
- WHERE: src/gui_2.py
- WHAT: Handle node drag and dependency lines
- HOW: Node editor callbacks
- SAFETY: Validate DAG after edit
- [ ] Task: Implement status display
- WHERE: src/gui_2.py
- WHAT: Color-coded status per node
- HOW: Node colors based on ticket status
- SAFETY: Sync with backend state
## Phase 3: Tests & Verification ## Phase 2: Basic Node Rendering
- [ ] Task: Write node editor tests Focus: Render tickets as nodes
- [ ] Task: Conductor - Phase Verification
- [ ] Task 2.1: Create node editor context
- WHERE: `src/gui_2.py` MMA dashboard
- WHAT: Begin/end node editor
- HOW:
```python
ed.begin("Ticket DAG")
for ticket in self.track.tickets:
ed.begin_node(ticket.id)
imgui.text(ticket.id)
imgui.text(ticket.status)
ed.end_node()
ed.end()
```
- [ ] Task 2.2: Set node positions
- WHERE: `src/gui_2.py`
- WHAT: Position nodes in grid
- HOW:
```python
# Auto-layout: grid positions
col = i % 4
row = i // 4
ed.set_node_position(ticket.id, col * 200, row * 150)
```
- [ ] Task 2.3: Add status colors
- WHERE: `src/gui_2.py`
- WHAT: Color nodes by status
- HOW:
```python
status_colors = {"todo": vec4(150, 150, 150, 255), "in_progress": vec4(255, 200, 100, 255),
"completed": vec4(100, 255, 100, 255), "blocked": vec4(255, 100, 100, 255)}
color = status_colors.get(ticket.status, vec4(200, 200, 200, 255))
ed.push_style_color(ed.StyleColor.node_bg, color)
```
## Phase 3: Dependency Links
Focus: Draw lines between nodes
- [ ] Task 3.1: Create links for dependencies
- WHERE: `src/gui_2.py`
- WHAT: Draw lines from dependency to dependent
- HOW:
```python
for ticket in self.track.tickets:
for dep_id in ticket.depends_on:
# Create link: dep_id -> ticket.id
ed.link(f"link_{dep_id}_{ticket.id}", dep_id, ticket.id)
```
## Phase 4: Interactive Editing
Focus: Allow creating/removing dependencies
- [ ] Task 4.1: Handle link creation
- WHERE: `src/gui_2.py`
- WHAT: Detect new links and update Ticket
- HOW:
```python
# Check for new links
if ed.begin_create():
created = ed.get_created_link()
if created:
# Add dependency to ticket
pass
ed.end_create()
```
- [ ] Task 4.2: Handle link deletion
- WHERE: `src/gui_2.py`
- WHAT: Detect deleted links
- HOW: `ed.begin_delete()`, `ed.get_deleted_link()`
- [ ] Task 4.3: Validate DAG after edit
- WHERE: `src/gui_2.py`
- WHAT: Check for cycles
- HOW:
```python
from src.dag_engine import TrackDAG
temp_dag = TrackDAG(updated_tickets)
if temp_dag.has_cycle():
imgui.open_popup("Cycle Detected!")
# Revert change
```
## Phase 5: Testing
- [ ] Task 5.1: Write unit tests
- [ ] Task 5.2: Conductor - Phase Verification