chore(conductor): Mark track 'Saved System Prompt Presets' as complete

This commit is contained in:
2026-03-09 22:35:52 -04:00
parent e2a403a187
commit 95381c258c
9 changed files with 1729 additions and 158 deletions

View File

@@ -346,40 +346,40 @@ class AppController:
}
self._gettable_fields = dict(self._settable_fields)
self._gettable_fields.update({
'ui_focus_agent': 'ui_focus_agent',
'active_discussion': 'active_discussion',
'_track_discussion_active': '_track_discussion_active',
'proposed_tracks': 'proposed_tracks',
'mma_streams': 'mma_streams',
'_worker_status': '_worker_status',
'active_track': 'active_track',
'active_tickets': 'active_tickets',
'tracks': 'tracks',
'thinking_indicator': 'thinking_indicator',
'operations_live_indicator': 'operations_live_indicator',
'prior_session_indicator': 'prior_session_indicator',
'_show_patch_modal': '_show_patch_modal',
'_pending_patch_text': '_pending_patch_text',
'_pending_patch_files': '_pending_patch_files',
'_inject_file_path': '_inject_file_path',
'_inject_mode': '_inject_mode',
'_inject_preview': '_inject_preview',
'_show_inject_modal': '_show_inject_modal',
'bg_shader_enabled': 'bg_shader_enabled',
'global_system_prompt': 'ui_global_system_prompt',
'project_system_prompt': 'ui_project_system_prompt',
'global_preset_name': 'ui_global_preset_name',
'project_preset_name': 'ui_project_preset_name',
'temperature': 'temperature',
'max_tokens': 'max_tokens',
'show_preset_manager_modal': 'show_preset_manager_modal',
'_editing_preset_name': '_editing_preset_name',
'_editing_preset_content': '_editing_preset_content',
'_editing_preset_temperature': '_editing_preset_temperature',
'_editing_preset_top_p': '_editing_preset_top_p',
'_editing_preset_max_output_tokens': '_editing_preset_max_output_tokens',
'_editing_preset_scope': '_editing_preset_scope'
})
'ui_focus_agent': 'ui_focus_agent',
'active_discussion': 'active_discussion',
'_track_discussion_active': '_track_discussion_active',
'proposed_tracks': 'proposed_tracks',
'mma_streams': 'mma_streams',
'_worker_status': '_worker_status',
'active_track': 'active_track',
'active_tickets': 'active_tickets',
'tracks': 'tracks',
'thinking_indicator': 'thinking_indicator',
'operations_live_indicator': 'operations_live_indicator',
'prior_session_indicator': 'prior_session_indicator',
'_show_patch_modal': '_show_patch_modal',
'_pending_patch_text': '_pending_patch_text',
'_pending_patch_files': '_pending_patch_files',
'_inject_file_path': '_inject_file_path',
'_inject_mode': '_inject_mode',
'_inject_preview': '_inject_preview',
'_show_inject_modal': '_show_inject_modal',
'bg_shader_enabled': 'bg_shader_enabled',
'global_system_prompt': 'ui_global_system_prompt',
'project_system_prompt': 'ui_project_system_prompt',
'global_preset_name': 'ui_global_preset_name',
'project_preset_name': 'ui_project_preset_name',
'temperature': 'temperature',
'max_tokens': 'max_tokens',
'show_preset_manager_modal': 'show_preset_manager_modal',
'_editing_preset_name': '_editing_preset_name',
'_editing_preset_content': '_editing_preset_content',
'_editing_preset_temperature': '_editing_preset_temperature',
'_editing_preset_top_p': '_editing_preset_top_p',
'_editing_preset_max_output_tokens': '_editing_preset_max_output_tokens',
'_editing_preset_scope': '_editing_preset_scope'
})
self.perf_monitor = performance_monitor.get_monitor()
self._perf_profiling_enabled = False
self._init_actions()
@@ -455,6 +455,8 @@ class AppController:
'_test_callback_func_write_to_file': self._test_callback_func_write_to_file,
'_set_env_var': lambda k, v: os.environ.update({k: v}),
'_apply_preset': self._apply_preset,
'_cb_save_preset': self._cb_save_preset,
'_cb_delete_preset': self._cb_delete_preset,
'_switch_project': self._switch_project,
'_refresh_from_project': self._refresh_from_project
}
@@ -1790,6 +1792,21 @@ class AppController:
if preset.max_output_tokens is not None:
self.max_tokens = preset.max_output_tokens
def _cb_save_preset(self, name, content, temp, top_p, max_tok, scope):
preset = models.Preset(
name=name,
system_prompt=content,
temperature=temp,
top_p=top_p,
max_output_tokens=max_tok
)
self.preset_manager.save_preset(preset, scope)
self.presets = self.preset_manager.load_all()
def _cb_delete_preset(self, name, scope):
self.preset_manager.delete_preset(name, scope)
self.presets = self.preset_manager.load_all()
def _cb_load_track(self, track_id: str) -> None:
state = project_manager.load_track_state(track_id, self.ui_files_base_dir)
if state:

View File

