feat(bias): implement GUI integration for tool weights and bias profiles
This commit is contained in:
@@ -857,9 +857,12 @@ class AppController:
|
||||
self.preset_manager = presets.PresetManager(Path(self.active_project_path).parent if self.active_project_path else None)
|
||||
self.presets = self.preset_manager.load_all()
|
||||
self.tool_preset_manager = tool_presets.ToolPresetManager(Path(self.active_project_path).parent if self.active_project_path else None)
|
||||
self.tool_presets = self.tool_preset_manager.load_all()
|
||||
self.ui_active_tool_preset = os.environ.get('SLOP_TOOL_PRESET')
|
||||
self.tool_presets = self.tool_preset_manager.load_all_presets()
|
||||
self.bias_profiles = self.tool_preset_manager.load_all_bias_profiles()
|
||||
self.ui_active_tool_preset = os.environ.get('SLOP_TOOL_PRESET') or ai_cfg.get("active_tool_preset")
|
||||
self.ui_active_bias_profile = ai_cfg.get("active_bias_profile")
|
||||
ai_client.set_tool_preset(self.ui_active_tool_preset)
|
||||
ai_client.set_bias_profile(self.ui_active_bias_profile)
|
||||
self.ui_global_preset_name = ai_cfg.get("active_preset")
|
||||
self.ui_project_preset_name = proj_meta.get("active_preset")
|
||||
|
||||
@@ -1819,7 +1822,8 @@ class AppController:
|
||||
self.preset_manager.project_root = Path(self.ui_files_base_dir)
|
||||
self.presets = self.preset_manager.load_all()
|
||||
self.tool_preset_manager.project_root = Path(self.ui_files_base_dir)
|
||||
self.tool_presets = self.tool_preset_manager.load_all()
|
||||
self.tool_presets = self.tool_preset_manager.load_all_presets()
|
||||
self.bias_profiles = self.tool_preset_manager.load_all_bias_profiles()
|
||||
|
||||
def _apply_preset(self, name: str, scope: str) -> None:
|
||||
if name == "None":
|
||||
@@ -1862,11 +1866,19 @@ class AppController:
|
||||
def _cb_save_tool_preset(self, name, categories, scope):
|
||||
preset = models.ToolPreset(name=name, categories=categories)
|
||||
self.tool_preset_manager.save_preset(preset, scope)
|
||||
self.tool_presets = self.tool_preset_manager.load_all()
|
||||
self.tool_presets = self.tool_preset_manager.load_all_presets()
|
||||
|
||||
def _cb_delete_tool_preset(self, name, scope):
|
||||
self.tool_preset_manager.delete_preset(name, scope)
|
||||
self.tool_presets = self.tool_preset_manager.load_all()
|
||||
self.tool_presets = self.tool_preset_manager.load_all_presets()
|
||||
|
||||
def _cb_save_bias_profile(self, profile: models.BiasProfile, scope: str = "project"):
|
||||
self.tool_preset_manager.save_bias_profile(profile, scope)
|
||||
self.bias_profiles = self.tool_preset_manager.load_all_bias_profiles()
|
||||
|
||||
def _cb_delete_bias_profile(self, name: str, scope: str = "project"):
|
||||
self.tool_preset_manager.delete_bias_profile(name, scope)
|
||||
self.bias_profiles = self.tool_preset_manager.load_all_bias_profiles()
|
||||
|
||||
def _cb_load_track(self, track_id: str) -> None:
|
||||
state = project_manager.load_track_state(track_id, self.ui_files_base_dir)
|
||||
|
||||
153
src/gui_2.py
153
src/gui_2.py
@@ -99,10 +99,19 @@ class App:
|
||||
self.show_preset_manager_modal = False
|
||||
self.show_tool_preset_manager_modal = False
|
||||
self.ui_active_tool_preset = ""
|
||||
self.ui_active_bias_profile = ""
|
||||
self._editing_bias_profile_name = ""
|
||||
self._editing_bias_profile_tool_weights = "" # JSON
|
||||
self._editing_bias_profile_cat_mults = "" # JSON
|
||||
self._editing_bias_profile_scope = "project"
|
||||
self._editing_tool_preset_name = ''
|
||||
self._editing_tool_preset_categories = {}
|
||||
self._editing_tool_preset_scope = 'project'
|
||||
self._selected_tool_preset_idx = -1
|
||||
self._editing_bias_profile_name = ""
|
||||
self._editing_bias_profile_tool_weights = "{}"
|
||||
self._editing_bias_profile_category_multipliers = "{}"
|
||||
self._selected_bias_profile_idx = -1
|
||||
self._editing_preset_name = ""
|
||||
self._editing_preset_content = ""
|
||||
self._editing_preset_temperature = 0.0
|
||||
@@ -1040,39 +1049,101 @@ class App:
|
||||
imgui.dummy(imgui.ImVec2(0, 8))
|
||||
|
||||
imgui.text("Categories & Tools:")
|
||||
imgui.begin_child("tp_categories_scroll", imgui.ImVec2(0, -40), True)
|
||||
imgui.begin_child("tp_categories_scroll", imgui.ImVec2(0, 300), True)
|
||||
try:
|
||||
for cat_name, default_tools in models.DEFAULT_TOOL_CATEGORIES.items():
|
||||
if imgui.tree_node(cat_name):
|
||||
if cat_name not in self._editing_tool_preset_categories:
|
||||
self._editing_tool_preset_categories[cat_name] = {}
|
||||
current_cat_tools = self._editing_tool_preset_categories[cat_name]
|
||||
self._editing_tool_preset_categories[cat_name] = []
|
||||
current_cat_tools = self._editing_tool_preset_categories[cat_name] # List of Tool
|
||||
|
||||
for tool_name in default_tools:
|
||||
# Determine current mode: disabled (not present), auto, or ask
|
||||
if tool_name not in current_cat_tools:
|
||||
mode = "disabled"
|
||||
else:
|
||||
config = current_cat_tools[tool_name]
|
||||
if isinstance(config, dict):
|
||||
mode = config.get("mode", "auto")
|
||||
else:
|
||||
mode = str(config)
|
||||
# Find existing Tool object in list
|
||||
tool = next((t for t in current_cat_tools if t.name == tool_name), None)
|
||||
mode = "disabled" if tool is None else tool.approval
|
||||
|
||||
if imgui.radio_button(f"Disabled##{cat_name}_{tool_name}", mode == "disabled"):
|
||||
if tool_name in current_cat_tools:
|
||||
del current_cat_tools[tool_name]
|
||||
if imgui.radio_button(f"Off##{cat_name}_{tool_name}", mode == "disabled"):
|
||||
if tool: current_cat_tools.remove(tool)
|
||||
imgui.same_line()
|
||||
if imgui.radio_button(f"Auto##{cat_name}_{tool_name}", mode == "auto"):
|
||||
current_cat_tools[tool_name] = "auto"
|
||||
if not tool:
|
||||
tool = models.Tool(name=tool_name, approval="auto")
|
||||
current_cat_tools.append(tool)
|
||||
else:
|
||||
tool.approval = "auto"
|
||||
imgui.same_line()
|
||||
if imgui.radio_button(f"Ask##{cat_name}_{tool_name}", mode == "ask"):
|
||||
current_cat_tools[tool_name] = "ask"
|
||||
if not tool:
|
||||
tool = models.Tool(name=tool_name, approval="ask")
|
||||
current_cat_tools.append(tool)
|
||||
else:
|
||||
tool.approval = "ask"
|
||||
imgui.same_line()
|
||||
imgui.text(tool_name)
|
||||
|
||||
if tool:
|
||||
imgui.same_line(250)
|
||||
imgui.set_next_item_width(100)
|
||||
_, tool.weight = imgui.slider_int(f"Weight##{cat_name}_{tool_name}", tool.weight, 1, 5)
|
||||
imgui.same_line()
|
||||
pb_str = json.dumps(tool.parameter_bias)
|
||||
imgui.set_next_item_width(150)
|
||||
ch_pb, pb_new = imgui.input_text(f"Params##{cat_name}_{tool_name}", pb_str)
|
||||
if ch_pb:
|
||||
try: tool.parameter_bias = json.loads(pb_new)
|
||||
except: pass
|
||||
imgui.tree_pop()
|
||||
finally:
|
||||
imgui.end_child()
|
||||
|
||||
imgui.separator()
|
||||
imgui.text_colored(C_SUB, "Bias Profiles")
|
||||
imgui.begin_child("bias_profiles_area", imgui.ImVec2(0, 200), True)
|
||||
try:
|
||||
avail_bias = imgui.get_content_region_avail()
|
||||
imgui.begin_child("bias_list", imgui.ImVec2(200, avail_bias.y), False)
|
||||
if imgui.button("New Profile", imgui.ImVec2(-1, 0)):
|
||||
self._editing_bias_profile_name = ""
|
||||
self._editing_bias_profile_tool_weights = "{}"
|
||||
self._editing_bias_profile_category_multipliers = "{}"
|
||||
self._selected_bias_profile_idx = -1
|
||||
imgui.separator()
|
||||
bnames = sorted(self.bias_profiles.keys())
|
||||
for i, bname in enumerate(bnames):
|
||||
is_sel = (self._selected_bias_profile_idx == i)
|
||||
if imgui.selectable(bname, is_sel)[0]:
|
||||
self._selected_bias_profile_idx = i
|
||||
self._editing_bias_profile_name = bname
|
||||
profile = self.bias_profiles[bname]
|
||||
self._editing_bias_profile_tool_weights = json.dumps(profile.tool_weights, indent=1)
|
||||
self._editing_bias_profile_category_multipliers = json.dumps(profile.category_multipliers, indent=1)
|
||||
imgui.end_child()
|
||||
imgui.same_line()
|
||||
imgui.begin_child("bias_edit", imgui.ImVec2(0, avail_bias.y), False)
|
||||
imgui.text("Name:")
|
||||
_, self._editing_bias_profile_name = imgui.input_text("##b_name", self._editing_bias_profile_name)
|
||||
imgui.text("Tool Weights (JSON):")
|
||||
_, self._editing_bias_profile_tool_weights = imgui.input_text_multiline("##b_tw", self._editing_bias_profile_tool_weights, imgui.ImVec2(-1, 60))
|
||||
imgui.text("Category Multipliers (JSON):")
|
||||
_, self._editing_bias_profile_category_multipliers = imgui.input_text_multiline("##b_cm", self._editing_bias_profile_category_multipliers, imgui.ImVec2(-1, 60))
|
||||
|
||||
if imgui.button("Save Profile"):
|
||||
try:
|
||||
tw = json.loads(self._editing_bias_profile_tool_weights)
|
||||
cm = json.loads(self._editing_bias_profile_category_multipliers)
|
||||
prof = models.BiasProfile(name=self._editing_bias_profile_name, tool_weights=tw, category_multipliers=cm)
|
||||
self.controller._cb_save_bias_profile(prof, self._editing_tool_preset_scope)
|
||||
self.ai_status = f"Bias profile '{prof.name}' saved"
|
||||
except Exception as e:
|
||||
self.ai_status = f"Error: {e}"
|
||||
imgui.same_line()
|
||||
if imgui.button("Delete Profile"):
|
||||
self.controller._cb_delete_bias_profile(self._editing_bias_profile_name, self._editing_tool_preset_scope)
|
||||
self.ai_status = f"Bias profile deleted"
|
||||
imgui.end_child()
|
||||
finally:
|
||||
imgui.end_child()
|
||||
|
||||
imgui.dummy(imgui.ImVec2(0, 8))
|
||||
if imgui.button("Save", imgui.ImVec2(100, 0)):
|
||||
if self._editing_tool_preset_name.strip():
|
||||
@@ -1897,6 +1968,16 @@ def hello():
|
||||
ch, self.temperature = imgui.slider_float("Temperature", self.temperature, 0.0, 2.0, "%.2f")
|
||||
ch, self.max_tokens = imgui.input_int("Max Tokens (Output)", self.max_tokens, 1024)
|
||||
ch, self.history_trunc_limit = imgui.input_int("History Truncation Limit", self.history_trunc_limit, 1024)
|
||||
imgui.text("Bias Profile")
|
||||
if imgui.begin_combo("##bias", self.ui_active_bias_profile or "None"):
|
||||
if imgui.selectable("None", not self.ui_active_bias_profile)[0]:
|
||||
self.ui_active_bias_profile = ""
|
||||
ai_client.set_bias_profile(None)
|
||||
for bname in sorted(self.bias_profiles.keys()):
|
||||
if imgui.selectable(bname, bname == self.ui_active_bias_profile)[0]:
|
||||
self.ui_active_bias_profile = bname
|
||||
ai_client.set_bias_profile(bname)
|
||||
imgui.end_combo()
|
||||
if self.current_provider == "gemini_cli":
|
||||
imgui.separator()
|
||||
imgui.text("Gemini CLI")
|
||||
@@ -3210,27 +3291,29 @@ def hello():
|
||||
preset = presets[active_name]
|
||||
for cat_name, tools in preset.categories.items():
|
||||
if imgui.tree_node(cat_name):
|
||||
for t_name, t_cfg in tools.items():
|
||||
imgui.text(t_name)
|
||||
imgui.same_line(150)
|
||||
for tool in tools:
|
||||
if tool.weight >= 5:
|
||||
imgui.text_colored(vec4(255, 100, 100), "[HIGH]")
|
||||
imgui.same_line()
|
||||
elif tool.weight == 4:
|
||||
imgui.text_colored(vec4(255, 255, 100), "[PREF]")
|
||||
imgui.same_line()
|
||||
elif tool.weight == 2:
|
||||
imgui.text_colored(vec4(255, 150, 50), "[REJECT]")
|
||||
imgui.same_line()
|
||||
elif tool.weight <= 1:
|
||||
imgui.text_colored(vec4(180, 180, 180), "[LOW]")
|
||||
imgui.same_line()
|
||||
|
||||
# Determine current mode
|
||||
if isinstance(t_cfg, dict):
|
||||
mode = t_cfg.get("mode", "auto")
|
||||
else:
|
||||
mode = str(t_cfg)
|
||||
imgui.text(tool.name)
|
||||
imgui.same_line(180)
|
||||
|
||||
if imgui.radio_button(f"Auto##{cat_name}_{t_name}", mode == "auto"):
|
||||
if isinstance(t_cfg, dict):
|
||||
t_cfg["mode"] = "auto"
|
||||
else:
|
||||
preset.categories[cat_name][t_name] = "auto"
|
||||
mode = tool.approval
|
||||
if imgui.radio_button(f"Auto##{cat_name}_{tool.name}", mode == "auto"):
|
||||
tool.approval = "auto"
|
||||
imgui.same_line()
|
||||
if imgui.radio_button(f"Ask##{cat_name}_{t_name}", mode == "ask"):
|
||||
if isinstance(t_cfg, dict):
|
||||
t_cfg["mode"] = "ask"
|
||||
else:
|
||||
preset.categories[cat_name][t_name] = "ask"
|
||||
if imgui.radio_button(f"Ask##{cat_name}_{tool.name}", mode == "ask"):
|
||||
tool.approval = "ask"
|
||||
imgui.tree_pop()
|
||||
|
||||
def _render_theme_panel(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user