Add SSDL-style docstrings to preset manager and persona editor functions, and fix embedded call delegation bug
This commit is contained in:
@@ -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 = []
|
||||
|
||||
+165
-83
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user