@@ -889,6 +889,9 @@ class App:
imgui.end_child()
imgui.same_line()
imgui.begin_child("preset_edit_area", imgui.ImVec2(500, 600), False)
p_name = self._editing_preset_name or "(New Preset)"
imgui.text_colored(C_IN, f"Editing Preset: {p_name}")
imgui.separator()
imgui.text("Name:")
_, self._editing_preset_name = imgui.input_text("##edit_name", self._editing_preset_name)
imgui.text("Scope:")
@@ -909,27 +912,27 @@ class App:
if imgui.button("Save", imgui.ImVec2(120, 0)):
if self._editing_preset_name.strip():
new_p = models.Preset(
name=self._editing_preset_name.strip(),
system_prompt=self._editing_preset_content,
temperature=self._editing_preset_temperature,
top_p=self._editing_preset_top_p,
max_output_tokens=self._editing_preset_max_output_tokens
self.controller._cb_save_preset(
self._editing_preset_name.strip(),
self._editing_preset_content,
self._editing_preset_temperature,
self._editing_preset_top_p,
self._editing_preset_max_output_tokens,
self._editing_preset_scope
)
self.controller.preset_manager.save_preset(new_p, self._editing_preset_scope)
self.controller.presets = self.controller.preset_manager.load_all()
self.ai_status = f"Preset '{new_p.name}' saved to {self._editing_preset_scope}"
self.ai_status = f"Preset '{self._editing_preset_name.strip()}' saved to {self._editing_preset_scope}"
imgui.set_item_tooltip("Save the current preset settings")
imgui.same_line()
if imgui.button("Delete", imgui.ImVec2(120, 0)):
if self._editing_preset_name.strip():
try:
self.controller.preset_manager.delete_preset(self._editing_preset_name.strip(), self._editing_preset_scope)
self.controller.presets = self.controller.preset_manager.load_all()
self.controller._cb_delete_preset(self._editing_preset_name.strip(), self._editing_preset_scope)
self.ai_status = f"Preset '{self._editing_preset_name}' deleted from {self._editing_preset_scope}"
self._editing_preset_name = ""
self._editing_preset_content = ""
except Exception as e:
self.ai_status = f"Error deleting: {e}"
imgui.set_item_tooltip("Delete the selected preset")
imgui.same_line()
if imgui.button("Close", imgui.ImVec2(120, 0)):
self.show_preset_manager_modal = False
@@ -2925,9 +2928,10 @@ def hello():
if is_sel:
imgui.set_item_default_focus()
imgui.end_combo()
imgui.same_line()
imgui.same_line(0, 8)
if imgui.button("Manage Presets##global"):
self.show_preset_manager_modal = True
imgui.set_item_tooltip("Open preset management modal")
ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100))
imgui.separator()
imgui.text("Project System Prompt")
@@ -2941,11 +2945,11 @@ def hello():
if is_sel:
imgui.set_item_default_focus()
imgui.end_combo()
imgui.same_line()
imgui.same_line(0, 8)
if imgui.button("Manage Presets##project"):
self.show_preset_manager_modal = True
imgui.set_item_tooltip("Open preset management modal")
ch, self.ui_project_system_prompt = imgui.input_text_multiline("##psp", self.ui_project_system_prompt, imgui.ImVec2(-1, 100))
def _render_theme_panel(self) -> None:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_theme_panel")
exp, opened = imgui.begin("Theme", self.show_windows["Theme"])

View File

@@ -1,3 +1,4 @@
import sys
import tomllib
import tomli_w
from pathlib import Path
@@ -21,24 +22,21 @@ class PresetManager:
presets: Dict[str, Preset] = {}
# Load global presets
if self.global_path.exists():
data_global = self._load_file(self.global_path)
for name, p_data in data_global.get("presets", {}).items():
try:
with open(self.global_path, "rb") as f:
data = tomllib.load(f)
for name, p_data in data.get("presets", {}).items():
presets[name] = Preset.from_dict(name, p_data)
except Exception:
pass
presets[name] = Preset.from_dict(name, p_data)
except Exception as e:
print(f"Error parsing global preset '{name}': {e}", file=sys.stderr)
# Load project presets (overwriting global ones if names conflict)
if self.project_path and self.project_path.exists():
try:
with open(self.project_path, "rb") as f:
data = tomllib.load(f)
for name, p_data in data.get("presets", {}).items():
presets[name] = Preset.from_dict(name, p_data)
except Exception:
pass
if self.project_path:
data_project = self._load_file(self.project_path)
for name, p_data in data_project.get("presets", {}).items():
try:
presets[name] = Preset.from_dict(name, p_data)
except Exception as e:
print(f"Error parsing project preset '{name}': {e}", file=sys.stderr)
return presets
@@ -75,8 +73,14 @@ class PresetManager:
return {"presets": {}}
try:
with open(path, "rb") as f:
return tomllib.load(f)
except Exception:
data = tomllib.load(f)
if not isinstance(data, dict):
return {"presets": {}}
if "presets" not in data:
data["presets"] = {}
return data
except Exception as e:
print(f"Error loading presets from {path}: {e}", file=sys.stderr)
return {"presets": {}}
def _save_file(self, path: Path, data: Dict[str, Any]) -> None: