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.
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
- [x] **Task:** Write tests for new core integrations. [ece84d4]
|
- [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_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`.
|
- [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
|
## 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 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 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.
|
- [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.
|
- [x] **Task:** Write tests for major features.
|
||||||
- [ ] Sub-task: Create `tests/test_gui2_api_hooks.py` to test the hook server integration.
|
- [x] 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.
|
- [x] 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:** Conductor - User Manual Verification 'Major Feature Implementation' (Protocol in workflow.md)
|
||||||
|
|
||||||
## Phase 3: UI/UX Refinement [checkpoint: cc5074e]
|
## 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] 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] **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: 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] Sub-task: Ensure `ai_client` respects these settings when determining which tools are available to the AI.
|
||||||
- [x] **Task:** Full Theme Integration. [merged]
|
- [x] **Task:** Full Theme Integration. [merged]
|
||||||
- [x] Sub-task: Review all newly added windows and controls.
|
- [x] Sub-task: Review all newly added windows and controls.
|
||||||
@@ -58,22 +58,25 @@
|
|||||||
- [x] **Task:** Write tests for UI/UX changes. [ddb53b2]
|
- [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: 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.
|
- [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
|
## Phase 4: Finalization and Verification
|
||||||
|
|
||||||
- [ ] **Task:** Conduct full manual testing against `spec.md` Acceptance Criteria.
|
- [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.)
|
||||||
- [ ] Sub-task: Verify AC1: `gui_2.py` launches.
|
- [x] Sub-task: Verify AC1: `gui_2.py` launches.
|
||||||
- [ ] Sub-task: Verify AC2: Hub layout is correct.
|
- [x] Sub-task: Verify AC2: Hub layout is correct.
|
||||||
- [ ] Sub-task: Verify AC3: Diagnostics panel works.
|
- [x] Sub-task: Verify AC3: Diagnostics panel works.
|
||||||
- [ ] Sub-task: Verify AC4: API hooks server runs.
|
- [x] Sub-task: Verify AC4: API hooks server runs.
|
||||||
- [ ] Sub-task: Verify AC5: MCP tools are usable by AI.
|
- [x] Sub-task: Verify AC5: MCP tools are usable by AI.
|
||||||
- [ ] Sub-task: Verify AC6: Prior Session Viewer works.
|
- [x] Sub-task: Verify AC6: Prior Session Viewer works.
|
||||||
- [ ] Sub-task: Verify AC7: Theming is consistent.
|
- [x] Sub-task: Verify AC7: Theming is consistent.
|
||||||
- [ ] **Task:** Run the full project test suite.
|
- [x] **Task:** Run the full project test suite.
|
||||||
- [ ] Sub-task: Execute `uv run run_tests.py` (or equivalent).
|
- [x] Sub-task: Execute `uv run run_tests.py` (or equivalent).
|
||||||
- [ ] Sub-task: Ensure all existing and new tests pass.
|
- [x] Sub-task: Ensure all existing and new tests pass.
|
||||||
- [ ] **Task:** Code Cleanup and Refactoring.
|
- [x] **Task:** Code Cleanup and Refactoring.
|
||||||
- [ ] Sub-task: Remove any dead code or temporary debug statements.
|
- [x] Sub-task: Remove any dead code or temporary debug statements.
|
||||||
- [ ] Sub-task: Ensure code follows project style guides.
|
- [x] Sub-task: Ensure code follows project style guides.
|
||||||
- [ ] **Task:** Conductor - User Manual Verification 'Finalization and Verification' (Protocol in workflow.md)
|
- [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.
|
||||||
|
|||||||
94
gui_2.py
94
gui_2.py
@@ -100,7 +100,7 @@ class App:
|
|||||||
|
|
||||||
ai_cfg = self.config.get("ai", {})
|
ai_cfg = self.config.get("ai", {})
|
||||||
self.current_provider: str = ai_cfg.get("provider", "gemini")
|
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.available_models: list[str] = []
|
||||||
self.temperature: float = ai_cfg.get("temperature", 0.0)
|
self.temperature: float = ai_cfg.get("temperature", 0.0)
|
||||||
self.max_tokens: int = ai_cfg.get("max_tokens", 8192)
|
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):
|
def _render_heavy_text(self, label: str, content: str):
|
||||||
imgui.text_colored(C_LBL, f"{label}:")
|
imgui.text_colored(C_LBL, f"{label}:")
|
||||||
imgui.same_line()
|
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 len(content) > COMMS_CLAMP_CHARS:
|
||||||
if self.ui_word_wrap:
|
if self.ui_word_wrap:
|
||||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||||
imgui.text(content)
|
imgui.text(content)
|
||||||
imgui.pop_text_wrap_pos()
|
imgui.pop_text_wrap_pos()
|
||||||
else:
|
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:
|
else:
|
||||||
if self.ui_word_wrap:
|
if self.ui_word_wrap:
|
||||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||||
@@ -1096,7 +1102,7 @@ class App:
|
|||||||
payload = entry.get("payload", entry)
|
payload = entry.get("payload", entry)
|
||||||
text = payload.get("text", payload.get("message", payload.get("content", "")))
|
text = payload.get("text", payload.get("message", payload.get("content", "")))
|
||||||
if text:
|
if text:
|
||||||
preview = str(text).replace("\n", " ")[:200]
|
preview = str(text).replace("\\n", " ")[:200]
|
||||||
if self.ui_word_wrap:
|
if self.ui_word_wrap:
|
||||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||||
imgui.text(preview)
|
imgui.text(preview)
|
||||||
@@ -1107,6 +1113,7 @@ class App:
|
|||||||
imgui.pop_id()
|
imgui.pop_id()
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
imgui.pop_style_color()
|
imgui.pop_style_color()
|
||||||
|
return
|
||||||
|
|
||||||
if not self.is_viewing_prior_session and imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open):
|
if not self.is_viewing_prior_session and imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open):
|
||||||
names = self._get_discussion_names()
|
names = self._get_discussion_names()
|
||||||
@@ -1175,12 +1182,6 @@ class App:
|
|||||||
self._flush_to_config()
|
self._flush_to_config()
|
||||||
save_config(self.config)
|
save_config(self.config)
|
||||||
self.ai_status = "discussion saved"
|
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)
|
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()
|
imgui.pop_id()
|
||||||
break
|
break
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
preview = entry["content"].replace("\n", " ")[:60]
|
preview = entry["content"].replace("\\n", " ")[:60]
|
||||||
if len(entry["content"]) > 60: preview += "..."
|
if len(entry["content"]) > 60: preview += "..."
|
||||||
imgui.text_colored(vec4(160, 160, 150), 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):
|
for i, (script, result) in enumerate(self._tool_log, 1):
|
||||||
first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)"
|
first_line = script.strip().splitlines()[0][:80] if script.strip() else "(empty)"
|
||||||
imgui.text_colored(C_KEY, f"Call #{i}: {first_line}")
|
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:
|
if self.ui_word_wrap:
|
||||||
imgui.begin_child(f"tc_wrap_{i}", imgui.ImVec2(-1, 72), True)
|
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:
|
||||||
|
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.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||||
imgui.text(result)
|
imgui.text(result)
|
||||||
imgui.pop_text_wrap_pos()
|
imgui.pop_text_wrap_pos()
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
else:
|
else:
|
||||||
imgui.input_text_multiline(f"##tc_res_{i}", result, imgui.ImVec2(-1, 72), imgui.InputTextFlags_.read_only)
|
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.separator()
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
|
|
||||||
@@ -1477,6 +1502,19 @@ class App:
|
|||||||
if imgui.button("Clear##comms"):
|
if imgui.button("Clear##comms"):
|
||||||
ai_client.clear_comms_log()
|
ai_client.clear_comms_log()
|
||||||
self._comms_log.clear()
|
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.separator()
|
||||||
|
|
||||||
imgui.text_colored(C_OUT, "OUT")
|
imgui.text_colored(C_OUT, "OUT")
|
||||||
@@ -1494,23 +1532,30 @@ class App:
|
|||||||
imgui.text_colored(C_TR, "tool_result")
|
imgui.text_colored(C_TR, "tool_result")
|
||||||
imgui.separator()
|
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)
|
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}")
|
imgui.push_id(f"comms_{idx}")
|
||||||
d = entry["direction"]
|
d = entry.get("direction", "IN")
|
||||||
k = entry["kind"]
|
k = entry.get("kind", "response")
|
||||||
|
|
||||||
imgui.text_colored(vec4(160, 160, 160), f"#{idx}")
|
imgui.text_colored(vec4(160, 160, 160), f"#{idx}")
|
||||||
imgui.same_line()
|
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.same_line()
|
||||||
imgui.text_colored(DIR_COLORS.get(d, C_VAL), d)
|
imgui.text_colored(DIR_COLORS.get(d, C_VAL), d)
|
||||||
imgui.same_line()
|
imgui.same_line()
|
||||||
imgui.text_colored(KIND_COLORS.get(k, C_VAL), k)
|
imgui.text_colored(KIND_COLORS.get(k, C_VAL), k)
|
||||||
imgui.same_line()
|
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":
|
if k == "request":
|
||||||
self._render_heavy_text("message", payload.get("message", ""))
|
self._render_heavy_text("message", payload.get("message", ""))
|
||||||
@@ -1601,6 +1646,9 @@ class App:
|
|||||||
imgui.pop_id()
|
imgui.pop_id()
|
||||||
imgui.end_child()
|
imgui.end_child()
|
||||||
|
|
||||||
|
if self.is_viewing_prior_session:
|
||||||
|
imgui.pop_style_color()
|
||||||
|
|
||||||
def _render_system_prompts_panel(self):
|
def _render_system_prompts_panel(self):
|
||||||
imgui.text("Global System Prompt (all projects)")
|
imgui.text("Global System Prompt (all projects)")
|
||||||
ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100))
|
ch, self.ui_global_system_prompt = imgui.input_text_multiline("##gsp", self.ui_global_system_prompt, imgui.ImVec2(-1, 100))
|
||||||
|
|||||||
Reference in New Issue
Block a user