refactor(gui): redesign persona modal as non-blocking window and embed sub-managers
This commit is contained in:
215
src/gui_2.py
215
src/gui_2.py
@@ -923,17 +923,7 @@ class App:
|
|||||||
imgui.close_current_popup()
|
imgui.close_current_popup()
|
||||||
imgui.end_popup()
|
imgui.end_popup()
|
||||||
|
|
||||||
def _render_preset_manager_window(self, is_embedded: bool = False) -> None:
|
def _render_preset_manager_content(self, is_embedded: bool = False) -> None:
|
||||||
if not self.show_preset_manager_window and not is_embedded: return
|
|
||||||
|
|
||||||
if not is_embedded:
|
|
||||||
imgui.set_next_window_size(imgui.ImVec2(800, 600), imgui.Cond_.first_use_ever)
|
|
||||||
opened, self.show_preset_manager_window = imgui.begin("Preset Manager", self.show_preset_manager_window)
|
|
||||||
if not opened:
|
|
||||||
imgui.end()
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
avail = imgui.get_content_region_avail()
|
avail = imgui.get_content_region_avail()
|
||||||
imgui.begin_child("preset_list_area", imgui.ImVec2(250, avail.y), True)
|
imgui.begin_child("preset_list_area", imgui.ImVec2(250, avail.y), True)
|
||||||
try:
|
try:
|
||||||
@@ -996,21 +986,24 @@ class App:
|
|||||||
self.show_preset_manager_window = False
|
self.show_preset_manager_window = False
|
||||||
finally:
|
finally:
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
finally:
|
|
||||||
if not is_embedded:
|
|
||||||
imgui.end()
|
|
||||||
|
|
||||||
def _render_tool_preset_manager_window(self, is_embedded: bool = False) -> None:
|
def _render_preset_manager_window(self, is_embedded: bool = False) -> None:
|
||||||
if not self.show_tool_preset_manager_window and not is_embedded: return
|
if not self.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(800, 600), imgui.Cond_.first_use_ever)
|
||||||
opened, self.show_tool_preset_manager_window = imgui.begin("Tool Preset Manager", self.show_tool_preset_manager_window)
|
opened, self.show_preset_manager_window = imgui.begin("Preset Manager", self.show_preset_manager_window)
|
||||||
if not opened:
|
if not opened:
|
||||||
imgui.end()
|
imgui.end()
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||||
|
finally:
|
||||||
|
if not is_embedded:
|
||||||
|
imgui.end()
|
||||||
|
|
||||||
|
def _render_tool_preset_manager_content(self, is_embedded: bool = False) -> None:
|
||||||
avail = imgui.get_content_region_avail()
|
avail = imgui.get_content_region_avail()
|
||||||
# Left Column: Listbox
|
# Left Column: Listbox
|
||||||
imgui.begin_child("tool_preset_list_area", imgui.ImVec2(250, avail.y), True)
|
imgui.begin_child("tool_preset_list_area", imgui.ImVec2(250, avail.y), True)
|
||||||
@@ -1238,6 +1231,19 @@ class App:
|
|||||||
self.show_tool_preset_manager_window = False
|
self.show_tool_preset_manager_window = False
|
||||||
finally:
|
finally:
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
|
|
||||||
|
def _render_tool_preset_manager_window(self, is_embedded: bool = False) -> None:
|
||||||
|
if not self.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)
|
||||||
|
opened, self.show_tool_preset_manager_window = imgui.begin("Tool Preset Manager", self.show_tool_preset_manager_window)
|
||||||
|
if not opened:
|
||||||
|
imgui.end()
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._render_tool_preset_manager_content(is_embedded=is_embedded)
|
||||||
finally:
|
finally:
|
||||||
if not is_embedded:
|
if not is_embedded:
|
||||||
imgui.end()
|
imgui.end()
|
||||||
@@ -1258,14 +1264,15 @@ class App:
|
|||||||
try:
|
try:
|
||||||
if imgui.button("New Persona", imgui.ImVec2(-1, 0)):
|
if imgui.button("New Persona", imgui.ImVec2(-1, 0)):
|
||||||
self._editing_persona_name = ""
|
self._editing_persona_name = ""
|
||||||
self._editing_persona_provider = self.current_provider
|
|
||||||
self._editing_persona_model = self.current_model
|
|
||||||
self._editing_persona_system_prompt = ""
|
self._editing_persona_system_prompt = ""
|
||||||
self._editing_persona_temperature = 0.7
|
|
||||||
self._editing_persona_max_tokens = 4096
|
|
||||||
self._editing_persona_tool_preset_id = ""
|
self._editing_persona_tool_preset_id = ""
|
||||||
self._editing_persona_bias_profile_id = ""
|
self._editing_persona_bias_profile_id = ""
|
||||||
self._editing_persona_preferred_models_list = []
|
self._editing_persona_preferred_models_list = [{
|
||||||
|
"provider": self.current_provider,
|
||||||
|
"model": self.current_model,
|
||||||
|
"temperature": 0.7,
|
||||||
|
"max_output_tokens": 4096
|
||||||
|
}]
|
||||||
self._editing_persona_scope = "project"
|
self._editing_persona_scope = "project"
|
||||||
self._editing_persona_is_new = True
|
self._editing_persona_is_new = True
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
@@ -1275,13 +1282,10 @@ class App:
|
|||||||
if imgui.selectable(name, is_sel)[0]:
|
if imgui.selectable(name, is_sel)[0]:
|
||||||
p = personas[name]
|
p = personas[name]
|
||||||
self._editing_persona_name = p.name
|
self._editing_persona_name = p.name
|
||||||
self._editing_persona_provider = p.provider or ""
|
|
||||||
self._editing_persona_model = p.model or ""
|
|
||||||
self._editing_persona_system_prompt = p.system_prompt or ""
|
self._editing_persona_system_prompt = p.system_prompt or ""
|
||||||
self._editing_persona_temperature = p.temperature if p.temperature is not None else 0.7
|
|
||||||
self._editing_persona_max_tokens = p.max_output_tokens if p.max_output_tokens is not None else 4096
|
|
||||||
self._editing_persona_tool_preset_id = p.tool_preset or ""
|
self._editing_persona_tool_preset_id = p.tool_preset or ""
|
||||||
self._editing_persona_bias_profile_id = p.bias_profile or ""
|
self._editing_persona_bias_profile_id = p.bias_profile or ""
|
||||||
|
import copy
|
||||||
self._editing_persona_preferred_models_list = copy.deepcopy(p.preferred_models) if p.preferred_models else []
|
self._editing_persona_preferred_models_list = copy.deepcopy(p.preferred_models) if p.preferred_models else []
|
||||||
self._editing_persona_scope = self.controller.persona_manager.get_persona_scope(p.name)
|
self._editing_persona_scope = self.controller.persona_manager.get_persona_scope(p.name)
|
||||||
self._editing_persona_is_new = False
|
self._editing_persona_is_new = False
|
||||||
@@ -1293,7 +1297,7 @@ class App:
|
|||||||
# Right Pane: Editor
|
# Right Pane: Editor
|
||||||
imgui.begin_child("persona_edit_area", imgui.ImVec2(0, avail.y), False)
|
imgui.begin_child("persona_edit_area", imgui.ImVec2(0, avail.y), False)
|
||||||
try:
|
try:
|
||||||
header = "New Persona" if self._editing_persona_is_new else f"Editing Persona: {self._editing_persona_name}"
|
header = "New Persona" if getattr(self, '_editing_persona_is_new', True) else f"Editing Persona: {self._editing_persona_name}"
|
||||||
imgui.text_colored(C_IN, header)
|
imgui.text_colored(C_IN, header)
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
@@ -1310,38 +1314,59 @@ class App:
|
|||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
|
|
||||||
imgui.text("Default Provider/Model (used if Preferred Models list is empty):")
|
imgui.text("Preferred Models:")
|
||||||
imgui.text("Provider:")
|
|
||||||
imgui.same_line()
|
|
||||||
providers = self.controller.PROVIDERS
|
providers = self.controller.PROVIDERS
|
||||||
p_idx = providers.index(self._editing_persona_provider) + 1 if self._editing_persona_provider in providers else 0
|
imgui.begin_child("pref_models_list", imgui.ImVec2(0, 150), True)
|
||||||
imgui.push_item_width(150)
|
to_remove = []
|
||||||
_, p_idx = imgui.combo("##pprov", p_idx, ["None"] + providers)
|
for i, entry in enumerate(self._editing_persona_preferred_models_list):
|
||||||
self._editing_persona_provider = providers[p_idx - 1] if p_idx > 0 else ""
|
imgui.push_id(f"pref_model_{i}")
|
||||||
imgui.pop_item_width()
|
imgui.text(f"{i+1}.")
|
||||||
|
imgui.same_line()
|
||||||
|
|
||||||
|
imgui.set_next_item_width(120)
|
||||||
|
prov = entry.get("provider", "")
|
||||||
|
p_idx = providers.index(prov) + 1 if prov in providers else 0
|
||||||
|
changed_p, p_idx = imgui.combo("##prov", p_idx, ["None"] + providers)
|
||||||
|
if changed_p:
|
||||||
|
entry["provider"] = providers[p_idx-1] if p_idx > 0 else ""
|
||||||
|
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
imgui.text("Model:")
|
imgui.set_next_item_width(200)
|
||||||
imgui.same_line()
|
curr_prov = entry.get("provider", "")
|
||||||
all_models = self.controller.all_available_models.get(self._editing_persona_provider, [])
|
m_list = self.controller.all_available_models.get(curr_prov, [])
|
||||||
if not all_models and self._editing_persona_model:
|
model = entry.get("model", "")
|
||||||
all_models = [self._editing_persona_model]
|
m_idx = m_list.index(model) + 1 if model in m_list else 0
|
||||||
m_idx = all_models.index(self._editing_persona_model) + 1 if self._editing_persona_model in all_models else 0
|
changed_m, m_idx = imgui.combo("##model", m_idx, ["None"] + m_list)
|
||||||
imgui.push_item_width(200)
|
if changed_m:
|
||||||
_, m_idx = imgui.combo("##pmodel", m_idx, ["None"] + all_models)
|
entry["model"] = m_list[m_idx-1] if m_idx > 0 else ""
|
||||||
self._editing_persona_model = all_models[m_idx - 1] if m_idx > 0 else ""
|
|
||||||
imgui.pop_item_width()
|
|
||||||
|
|
||||||
imgui.text("Temp:")
|
|
||||||
imgui.same_line()
|
|
||||||
imgui.set_next_item_width(100)
|
|
||||||
_, self._editing_persona_temperature = imgui.slider_float("##ptemp", self._editing_persona_temperature, 0.0, 2.0)
|
|
||||||
|
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
imgui.text("Max Tok:")
|
imgui.text("T:")
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
imgui.set_next_item_width(100)
|
imgui.set_next_item_width(60)
|
||||||
_, self._editing_persona_max_tokens = imgui.input_int("##pmaxt", self._editing_persona_max_tokens)
|
_, entry["temperature"] = imgui.input_float("##temp", entry.get("temperature", 0.7), 0.1, 0.1, "%.1f")
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.text("Max:")
|
||||||
|
imgui.same_line()
|
||||||
|
imgui.set_next_item_width(80)
|
||||||
|
_, entry["max_output_tokens"] = imgui.input_int("##maxt", entry.get("max_output_tokens", 4096))
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("x"):
|
||||||
|
to_remove.append(i)
|
||||||
|
imgui.pop_id()
|
||||||
|
for i in reversed(to_remove):
|
||||||
|
self._editing_persona_preferred_models_list.pop(i)
|
||||||
|
imgui.end_child()
|
||||||
|
|
||||||
|
if imgui.button("Add Preferred Model"):
|
||||||
|
self._editing_persona_preferred_models_list.append({
|
||||||
|
"provider": self.current_provider,
|
||||||
|
"model": self.current_model,
|
||||||
|
"temperature": 0.7,
|
||||||
|
"max_output_tokens": 4096
|
||||||
|
})
|
||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
imgui.text("Tool Preset:")
|
imgui.text("Tool Preset:")
|
||||||
@@ -1363,68 +1388,14 @@ class App:
|
|||||||
self._editing_persona_bias_profile_id = bias_names[b_idx] if b_idx > 0 else ""
|
self._editing_persona_bias_profile_id = bias_names[b_idx] if b_idx > 0 else ""
|
||||||
imgui.pop_item_width()
|
imgui.pop_item_width()
|
||||||
|
|
||||||
imgui.separator()
|
if imgui.collapsing_header("Manage Tool Presets & Biases"):
|
||||||
imgui.text("Preferred Models List:")
|
imgui.begin_child("tool_preset_embedded", imgui.ImVec2(0, 300), True)
|
||||||
imgui.begin_child("pref_models_list", imgui.ImVec2(0, 200), True)
|
self._render_tool_preset_manager_content(is_embedded=True)
|
||||||
to_remove = []
|
|
||||||
for i, entry in enumerate(self._editing_persona_preferred_models_list):
|
|
||||||
imgui.push_id(f"pref_model_{i}")
|
|
||||||
imgui.text(f"{i+1}.")
|
|
||||||
imgui.same_line()
|
|
||||||
|
|
||||||
# Provider
|
|
||||||
imgui.set_next_item_width(120)
|
|
||||||
prov = entry.get("provider", "")
|
|
||||||
p_idx = providers.index(prov) + 1 if prov in providers else 0
|
|
||||||
changed_p, p_idx = imgui.combo("##prov", p_idx, ["None"] + providers)
|
|
||||||
if changed_p:
|
|
||||||
entry["provider"] = providers[p_idx-1] if p_idx > 0 else ""
|
|
||||||
|
|
||||||
imgui.same_line()
|
|
||||||
# Model
|
|
||||||
imgui.set_next_item_width(200)
|
|
||||||
curr_prov = entry.get("provider", "")
|
|
||||||
m_list = self.controller.all_available_models.get(curr_prov, [])
|
|
||||||
model = entry.get("model", "")
|
|
||||||
m_idx = m_list.index(model) + 1 if model in m_list else 0
|
|
||||||
changed_m, m_idx = imgui.combo("##model", m_idx, ["None"] + m_list)
|
|
||||||
if changed_m:
|
|
||||||
entry["model"] = m_list[m_idx-1] if m_idx > 0 else ""
|
|
||||||
|
|
||||||
imgui.same_line()
|
|
||||||
imgui.text("T:")
|
|
||||||
imgui.same_line()
|
|
||||||
# Temp
|
|
||||||
imgui.set_next_item_width(60)
|
|
||||||
_, entry["temperature"] = imgui.input_float("##temp", entry.get("temperature", 0.7), 0.1, 0.1, "%.1f")
|
|
||||||
|
|
||||||
imgui.same_line()
|
|
||||||
imgui.text("M:")
|
|
||||||
imgui.same_line()
|
|
||||||
# MaxTok
|
|
||||||
imgui.set_next_item_width(80)
|
|
||||||
_, entry["max_output_tokens"] = imgui.input_int("##maxt", entry.get("max_output_tokens", 4096))
|
|
||||||
|
|
||||||
imgui.same_line()
|
|
||||||
if imgui.button("x"):
|
|
||||||
to_remove.append(i)
|
|
||||||
imgui.pop_id()
|
|
||||||
for i in reversed(to_remove):
|
|
||||||
self._editing_persona_preferred_models_list.pop(i)
|
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
|
|
||||||
if imgui.button("Add Preferred Model"):
|
|
||||||
self._editing_persona_preferred_models_list.append({
|
|
||||||
"provider": self._editing_persona_provider or self.current_provider,
|
|
||||||
"model": self._editing_persona_model or self.current_model,
|
|
||||||
"temperature": self._editing_persona_temperature,
|
|
||||||
"max_output_tokens": self._editing_persona_max_tokens
|
|
||||||
})
|
|
||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
imgui.text("System Prompt:")
|
imgui.text("System Prompt:")
|
||||||
|
|
||||||
# Load Prompt Preset
|
|
||||||
imgui.text("Load from Preset:")
|
imgui.text("Load from Preset:")
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
prompt_presets = ["Select..."] + sorted(self.controller.presets.keys())
|
prompt_presets = ["Select..."] + sorted(self.controller.presets.keys())
|
||||||
@@ -1439,27 +1410,21 @@ class App:
|
|||||||
if pname in self.controller.presets:
|
if pname in self.controller.presets:
|
||||||
p = self.controller.presets[pname]
|
p = self.controller.presets[pname]
|
||||||
self._editing_persona_system_prompt = p.system_prompt
|
self._editing_persona_system_prompt = p.system_prompt
|
||||||
if p.temperature is not None: self._editing_persona_temperature = p.temperature
|
|
||||||
if p.max_output_tokens is not None: self._editing_persona_max_tokens = p.max_output_tokens
|
|
||||||
self._load_preset_idx = 0
|
self._load_preset_idx = 0
|
||||||
|
|
||||||
|
if imgui.collapsing_header("Manage Prompt Presets"):
|
||||||
|
imgui.begin_child("prompt_preset_embedded", imgui.ImVec2(0, 200), True)
|
||||||
|
self._render_preset_manager_content(is_embedded=True)
|
||||||
|
imgui.end_child()
|
||||||
|
|
||||||
_, self._editing_persona_system_prompt = imgui.input_text_multiline("##pprompt", self._editing_persona_system_prompt, imgui.ImVec2(-1, 150))
|
_, self._editing_persona_system_prompt = imgui.input_text_multiline("##pprompt", self._editing_persona_system_prompt, imgui.ImVec2(-1, 150))
|
||||||
|
|
||||||
imgui.separator()
|
imgui.separator()
|
||||||
if imgui.button("Save Persona", imgui.ImVec2(120, 0)):
|
if imgui.button("Save Persona", imgui.ImVec2(120, 0)):
|
||||||
if self._editing_persona_name.strip():
|
if self._editing_persona_name.strip():
|
||||||
try:
|
try:
|
||||||
# If preferred list is empty, maybe we should add the default one?
|
import copy
|
||||||
# The models.Persona properties already handle returning None/default if list is empty.
|
|
||||||
# But for saving, we should probably ensure the list isn't empty if we have values.
|
|
||||||
save_models = copy.deepcopy(self._editing_persona_preferred_models_list)
|
save_models = copy.deepcopy(self._editing_persona_preferred_models_list)
|
||||||
if not save_models and self._editing_persona_model:
|
|
||||||
save_models.append({
|
|
||||||
"provider": self._editing_persona_provider,
|
|
||||||
"model": self._editing_persona_model,
|
|
||||||
"temperature": self._editing_persona_temperature,
|
|
||||||
"max_output_tokens": self._editing_persona_max_tokens
|
|
||||||
})
|
|
||||||
|
|
||||||
persona = models.Persona(
|
persona = models.Persona(
|
||||||
name=self._editing_persona_name.strip(),
|
name=self._editing_persona_name.strip(),
|
||||||
@@ -1479,7 +1444,7 @@ class App:
|
|||||||
|
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
if imgui.button("Delete", imgui.ImVec2(100, 0)):
|
if imgui.button("Delete", imgui.ImVec2(100, 0)):
|
||||||
if not self._editing_persona_is_new and self._editing_persona_name:
|
if not getattr(self, '_editing_persona_is_new', True) and self._editing_persona_name:
|
||||||
self.controller._cb_delete_persona(self._editing_persona_name, self._editing_persona_scope)
|
self.controller._cb_delete_persona(self._editing_persona_name, self._editing_persona_scope)
|
||||||
self.ai_status = f"Deleted Persona: {self._editing_persona_name}"
|
self.ai_status = f"Deleted Persona: {self._editing_persona_name}"
|
||||||
self._editing_persona_name = ""
|
self._editing_persona_name = ""
|
||||||
@@ -1494,8 +1459,6 @@ class App:
|
|||||||
finally:
|
finally:
|
||||||
if not is_embedded:
|
if not is_embedded:
|
||||||
imgui.end()
|
imgui.end()
|
||||||
|
|
||||||
|
|
||||||
def _render_projects_panel(self) -> None:
|
def _render_projects_panel(self) -> None:
|
||||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_projects_panel")
|
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_projects_panel")
|
||||||
proj_name = self.project.get("project", {}).get("name", Path(self.active_project_path).stem)
|
proj_name = self.project.get("project", {}).get("name", Path(self.active_project_path).stem)
|
||||||
|
|||||||
Reference in New Issue
Block a user