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

This commit is contained in:
ed
2026-06-12 22:01:36 -04:00
parent c3edbd9543
commit 42af7db7f9
2 changed files with 166 additions and 84 deletions
+1 -1
View File
@@ -9,5 +9,5 @@ active = "main"
[discussions.main] [discussions.main]
git_commit = "" git_commit = ""
last_updated = "2026-06-12T21:55:15" last_updated = "2026-06-12T22:01:30"
history = [] history = []
+87 -5
View File
@@ -311,7 +311,7 @@ class App:
SSDL Shape: SSDL Shape:
`[I:init_controller] -> [I:init_workspace] -> [I:load_profiles]` `[I:init_controller] -> [I:init_workspace] -> [I:load_profiles]`
""" """
# --- Core Dependencies & State --- #region: --- Core Dependencies & State ---
from src.startup_profiler import startup_profiler from src.startup_profiler import startup_profiler
with startup_profiler.phase("app_init_AppController"): with startup_profiler.phase("app_init_AppController"):
self.controller = app_controller.AppController(defer_warmup=True) self.controller = app_controller.AppController(defer_warmup=True)
@@ -320,14 +320,17 @@ class App:
from src import history, performance_monitor from src import history, performance_monitor
self.perf_monitor = performance_monitor.PerformanceMonitor() self.perf_monitor = performance_monitor.PerformanceMonitor()
self.history = history.HistoryManager(max_capacity=100) self.history = history.HistoryManager(max_capacity=100)
# --- Undo/Redo & Snapshot State --- # --- Undo/Redo & Snapshot State ---
self._last_ui_snapshot: Optional[history.UISnapshot] = None self._last_ui_snapshot: Optional[history.UISnapshot] = None
self._snapshot_timer: float = 0.0 self._snapshot_timer: float = 0.0
self._snapshot_debounce: float = 1.5 self._snapshot_debounce: float = 1.5
self._pending_snapshot: bool = False self._pending_snapshot: bool = False
self._is_applying_snapshot: bool = False self._is_applying_snapshot: bool = False
# --- Command Palette --- # --- Command Palette ---
self.show_command_palette: bool = False self.show_command_palette: bool = False
# --- Initialization --- # --- Initialization ---
with startup_profiler.phase("app_init_state"): with startup_profiler.phase("app_init_state"):
self.controller.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'], 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'] 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"): with startup_profiler.phase("app_init_workspace"):
self.workspace_manager = workspace_manager.WorkspaceManager(project_root=self.controller.active_project_root) self.workspace_manager = workspace_manager.WorkspaceManager(project_root=self.controller.active_project_root)
self.disc_entries = self.controller.disc_entries self.disc_entries = self.controller.disc_entries
self.disc_roles = self.controller.disc_roles self.disc_roles = self.controller.disc_roles
self.workspace_profiles = self.workspace_manager.load_all_profiles() self.workspace_profiles = self.workspace_manager.load_all_profiles()
with startup_profiler.phase("app_init_start_services"): self.controller.start_services(self) 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['save_context_preset'] = self.save_context_preset
self.controller._predefined_callbacks['load_context_preset'] = self.load_context_preset self.controller._predefined_callbacks['load_context_preset'] = self.load_context_preset
self.controller._predefined_callbacks['delete_context_preset'] = self.delete_context_preset self.controller._predefined_callbacks['delete_context_preset'] = self.delete_context_preset
@@ -355,6 +360,7 @@ class App:
self.controller._predefined_callbacks['set_screenshots_for_test'] = lambda ss: setattr(self, 'screenshots', ss) 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._predefined_callbacks['_toggle_command_palette'] = self._toggle_command_palette
self.controller._gettable_fields['show_command_palette'] = 'show_command_palette' self.controller._gettable_fields['show_command_palette'] = 'show_command_palette'
#endregion: --- Core Dependencies & State ---
def _save_context_preset_force(name: str): def _save_context_preset_force(name: str):
if not name: return if not name: return
@@ -384,7 +390,8 @@ class App:
'Save##ctx': self._handle_save_ctx_click, 'Save##ctx': self._handle_save_ctx_click,
'Save Anyway': self._handle_save_anyway_click, 'Save Anyway': self._handle_save_anyway_click,
}) })
# --- UI Component State ---
#region: --- UI Component State ---
self.text_viewer_wrap = True self.text_viewer_wrap = True
self._text_viewer_editor: Optional[ced.TextEditor] = None self._text_viewer_editor: Optional[ced.TextEditor] = None
self.show_windows.setdefault("Diagnostics", False) self.show_windows.setdefault("Diagnostics", False)
@@ -397,7 +404,9 @@ class App:
self.show_windows.setdefault('External Tools', False) self.show_windows.setdefault('External Tools', False)
self.show_windows.setdefault('Shader Editor', False) self.show_windows.setdefault('Shader Editor', False)
self.show_windows.setdefault('Undo/Redo History', False) self.show_windows.setdefault('Undo/Redo History', False)
# --- Preset & Profile Management State --- #endregion: --- UI Component State ---
#region: --- Preset & Profile Management State ---
self.context_preview_text = "" self.context_preview_text = ""
self.ui_separate_context_preview = False self.ui_separate_context_preview = False
self.ui_active_context_preset = "" self.ui_active_context_preset = ""
@@ -451,6 +460,8 @@ class App:
self._editing_persona_is_new = True self._editing_persona_is_new = True
self._persona_editor_opened = False self._persona_editor_opened = False
self._personas_list: dict[str, dict] = {} self._personas_list: dict[str, dict] = {}
#endregion --- Preset & Profile Management State ---
# --- Layout State --- # --- Layout State ---
self._persona_split_v = 0.4 self._persona_split_v = 0.4
self._persona_models_open = True self._persona_models_open = True
@@ -463,6 +474,7 @@ class App:
self._bias_cats_open = True self._bias_cats_open = True
self._prompt_md_preview = False self._prompt_md_preview = False
self.ui_discussion_split_h = 300.0 self.ui_discussion_split_h = 300.0
# --- Workspace State --- # --- Workspace State ---
gui_cfg = self.config.get("gui", {}) gui_cfg = self.config.get("gui", {})
self.ui_multi_viewport = gui_cfg.get("multi_viewport", False) self.ui_multi_viewport = gui_cfg.get("multi_viewport", False)
@@ -471,6 +483,7 @@ class App:
self._new_workspace_profile_name = "" self._new_workspace_profile_name = ""
self._new_workspace_profile_scope = "project" self._new_workspace_profile_scope = "project"
self.ui_new_vp_name = "" self.ui_new_vp_name = ""
# --- Controller Lock Aliases --- # --- Controller Lock Aliases ---
self._send_thread_lock = self.controller._send_thread_lock self._send_thread_lock = self.controller._send_thread_lock
self._disc_entries_lock = self.controller._disc_entries_lock self._disc_entries_lock = self.controller._disc_entries_lock
@@ -480,6 +493,7 @@ class App:
self._pending_gui_tasks_lock = self.controller._pending_gui_tasks_lock self._pending_gui_tasks_lock = self.controller._pending_gui_tasks_lock
self._pending_dialog_lock = self.controller._pending_dialog_lock self._pending_dialog_lock = self.controller._pending_dialog_lock
self._api_event_queue_lock = self.controller._api_event_queue_lock self._api_event_queue_lock = self.controller._api_event_queue_lock
# --- Cache & Discussion State --- # --- Cache & Discussion State ---
self._discussion_names_cache: list[str] = [] self._discussion_names_cache: list[str] = []
self._discussion_names_dirty: bool = True self._discussion_names_dirty: bool = True
@@ -488,9 +502,11 @@ class App:
self._focus_md_cache: dict[str, str] = {} self._focus_md_cache: dict[str, str] = {}
self._last_ui_focus_agent: Optional[str] = None self._last_ui_focus_agent: Optional[str] = None
self._log_registry: Optional[log_registry.LogRegistry] = None self._log_registry: Optional[log_registry.LogRegistry] = None
# --- Node Editor State --- # --- Node Editor State ---
self.node_editor_config = ed.Config() self.node_editor_config = ed.Config()
self.node_editor_ctx = ed.create_editor(self.node_editor_config) self.node_editor_ctx = ed.create_editor(self.node_editor_config)
# --- Context & AST State --- # --- Context & AST State ---
self.ui_selected_ticket_id: Optional[str] = None self.ui_selected_ticket_id: Optional[str] = None
self.ui_selected_tickets: set[str] = set() self.ui_selected_tickets: set[str] = set()
@@ -509,6 +525,7 @@ class App:
self.context_files = [] self.context_files = []
self.ui_synthesis_prompt: str = "" self.ui_synthesis_prompt: str = ""
self.ui_synthesis_selected_takes: dict[str, bool] = {} self.ui_synthesis_selected_takes: dict[str, bool] = {}
# --- Rendering & Theme State --- # --- Rendering & Theme State ---
self.perf_show_graphs: dict[str, bool] = {} self.perf_show_graphs: dict[str, bool] = {}
self.ui_crt_filter = False self.ui_crt_filter = False
@@ -2817,6 +2834,17 @@ def render_base_prompt_diff_modal(app: App) -> None:
imgui.end_popup() imgui.end_popup()
def render_save_preset_modal(app: App) -> None: 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 if not app._show_save_preset_modal: return
imgui.open_popup("Save Layout Preset") imgui.open_popup("Save Layout Preset")
with imscope.popup_modal("Save Layout Preset", True, imgui.WindowFlags_.always_auto_resize) as (opened, _): 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() imgui.close_current_popup()
def render_preset_manager_content(app: App, is_embedded: bool = False) -> None: 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() avail = imgui.get_content_region_avail()
if not hasattr(app, "_prompt_md_preview"): app._prompt_md_preview = False 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() imgui.end_table()
def render_preset_manager_window(app: App, is_embedded: bool = False) -> None: 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 app.show_preset_manager_window and not is_embedded: return
if not is_embedded: if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) 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) render_preset_manager_content(app, is_embedded=is_embedded)
def render_tool_preset_manager_content(app: App, is_embedded: bool = False) -> None: 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() avail = imgui.get_content_region_avail()
if not hasattr(app, "_tool_split_v"): app._tool_split_v = 0.4 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 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() imgui.end_table()
def render_tool_preset_manager_window(app: App, is_embedded: bool = False) -> None: 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 app.show_tool_preset_manager_window and not is_embedded: return
if not is_embedded: if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) 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 app.show_tool_preset_manager_window = visible
if opened: render_tool_preset_manager_content(app, is_embedded=is_embedded) if opened: render_tool_preset_manager_content(app, is_embedded=is_embedded)
else: 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: 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 app.show_persona_editor_window and not is_embedded: return
if not is_embedded: if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)