Private
Public Access
0
0

docs(conductor): Synchronize docs for track 'Context Composition Presets'

This commit is contained in:
2026-05-16 12:36:20 -04:00
parent c52e4612ae
commit fcc8822612
4 changed files with 122 additions and 30 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ For deep implementation details when planning or implementing tracks, consult `d
## Primary Use Cases
- **Full Control over Vendor APIs:** Exposing detailed API metrics and configuring deep agent capabilities directly within the GUI.
- **Context & Memory Management:** Better visualization and management of token usage and context memory. Features an independent **Context Composition** panel decoupled from the project whitelist, with directory-grouped listings and per-file **View Modes** (Full, Summary, Skeleton, Outline, None). Includes a **Visual Slice Editor** for creating fuzzy-anchored line ranges with **Annotations** (tags and comments), and **View Presets** for saving named configurations of view settings. Features a dedicated **'Context' role** for manual injections and **Context Presets** for saving and loading complete compositions. Allows assigning specific context presets to MMA agent personas for granular cognitive load isolation.
- **Context & Memory Management:** Better visualization and management of token usage and context memory. Features an independent **Context Composition** panel decoupled from the project whitelist, with directory-grouped listings and per-file **View Modes** (Full, Summary, Skeleton, Outline, None). Includes a **Visual Slice Editor** for creating fuzzy-anchored line ranges with **Annotations** (tags and comments), and **View Presets** for saving named configurations of view settings. Features a dedicated **'Context' role** for manual injections and **Context Presets** for saving and loading complete compositions with **File Existence Validation**. Includes a high-fidelity **Context Preview** window providing a scrollable Markdown view of the final aggregated context and real-time token estimation before dispatching to agents. Allows assigning specific context presets to MMA agent personas for granular cognitive load isolation.
- **Manual "Vibe Coding" Assistant:** Serving as an auxiliary, multi-provider assistant that natively interacts with the codebase via sandboxed PowerShell scripts and MCP-like file tools, emphasizing manual developer oversight and explicit confirmation.
- **State-Preserving Hot Reload:** Supports selective, manual hot-reloading of Python modules (including the main GUI logic) via a delegation-based architecture. This allows for rapid UI iteration without losing application state or restarting the session.
+2
View File
@@ -35,6 +35,8 @@
- **src/personas.py:** Implements `PersonaManager` for high-performance CRUD operations on unified agent personas stored in TOML format (`personas.toml`, `project_personas.toml`). Handles consolidation of model settings, prompts, and tool biases.
- **src/context_presets.py:** Implements `ContextPresetManager` for managing complex context compositions (files, view modes, screenshots) within the project configuration. Supports validation of file existence and relative path mapping.
- **src/tool_bias.py:** Implements the `ToolBiasEngine` for semantic tool description nudging and dynamic tooling strategy generation.
- **src/tool_presets.py:** Extends `ToolPresetManager` to handle nested `Tool` models, weights, and global `BiasProfile` persistence within `tool_presets.toml`.
+100 -28
View File
@@ -135,11 +135,31 @@ class App:
self.controller._predefined_callbacks['load_context_preset'] = self.controller.load_context_preset
self.controller._predefined_callbacks['set_ui_file_paths'] = lambda p: setattr(self, 'ui_file_paths', p)
self.controller._predefined_callbacks['set_ui_screenshot_paths'] = lambda p: setattr(self, 'ui_screenshot_paths', p)
self.controller._predefined_callbacks['set_context_files_for_test'] = lambda files: setattr(self, 'context_files', [models.FileItem(path=f) for f in files])
self.controller._predefined_callbacks['set_screenshots_for_test'] = lambda ss: setattr(self, 'screenshots', ss)
def _save_context_preset_force(name: str):
if not name: return
preset_files = []
for f in self.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(self.screenshots))
self.controller.save_context_preset(preset)
self.ui_new_context_preset_name = ""
self.show_missing_files_modal = False
self.controller._predefined_callbacks['save_context_preset_force'] = _save_context_preset_force
self.controller._predefined_callbacks['set_ui_attr'] = lambda k, v: setattr(self, k, v)
self.controller._predefined_callbacks['set_context_files'] = self._set_context_files
self.controller._predefined_callbacks['simulate_save_preset'] = self._simulate_save_preset
self.controller._clickable_actions.update({
'btn_undo': self._handle_undo,
'btn_redo': self._handle_redo,
'btn_open_external_editor': self._open_patch_in_external_editor,
'Save##ctx': self._handle_save_ctx_click,
'Save Anyway': self._handle_save_anyway_click,
})
# --- UI Component State ---
self.text_viewer_wrap = True
@@ -156,6 +176,11 @@ class App:
# --- Preset & Profile Management State ---
self.ui_active_context_preset = ""
self.ui_new_context_preset_name = ""
self._pending_save_ctx_click = False
self._pending_save_anyway_click = False
self.show_missing_files_modal = False
self.missing_context_files = []
self.target_context_preset_name = ""
self._new_preset_name = ""
self._editing_preset_name = ""
self._editing_preset_system_prompt = ""
@@ -258,6 +283,10 @@ class App:
self.shader_uniforms = {'crt': 1.0, 'scanline': 0.5, 'bloom': 0.8}
self._hot_reload_error: Optional[str] = None
def _set_context_files(self, paths: list[str]) -> None:
from src import models
self.context_files = [models.FileItem(path=p) for p in paths]
def _simulate_save_preset(self, name: str) -> None:
from src import models
item = models.FileItem(path='test.py')
@@ -269,6 +298,12 @@ class App:
"""UI-level wrapper for approving a pending tool execution ask."""
self.controller._handle_approve_ask()
def _handle_save_ctx_click(self) -> None:
self._pending_save_ctx_click = True
def _handle_save_anyway_click(self) -> None:
self._pending_save_anyway_click = True
def _post_init(self) -> None:
theme.apply_current()
@@ -553,27 +588,6 @@ class App:
pass
self.controller.shutdown()
def save_context_preset(self, name: str) -> None:
"""
[C: tests/test_context_presets.py:test_save_context_preset]
"""
sys.stderr.write(f"[DEBUG] save_context_preset called with: {name}\n")
sys.stderr.flush()
if 'context_presets' not in self.controller.project:
self.controller.project['context_presets'] = {}
preset_files = []
for f in self.context_files:
path = f.path if hasattr(f, 'path') else str(f)
view_mode = f.view_mode if hasattr(f, 'view_mode') else 'summary'
preset_files.append(models.ContextFileEntry(path=path, view_mode=view_mode))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(self.screenshots))
self.controller.project['context_presets'][name] = preset.to_dict()
self.controller._save_active_project()
sys.stderr.write(f"[DEBUG] save_context_preset finished. Project keys: {list(self.controller.project.keys())}\n")
sys.stderr.flush()
def load_context_preset(self, name: str) -> None:
"""
[C: tests/test_context_presets.py:test_load_context_preset, tests/test_context_presets.py:test_load_nonexistent_preset]
@@ -1203,6 +1217,7 @@ def render_main_interface(app: App) -> None:
# Modals / Popups
render_approve_script_modal(app)
render_mma_modals(app)
render_context_modals(app)
def render_custom_title_bar(app: App) -> None:
# Obsolete, removed since it renders behind the full screen dock space.
@@ -2845,12 +2860,12 @@ def render_context_composition_panel(app: App) -> None:
total_lines, total_ast = app._update_context_file_stats()
render_context_batch_actions(app, total_lines, total_ast)
render_context_files_table(app)
imgui.separator()
render_context_presets(app)
imgui.separator()
if imgui.collapsing_header("Screenshots"):
render_context_screenshots(app)
imgui.separator()
render_context_presets(app)
def render_ast_inspector_modal(app: App) -> None:
"""
@@ -3165,10 +3180,34 @@ def render_context_presets(app: App) -> None:
changed, new_name = imgui.input_text("##new_preset", getattr(app, "ui_new_context_preset_name", ""))
if changed: app.ui_new_context_preset_name = new_name
imgui.same_line()
if imgui.button("Save##ctx"):
if getattr(app, "ui_new_context_preset_name", "").strip():
app.save_context_preset(app.ui_new_context_preset_name.strip())
app.ui_new_context_preset_name = ""
if imgui.button("Save##ctx") or getattr(app, "_pending_save_ctx_click", False):
app._pending_save_ctx_click = False
name = getattr(app, "ui_new_context_preset_name", "").strip()
if name:
missing = []
root = app.controller.active_project_root
for f in app.context_files:
path = f.path if hasattr(f, "path") else str(f)
if not os.path.isabs(path):
full_path = os.path.join(root, path)
else:
full_path = path
if not os.path.exists(full_path):
missing.append(path)
if missing:
app.missing_context_files = missing
app.show_missing_files_modal = True
app.target_context_preset_name = name
else:
preset_files = []
for f in app.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
imgui.same_line()
if imgui.button("Delete##ctx"):
if getattr(app, "ui_active_context_preset", ""):
@@ -5197,3 +5236,36 @@ def render_mma_focus_selector(app: App) -> None:
if app.ui_focus_agent and imgui.button("x##clear_focus"): app.ui_focus_agent = None
#endregion: MMA
def render_context_modals(app: App) -> None:
if app.show_missing_files_modal:
imgui.open_popup("Missing Files Warning")
app.show_missing_files_modal = False
if imgui.begin_popup_modal("Missing Files Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text("The following files are missing from disk:")
imgui.separator()
imgui.begin_child("missing_files_list", imgui.ImVec2(0, 150), True)
for f in app.missing_context_files:
imgui.text_colored(imgui.ImVec4(1, 0.4, 0.4, 1), f)
imgui.end_child()
imgui.separator()
if imgui.button("Save Anyway") or getattr(app, "_pending_save_anyway_click", False):
app._pending_save_anyway_click = False
name = app.target_context_preset_name
preset_files = []
for f in app.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
app.ui_new_context_preset_name = ""
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel"):
imgui.close_current_popup()
imgui.end_popup()
+19 -1
View File
@@ -11,7 +11,20 @@ def test_gui_context_preset_save_load(live_gui) -> None:
test_files = ["test.py"]
test_screenshots = ["test.png"]
client.push_event("custom_callback", {"callback": "simulate_save_preset", "args": [preset_name]})
# Switch to Context Composition tab to ensure it's rendered
client.push_event("select_tab", {"tab": "Context Composition"})
time.sleep(1.0)
# Inject context state directly
client.push_event("custom_callback", {"callback": "set_context_files_for_test", "args": [test_files]})
client.push_event("custom_callback", {"callback": "set_screenshots_for_test", "args": [test_screenshots]})
client.push_event("custom_callback", {"callback": "set_ui_attr", "args": ["ui_new_context_preset_name", preset_name]})
time.sleep(1.0)
# Trigger Save (which will trigger validation, and since test.py doesn't exist, it opens a modal)
client.push_event("custom_callback", {"callback": "set_ui_attr", "args": ["_pending_save_ctx_click", True]})
time.sleep(1.0)
# The "Missing Files Warning" modal should be open. Trigger "Save Anyway".
client.push_event("custom_callback", {"callback": "set_ui_attr", "args": ["_pending_save_anyway_click", True]})
time.sleep(1.5)
project_data = client.get_project()
@@ -25,6 +38,11 @@ def test_gui_context_preset_save_load(live_gui) -> None:
assert preset_files == test_files
assert preset_entry.get("screenshots", []) == test_screenshots
# Clear current state
client.push_event("custom_callback", {"callback": "set_context_files_for_test", "args": [[]]})
client.push_event("custom_callback", {"callback": "set_screenshots_for_test", "args": [[]]})
time.sleep(1.0)
# Load the preset
client.push_event("custom_callback", {"callback": "load_context_preset", "args": [preset_name]})
time.sleep(1.0)