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

@@ -1,202 +1,141 @@
# Implementation Plan: Manual Skeleton Context Injection (manual_skeleton_injection_20260306)
## Phase 1: File Selection UI
- [ ] 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
> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md)
## Phase 2: Skeleton Preview
- [ ] Task: Generate preview
- 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 1: UI Foundation
Focus: Add file injection button and state
## Phase 3: Full Read Option
- [ ] Task: Add full read toggle
- WHERE: src/gui_2.py
- WHAT: Option for full file
- HOW: Checkbox/switch
- [ ] Task 1.1: Initialize MMA Environment
- Run `activate_skill mma-orchestrator` before starting
## Phase 4: Verification
- [ ] Task: Test injection flow
- [ ] Task: Conductor - Phase Verification
## Phase 1: Skeleton Preview
- [ ] Task: Implement inject button
- WHERE: src/gui_2.py discussion panel
- how: Call ASTParser.get_skeleton() for preview
- Display preview
- on preview change, regenerate skeleton via `get_skeleton()`
- Show "Skeleton" or "Full" toggle in preview
- on "Inject", append to discussion input
- [ ] Task: Add toggle logic
- where: src/gui_2.py
- how: imgui.checkbox to toggle between skeleton/full file
- On toggle change, regenerate skeleton
- else:
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
time.sleep(0.5) # Check for slow operations
time.sleep(0.5)
for i, range(len(tickets):
t = t. completed
t.status = "completed"
else:
t.status = "in_progress"
# Session stats header
if imgui.collapsing_header("Session Statistics"):
imgui.text_wrapped(f"Tokens: {sum(t['input'] + t['output']):,}")
imgui.text(f"Cost projection: ${cost_tracker.estimate_cost(t['model'], t['input'], t['output']) * 1.0:.4f}")
# Cost projection
burn_rate = tokens_per minute * sum(t['input'] / t['output'] * 60)
time.sleep =(session - now)
projected_remaining = time = now() - remaining_time
- [ ] Task 1.2: Add injection state variables
- WHERE: `src/gui_2.py` `App.__init__`
- WHAT: State for injection UI
- HOW:
```python
self._inject_file_path: str = ""
self._inject_mode: str = "skeleton" # "skeleton" | "full"
self._inject_preview: str = ""
self._show_inject_modal: bool = False
```
- CODE STYLE: 1-space indentation
- [ ] Task 1.3: Add inject button to discussion panel
- WHERE: `src/gui_2.py` discussion panel
- WHAT: Button to open injection modal
- HOW:
```python
if imgui.button("Inject File"):
self._show_inject_modal = True
```
## Phase 2: File Selection
Focus: File picker and path validation
- [ ] Task 2.1: Create file selection modal
- WHERE: `src/gui_2.py`
- 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:
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.text_wrapped(f" {priority}")
imgui.end()
# Drag-drop reordering
imgui.combo("Reorder", options: top/bottom/after")
imgui.text("Top")
imgui.text("Bottom")
else
imgui.text("Bulk Actions")
imgui.text("Apply to: execute/skip/block")
imgui.end_child()
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}"
```
- [ ] Task 3.2: Add mode toggle
- WHERE: `src/gui_2.py` inject modal
- WHAT: Radio buttons for skeleton/full
- HOW:
```python
if imgui.radio_button("Skeleton", self._inject_mode == "skeleton"):
self._inject_mode = "skeleton"
self._update_inject_preview()
imgui.same_line()
if imgui.radio_button("Full File", self._inject_mode == "full"):
self._inject_mode = "full"
self._update_inject_preview()
```
- [ ] Task 3.3: Display preview
- WHERE: `src/gui_2.py` inject modal
- WHAT: Scrollable preview area
- HOW:
```python
imgui.begin_child("preview", height=300)
imgui.text_wrapped(self._inject_preview)
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
imgui.end_table()

View File

@@ -1,36 +1,113 @@
# Track Specification: Manual Skeleton Context Injection (manual_skeleton_injection_20260306)
## 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
### 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
- No UI to flag files for skeleton vs full
- No preview of skeleton before injection
- No on-demand definition lookup
#### ASTParser (src/file_cache.py)
- **`ASTParser` class**: Uses tree-sitter for Python parsing
- **`get_skeleton(code: str) -> str`**: Returns file skeleton (signatures/docstrings preserved, function bodies replaced with `...`)
- **`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
- File picker UI in discussion panel
- Skeleton preview before injection
- Toggle: skeleton vs full file
- Uses existing `py_get_skeleton()` tool
## Key Integration Points
| File | Purpose |
|-----|---------|
| `src/gui_2.py` | File picker, injection UI |
| `src/mcp_client.py` | `py_get_skeleton()` |
| `src/file_cache.py` | `ASTParser` |
### FR1: File Selection
- Button "Inject File" in discussion panel
- Opens file browser limited to project files
- Path validation against project's `files.base_dir`
### 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
- [ ] File picker UI functional
- [ ] Skeleton preview displays
- [ ] Manual refresh button works
- [ ] Full read option available
- [ ] 1-space indentation
- [ ] "Inject File" button in discussion panel
- [ ] File browser limits to project files
- [ ] Skeleton/Full toggle works
- [ ] Preview displays correctly
- [ ] Inject appends to input
- [ ] Large file truncation works
- [ ] 1-space indentation maintained