From 42af7db7f93809d9e39a130c72dce97e26582ab0 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 12 Jun 2026 22:01:36 -0400 Subject: [PATCH] Add SSDL-style docstrings to preset manager and persona editor functions, and fix embedded call delegation bug --- project_history.toml | 2 +- src/gui_2.py | 248 ++++++++++++++++++++++++++++--------------- 2 files changed, 166 insertions(+), 84 deletions(-) diff --git a/project_history.toml b/project_history.toml index c8d5d1bd..a257b754 100644 --- a/project_history.toml +++ b/project_history.toml @@ -9,5 +9,5 @@ active = "main" [discussions.main] git_commit = "" -last_updated = "2026-06-12T21:55:15" +last_updated = "2026-06-12T22:01:30" history = [] diff --git a/src/gui_2.py b/src/gui_2.py index e4069085..94d317c9 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -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)