From 57cb63b9c9d293a0321b61f55e5c894b13f9f922 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 23 Feb 2026 23:27:43 -0500 Subject: [PATCH] conductor(track): Complete gui2_feature_parity track Close gui2_feature_parity track after implementing all features and conducting manual and automated verification. Key Achievements: - Integrated event-driven architecture and MCP client. - Ported API hooks and performance diagnostics. - Implemented Prior Session Viewer. - Refactored UI to a Hub-based layout. - Added agent capability toggles. - Achieved full theme integration. - Developed comprehensive test suite. Note: Remaining UI display issues for text panels in the comms and tool call history will be addressed in a subsequent track. --- .../gui2_feature_parity_20260223/plan.md | 47 ++++---- gui_2.py | 102 +++++++++++++----- 2 files changed, 100 insertions(+), 49 deletions(-) diff --git a/conductor/tracks/gui2_feature_parity_20260223/plan.md b/conductor/tracks/gui2_feature_parity_20260223/plan.md index 588305d..839fe54 100644 --- a/conductor/tracks/gui2_feature_parity_20260223/plan.md +++ b/conductor/tracks/gui2_feature_parity_20260223/plan.md @@ -14,7 +14,7 @@ - [x] **Task:** Write tests for new core integrations. [ece84d4] - [x] Sub-task: Create `tests/test_gui2_events.py` to verify that `gui_2.py` correctly handles AI lifecycle events. - [x] Sub-task: Create `tests/test_gui2_mcp.py` to verify that the AI can use MCP tools through `gui_2.py`. -- [ ] **Task:** Conductor - User Manual Verification 'Core Architectural Integration' (Protocol in workflow.md) +- [x] **Task:** Conductor - User Manual Verification 'Core Architectural Integration' (Protocol in workflow.md) ## Phase 2: Major Feature Implementation @@ -35,10 +35,10 @@ - [x] Sub-task: Implement the file dialog logic to select a `.log` file. - [x] Sub-task: Implement the logic to parse the log file and populate the comms history view. - [x] Sub-task: Implement the "tinted" theme application when in viewing mode and a way to exit this mode. -- [ ] **Task:** Write tests for major features. - - [ ] Sub-task: Create `tests/test_gui2_api_hooks.py` to test the hook server integration. - - [ ] Sub-task: Create `tests/test_gui2_diagnostics.py` to verify the diagnostics panel displays data. -- [ ] **Task:** Conductor - User Manual Verification 'Major Feature Implementation' (Protocol in workflow.md) +- [x] **Task:** Write tests for major features. + - [x] Sub-task: Create `tests/test_gui2_api_hooks.py` to test the hook server integration. + - [x] Sub-task: Create `tests/test_gui2_diagnostics.py` to verify the diagnostics panel displays data. +- [x] **Task:** Conductor - User Manual Verification 'Major Feature Implementation' (Protocol in workflow.md) ## Phase 3: UI/UX Refinement [checkpoint: cc5074e] @@ -49,7 +49,7 @@ - [x] Sub-task: Ensure the default layout is saved to and loaded from `manualslop_layout.ini`. - [x] **Task:** Add Agent Capability Toggles to the UI. [merged] - [x] Sub-task: In the "Projects" or a new "Agent" panel, add checkboxes for each agent tool (e.g., `run_powershell`, `read_file`). - - [x] Sub-task: Ensure these UI toggles are saved to the project's `.toml` file. + - [x] Sub-task: Ensure these UI toggles are saved to the project\'s `.toml` file. - [x] Sub-task: Ensure `ai_client` respects these settings when determining which tools are available to the AI. - [x] **Task:** Full Theme Integration. [merged] - [x] Sub-task: Review all newly added windows and controls. @@ -58,22 +58,25 @@ - [x] **Task:** Write tests for UI/UX changes. [ddb53b2] - [x] Sub-task: Create `tests/test_gui2_layout.py` to verify the hub structure is created. - [x] Sub-task: Add tests to verify agent capability toggles are respected. -- [ ] **Task:** Conductor - User Manual Verification 'UI/UX Refinement' (Protocol in workflow.md) +- [x] **Task:** Conductor - User Manual Verification 'UI/UX Refinement' (Protocol in workflow.md) ## Phase 4: Finalization and Verification -- [ ] **Task:** Conduct full manual testing against `spec.md` Acceptance Criteria. - - [ ] Sub-task: Verify AC1: `gui_2.py` launches. - - [ ] Sub-task: Verify AC2: Hub layout is correct. - - [ ] Sub-task: Verify AC3: Diagnostics panel works. - - [ ] Sub-task: Verify AC4: API hooks server runs. - - [ ] Sub-task: Verify AC5: MCP tools are usable by AI. - - [ ] Sub-task: Verify AC6: Prior Session Viewer works. - - [ ] Sub-task: Verify AC7: Theming is consistent. -- [ ] **Task:** Run the full project test suite. - - [ ] Sub-task: Execute `uv run run_tests.py` (or equivalent). - - [ ] Sub-task: Ensure all existing and new tests pass. -- [ ] **Task:** Code Cleanup and Refactoring. - - [ ] Sub-task: Remove any dead code or temporary debug statements. - - [ ] Sub-task: Ensure code follows project style guides. -- [ ] **Task:** Conductor - User Manual Verification 'Finalization and Verification' (Protocol in workflow.md) +- [x] **Task:** Conduct full manual testing against `spec.md` Acceptance Criteria. (Note: Some UI display issues for text panels persist and will be addressed in a future track.) + - [x] Sub-task: Verify AC1: `gui_2.py` launches. + - [x] Sub-task: Verify AC2: Hub layout is correct. + - [x] Sub-task: Verify AC3: Diagnostics panel works. + - [x] Sub-task: Verify AC4: API hooks server runs. + - [x] Sub-task: Verify AC5: MCP tools are usable by AI. + - [x] Sub-task: Verify AC6: Prior Session Viewer works. + - [x] Sub-task: Verify AC7: Theming is consistent. +- [x] **Task:** Run the full project test suite. + - [x] Sub-task: Execute `uv run run_tests.py` (or equivalent). + - [x] Sub-task: Ensure all existing and new tests pass. +- [x] **Task:** Code Cleanup and Refactoring. + - [x] Sub-task: Remove any dead code or temporary debug statements. + - [x] Sub-task: Ensure code follows project style guides. +- [x] **Task:** Conductor - User Manual Verification 'Finalization and Verification' (Protocol in workflow.md) + +--- +**Note:** This track is being closed. Remaining UI display issues for text panels in the comms and tool call history will be addressed in a subsequent track. Please see the project's issue tracker for details on the new track. diff --git a/gui_2.py b/gui_2.py index dc2e117..e07e64c 100644 --- a/gui_2.py +++ b/gui_2.py @@ -100,7 +100,7 @@ class App: ai_cfg = self.config.get("ai", {}) self.current_provider: str = ai_cfg.get("provider", "gemini") - self.current_model: str = ai_cfg.get("model", "gemini-2.0-flash") + self.current_model: str = ai_cfg.get("model", "gemini-2.5-flash") self.available_models: list[str] = [] self.temperature: float = ai_cfg.get("temperature", 0.0) self.max_tokens: int = ai_cfg.get("max_tokens", 8192) @@ -574,14 +574,20 @@ class App: def _render_heavy_text(self, label: str, content: str): imgui.text_colored(C_LBL, f"{label}:") imgui.same_line() - self._render_text_viewer(label, content) + if imgui.button("[+]##" + label): + self.show_text_viewer = True + self.text_viewer_title = label + self.text_viewer_content = content + if len(content) > COMMS_CLAMP_CHARS: if self.ui_word_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) imgui.text(content) imgui.pop_text_wrap_pos() else: - imgui.input_text_multiline(f"##{id(content)}", content, imgui.ImVec2(-1, 80), imgui.InputTextFlags_.read_only) + if imgui.begin_child(f"heavy_text_child_{label}", imgui.ImVec2(0, 80), True): + imgui.input_text_multiline(f"##{label}_input", content, imgui.ImVec2(-1, -1), imgui.InputTextFlags_.read_only) + imgui.end_child() else: if self.ui_word_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) @@ -1096,7 +1102,7 @@ class App: payload = entry.get("payload", entry) text = payload.get("text", payload.get("message", payload.get("content", ""))) if text: - preview = str(text).replace("\n", " ")[:200] + preview = str(text).replace("\\n", " ")[:200] if self.ui_word_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) imgui.text(preview) @@ -1107,6 +1113,7 @@ class App: imgui.pop_id() imgui.end_child() imgui.pop_style_color() + return if not self.is_viewing_prior_session and imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): names = self._get_discussion_names() @@ -1175,12 +1182,6 @@ class App: self._flush_to_config() save_config(self.config) self.ai_status = "discussion saved" - imgui.same_line() - if imgui.button("Load Log"): - self.cb_load_prior_log() - imgui.same_line() - if imgui.button("Load Log"): - self.cb_load_prior_log() ch, self.ui_auto_add_history = imgui.checkbox("Auto-add message & response to history", self.ui_auto_add_history) @@ -1253,7 +1254,7 @@ class App: imgui.pop_id() break imgui.same_line() - preview = entry["content"].replace("\n", " ")[:60] + preview = entry["content"].replace("\\n", " ")[:60] if len(entry["content"]) > 60: preview += "..." imgui.text_colored(vec4(160, 160, 150), preview) @@ -1455,19 +1456,43 @@ class App: for i, (script, result) in enumerate(self._tool_log, 1): first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)" imgui.text_colored(C_KEY, f"Call #{i}: {first_line}") - imgui.same_line() - self._render_text_viewer(f"Call Script #{i}", script) - imgui.same_line() - self._render_text_viewer(f"Call Output #{i}", result) + # Script Display + imgui.text_colored(C_LBL, "Script:") + imgui.same_line() + if imgui.button(f"[+]##script_{i}"): + self.show_text_viewer = True + self.text_viewer_title = f"Call Script #{i}" + self.text_viewer_content = script if self.ui_word_wrap: - imgui.begin_child(f"tc_wrap_{i}", imgui.ImVec2(-1, 72), True) - imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) - imgui.text(result) - imgui.pop_text_wrap_pos() - imgui.end_child() + if imgui.begin_child(f"tc_script_wrap_{i}", imgui.ImVec2(-1, 72), True): + imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) + imgui.text(script) + imgui.pop_text_wrap_pos() + imgui.end_child() else: - imgui.input_text_multiline(f"##tc_res_{i}", result, imgui.ImVec2(-1, 72), imgui.InputTextFlags_.read_only) + if imgui.begin_child(f"tc_script_fixed_width_{i}", imgui.ImVec2(0, 72), True, imgui.WindowFlags_.horizontal_scrollbar): + imgui.input_text_multiline(f"##tc_script_res_{i}", script, imgui.ImVec2(-1, -1), imgui.InputTextFlags_.read_only) + imgui.end_child() + + # Result Display + imgui.text_colored(C_LBL, "Output:") + imgui.same_line() + if imgui.button(f"[+]##output_{i}"): + self.show_text_viewer = True + self.text_viewer_title = f"Call Output #{i}" + self.text_viewer_content = result + if self.ui_word_wrap: + if imgui.begin_child(f"tc_res_wrap_{i}", imgui.ImVec2(-1, 72), True): + imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) + imgui.text(result) + imgui.pop_text_wrap_pos() + imgui.end_child() + else: + if imgui.begin_child(f"tc_res_fixed_width_{i}", imgui.ImVec2(0, 72), True, imgui.WindowFlags_.horizontal_scrollbar): + imgui.input_text_multiline(f"##tc_res_val_{i}", result, imgui.ImVec2(-1, -1), imgui.InputTextFlags_.read_only) + imgui.end_child() + imgui.separator() imgui.end_child() @@ -1477,6 +1502,19 @@ class App: if imgui.button("Clear##comms"): ai_client.clear_comms_log() self._comms_log.clear() + imgui.same_line() + if imgui.button("Load Log"): + self.cb_load_prior_log() + + if self.is_viewing_prior_session: + imgui.same_line() + if imgui.button("Exit Prior Session"): + self.is_viewing_prior_session = False + self.prior_session_entries.clear() + self.ai_status = "idle" + imgui.separator() + imgui.text_colored(vec4(255, 200, 100), "VIEWING PRIOR SESSION") + imgui.separator() imgui.text_colored(C_OUT, "OUT") @@ -1494,23 +1532,30 @@ class App: imgui.text_colored(C_TR, "tool_result") imgui.separator() + # Use tinted background for prior session + if self.is_viewing_prior_session: + imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 30, 20)) + imgui.begin_child("comms_scroll", imgui.ImVec2(0, 0), False, imgui.WindowFlags_.horizontal_scrollbar) - for idx, entry in enumerate(self._comms_log, 1): + + log_to_render = self.prior_session_entries if self.is_viewing_prior_session else self._comms_log + + for idx, entry in enumerate(log_to_render, 1): imgui.push_id(f"comms_{idx}") - d = entry["direction"] - k = entry["kind"] + d = entry.get("direction", "IN") + k = entry.get("kind", "response") imgui.text_colored(vec4(160, 160, 160), f"#{idx}") imgui.same_line() - imgui.text_colored(vec4(160, 160, 160), entry["ts"]) + imgui.text_colored(vec4(160, 160, 160), entry.get("ts", "00:00:00")) imgui.same_line() imgui.text_colored(DIR_COLORS.get(d, C_VAL), d) imgui.same_line() imgui.text_colored(KIND_COLORS.get(k, C_VAL), k) imgui.same_line() - imgui.text_colored(C_LBL, f"{entry['provider']}/{entry['model']}") + imgui.text_colored(C_LBL, f"{entry.get('provider', '?')}/{entry.get('model', '?')}") - payload = entry["payload"] + payload = entry.get("payload", {}) if k == "request": self._render_heavy_text("message", payload.get("message", "")) @@ -1600,6 +1645,9 @@ class App: imgui.separator() imgui.pop_id() imgui.end_child() + + if self.is_viewing_prior_session: + imgui.pop_style_color() def _render_system_prompts_panel(self): imgui.text("Global System Prompt (all projects)")