Private
Public Access
0
0

Add SSDL-style docstrings to preset manager and persona editor functions, and fix embedded call delegation bug

This commit is contained in:
2026-06-12 22:01:36 -04:00
parent c3edbd9543
commit 42af7db7f9
2 changed files with 166 additions and 84 deletions
+165 -83
View File
@@ -311,7 +311,7 @@ class App:
SSDL Shape:
`[I:init_controller] -> [I:init_workspace] -> [I:load_profiles]`
"""
# --- Core Dependencies & State ---
#region: --- Core Dependencies & State ---
from src.startup_profiler import startup_profiler
with startup_profiler.phase("app_init_AppController"):
self.controller = app_controller.AppController(defer_warmup=True)
@@ -320,14 +320,17 @@ class App:
from src import history, performance_monitor
self.perf_monitor = performance_monitor.PerformanceMonitor()
self.history = history.HistoryManager(max_capacity=100)
# --- Undo/Redo & Snapshot State ---
self._last_ui_snapshot: Optional[history.UISnapshot] = None
self._snapshot_timer: float = 0.0
self._snapshot_debounce: float = 1.5
self._pending_snapshot: bool = False
self._last_ui_snapshot: Optional[history.UISnapshot] = None
self._snapshot_timer: float = 0.0
self._snapshot_debounce: float = 1.5
self._pending_snapshot: bool = False
self._is_applying_snapshot: bool = False
# --- Command Palette ---
self.show_command_palette: bool = False
# --- Initialization ---
with startup_profiler.phase("app_init_state"):
self.controller.init_state()
@@ -339,13 +342,15 @@ class App:
state_keys=['active_discussion', 'show_windows', 'ui_file_paths', 'ui_screenshot_paths', 'disc_entries', 'disc_roles'],
delegation_targets=['_render_main_interface', '_render_discussion_hub', '_render_files_and_media', '_render_ai_settings_hub', '_render_operations_hub', '_render_mma_dashboard']
))
with startup_profiler.phase("app_init_workspace"):
self.workspace_manager = workspace_manager.WorkspaceManager(project_root=self.controller.active_project_root)
self.disc_entries = self.controller.disc_entries
self.disc_roles = self.controller.disc_roles
self.workspace_profiles = self.workspace_manager.load_all_profiles()
with startup_profiler.phase("app_init_start_services"): self.controller.start_services(self)
# --- Controller Callbacks & Actions ---
#region: --- Controller Callbacks & Actions ---
self.controller._predefined_callbacks['save_context_preset'] = self.save_context_preset
self.controller._predefined_callbacks['load_context_preset'] = self.load_context_preset
self.controller._predefined_callbacks['delete_context_preset'] = self.delete_context_preset
@@ -355,72 +360,76 @@ class App:
self.controller._predefined_callbacks['set_screenshots_for_test'] = lambda ss: setattr(self, 'screenshots', ss)
self.controller._predefined_callbacks['_toggle_command_palette'] = self._toggle_command_palette
self.controller._gettable_fields['show_command_palette'] = 'show_command_palette'
#endregion: --- Core Dependencies & State ---
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'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
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['get_app_debug_info'] = lambda: self.app_debug_info
self.controller._gettable_fields['app_debug_info'] = 'app_debug_info'
self.controller._predefined_callbacks['get_app_debug_info'] = lambda: self.app_debug_info
self.controller._gettable_fields ['app_debug_info'] = 'app_debug_info'
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._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_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,
'Save##ctx': self._handle_save_ctx_click,
'Save Anyway': self._handle_save_anyway_click,
})
# --- UI Component State ---
#region: --- UI Component State ---
self.text_viewer_wrap = True
self._text_viewer_editor: Optional[ced.TextEditor] = None
self.show_windows.setdefault("Diagnostics", False)
self.show_windows.setdefault("Usage Analytics", False)
self.show_windows.setdefault("Context Preview", False)
self.show_windows.setdefault("Tier 1: Strategy", False)
self.show_windows.setdefault("Diagnostics", False)
self.show_windows.setdefault("Usage Analytics", False)
self.show_windows.setdefault("Context Preview", False)
self.show_windows.setdefault("Tier 1: Strategy", False)
self.show_windows.setdefault("Tier 2: Tech Lead", False)
self.show_windows.setdefault("Tier 3: Workers", False)
self.show_windows.setdefault("Tier 4: QA", False)
self.show_windows.setdefault('External Tools', False)
self.show_windows.setdefault('Shader Editor', False)
self.show_windows.setdefault("Tier 3: Workers", False)
self.show_windows.setdefault("Tier 4: QA", False)
self.show_windows.setdefault('External Tools', False)
self.show_windows.setdefault('Shader Editor', False)
self.show_windows.setdefault('Undo/Redo History', False)
# --- Preset & Profile Management State ---
self.context_preview_text = ""
self.ui_separate_context_preview = False
self.ui_active_context_preset = ""
self.target_context_preset_name = ""
self.show_empty_context_modal = False
self._pending_generation_action = None # 'generate' or 'md_only'
self._pending_save_ctx_click = False
self._pending_save_anyway_click = False
self.show_missing_files_modal = False
self.show_structural_editor_modal = False
self.show_command_palette = False
self.ui_command_search = ""
self.ui_command_idx = 0
self.missing_context_files = []
self._new_preset_name = ""
self._editing_preset_name = ""
self._editing_preset_system_prompt = ""
self._editing_preset_temperature = 0.0
self._editing_preset_top_p = 1.0
self._editing_preset_max_output_tokens = 4096
self._editing_preset_scope = "project"
self._editing_preset_is_new = False
self._presets_list: dict[str, dict] = {}
#endregion: --- UI Component State ---
#region: --- Preset & Profile Management State ---
self.context_preview_text = ""
self.ui_separate_context_preview = False
self.ui_active_context_preset = ""
self.target_context_preset_name = ""
self.show_empty_context_modal = False
self._pending_generation_action = None # 'generate' or 'md_only'
self._pending_save_ctx_click = False
self._pending_save_anyway_click = False
self.show_missing_files_modal = False
self.show_structural_editor_modal = False
self.show_command_palette = False
self.ui_command_search = ""
self.ui_command_idx = 0
self.missing_context_files = []
self._new_preset_name = ""
self._editing_preset_name = ""
self._editing_preset_system_prompt = ""
self._editing_preset_temperature = 0.0
self._editing_preset_top_p = 1.0
self._editing_preset_max_output_tokens = 4096
self._editing_preset_scope = "project"
self._editing_preset_is_new = False
self._presets_list: dict[str, dict] = {}
self._selected_preset_idx = -1
self._show_save_preset_modal = False
self._editing_tool_preset_name = ''
@@ -428,7 +437,7 @@ class App:
self._editing_tool_preset_scope = 'project'
self._selected_tool_preset_idx = -1
self._editing_bias_profile_name = ""
self._editing_bias_profile_tool_weights : dict[str, int] = {}
self._editing_bias_profile_tool_weights: dict[str, int] = {}
self._editing_bias_profile_category_multipliers: dict[str, float] = {}
self._editing_bias_profile_scope = "project"
self._selected_bias_profile_idx = -1
@@ -451,46 +460,53 @@ class App:
self._editing_persona_is_new = True
self._persona_editor_opened = False
self._personas_list: dict[str, dict] = {}
#endregion --- Preset & Profile Management State ---
# --- Layout State ---
self._persona_split_v = 0.4
self._persona_models_open = True
self._persona_prompt_open = True
self._tool_split_v = 0.4
self._bias_split_v = 0.6
self._tool_list_open = True
self._bias_list_open = True
self._bias_weights_open = True
self._bias_cats_open = True
self._prompt_md_preview = False
self._persona_split_v = 0.4
self._persona_models_open = True
self._persona_prompt_open = True
self._tool_split_v = 0.4
self._bias_split_v = 0.6
self._tool_list_open = True
self._bias_list_open = True
self._bias_weights_open = True
self._bias_cats_open = True
self._prompt_md_preview = False
self.ui_discussion_split_h = 300.0
# --- Workspace State ---
gui_cfg = self.config.get("gui", {})
self.ui_multi_viewport = gui_cfg.get("multi_viewport", False)
self.layout_presets = self.config.get("layout_presets", {})
self.ui_multi_viewport = gui_cfg.get("multi_viewport", False)
self.layout_presets = self.config.get("layout_presets", {})
self._show_save_workspace_profile_modal = False
self._new_workspace_profile_name = ""
self._new_workspace_profile_scope = "project"
self.ui_new_vp_name = ""
self._new_workspace_profile_name = ""
self._new_workspace_profile_scope = "project"
self.ui_new_vp_name = ""
# --- Controller Lock Aliases ---
self._send_thread_lock = self.controller._send_thread_lock
self._disc_entries_lock = self.controller._disc_entries_lock
self._pending_comms_lock = self.controller._pending_comms_lock
self._pending_tool_calls_lock = self.controller._pending_tool_calls_lock
self._send_thread_lock = self.controller._send_thread_lock
self._disc_entries_lock = self.controller._disc_entries_lock
self._pending_comms_lock = self.controller._pending_comms_lock
self._pending_tool_calls_lock = self.controller._pending_tool_calls_lock
self._pending_history_adds_lock = self.controller._pending_history_adds_lock
self._pending_gui_tasks_lock = self.controller._pending_gui_tasks_lock
self._pending_dialog_lock = self.controller._pending_dialog_lock
self._api_event_queue_lock = self.controller._api_event_queue_lock
self._pending_gui_tasks_lock = self.controller._pending_gui_tasks_lock
self._pending_dialog_lock = self.controller._pending_dialog_lock
self._api_event_queue_lock = self.controller._api_event_queue_lock
# --- Cache & Discussion State ---
self._discussion_names_cache: list[str] = []
self._discussion_names_dirty: bool = True
self._comms_log_cache: list[dict[str, Any]] = []
self._tool_log_cache: list[dict[str, Any]] = []
self._focus_md_cache: dict[str, str] = {}
self._last_ui_focus_agent: Optional[str] = None
self._log_registry: Optional[log_registry.LogRegistry] = None
self._comms_log_cache: list[dict[str, Any]] = []
self._tool_log_cache: list[dict[str, Any]] = []
self._focus_md_cache: dict[str, str] = {}
self._last_ui_focus_agent: Optional[str] = None
self._log_registry: Optional[log_registry.LogRegistry] = None
# --- Node Editor State ---
self.node_editor_config = ed.Config()
self.node_editor_ctx = ed.create_editor(self.node_editor_config)
# --- Context & AST State ---
self.ui_selected_ticket_id: Optional[str] = None
self.ui_selected_tickets: set[str] = set()
@@ -509,6 +525,7 @@ class App:
self.context_files = []
self.ui_synthesis_prompt: str = ""
self.ui_synthesis_selected_takes: dict[str, bool] = {}
# --- Rendering & Theme State ---
self.perf_show_graphs: dict[str, bool] = {}
self.ui_crt_filter = False
@@ -2817,6 +2834,17 @@ def render_base_prompt_diff_modal(app: App) -> None:
imgui.end_popup()
def render_save_preset_modal(app: App) -> None:
"""
Renders the popup modal for saving the current ImGui window layout preset.
State Mutations:
app._show_save_preset_modal (toggles visibility)
app._new_preset_name (stores input layout name)
app.layout_presets (saves layout definitions to configuration)
SSDL Shape:
`[I:preset_inputs] => [B:save_cancel]`
"""
if not app._show_save_preset_modal: return
imgui.open_popup("Save Layout Preset")
with imscope.popup_modal("Save Layout Preset", True, imgui.WindowFlags_.always_auto_resize) as (opened, _):
@@ -2841,6 +2869,17 @@ def render_save_preset_modal(app: App) -> None:
imgui.close_current_popup()
def render_preset_manager_content(app: App, is_embedded: bool = False) -> None:
"""
Renders the core prompt preset manager interface including the sidebar preset selector
and the preset prompt content text editor.
State Mutations:
app._selected_preset_idx
app._editing_preset_name, app._editing_preset_system_prompt, app._editing_preset_scope
SSDL Shape:
`[I:presets_list] -> [B:new_preset] -> [I:editor_meta] -> [I:editor_textbox] => [B:save_delete]`
"""
avail = imgui.get_content_region_avail()
if not hasattr(app, "_prompt_md_preview"): app._prompt_md_preview = False
@@ -2930,6 +2969,15 @@ def render_preset_manager_content(app: App, is_embedded: bool = False) -> None:
imgui.end_table()
def render_preset_manager_window(app: App, is_embedded: bool = False) -> None:
"""
Renders the window container for the Prompt Presets Manager.
State Mutations:
app.show_preset_manager_window (visibility toggle)
SSDL Shape:
`[I] -> [I:window] => [I:preset_manager_content]`
"""
if not app.show_preset_manager_window and not is_embedded: return
if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
@@ -2940,6 +2988,16 @@ def render_preset_manager_window(app: App, is_embedded: bool = False) -> None:
render_preset_manager_content(app, is_embedded=is_embedded)
def render_tool_preset_manager_content(app: App, is_embedded: bool = False) -> None:
"""
Renders the tool presets and tool capability profiles editor layout.
State Mutations:
app._editing_tool_preset_name, app._editing_tool_preset_scope, app._selected_tool_preset_idx
app.controller (saves/deletes tool presets)
SSDL Shape:
`[I:tool_presets] -> [B:new_tool_preset] -> [I:capability_toggles] -> [I:tools_list] => [B:save_delete]`
"""
avail = imgui.get_content_region_avail()
if not hasattr(app, "_tool_split_v"): app._tool_split_v = 0.4
if not hasattr(app, "_bias_split_v"): app._bias_split_v = 0.6
@@ -3119,6 +3177,15 @@ def render_tool_preset_manager_content(app: App, is_embedded: bool = False) -> N
imgui.end_table()
def render_tool_preset_manager_window(app: App, is_embedded: bool = False) -> None:
"""
Renders the window container for the Tool Preset Manager.
State Mutations:
app.show_tool_preset_manager_window (visibility toggle)
SSDL Shape:
`[I] -> [I:window] => [I:tool_preset_manager_content]`
"""
if not app.show_tool_preset_manager_window and not is_embedded: return
if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
@@ -3126,9 +3193,24 @@ def render_tool_preset_manager_window(app: App, is_embedded: bool = False) -> No
app.show_tool_preset_manager_window = visible
if opened: render_tool_preset_manager_content(app, is_embedded=is_embedded)
else:
render_preset_manager_content(app, is_embedded=is_embedded)
render_tool_preset_manager_content(app, is_embedded=is_embedded)
def render_persona_editor_window(app: App, is_embedded: bool = False) -> None:
"""
Renders the Persona Editor window, allowing creating, deleting, and modifying persona settings
(prompts, preferred models list, tool presets, aggregation strategy, etc).
State Mutations:
app.show_persona_editor_window (visibility toggle)
app._editing_persona_name, app._editing_persona_system_prompt
app._editing_persona_tool_preset_id, app._editing_persona_bias_profile_id
app._editing_persona_context_preset_id, app._editing_persona_aggregation_strategy
app._editing_persona_preferred_models_list, app._editing_persona_is_new
app.controller (saves/deletes personas)
SSDL Shape:
`[I:personas_list] -> [B:new_persona] -> [I:settings_editor] -> [I:models_list] -> [I:system_prompt_box] => [B:save_delete]`
"""
if not app.show_persona_editor_window and not is_embedded: return
if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)