From 6d825e658567800f400e414c15db6e40a15a10e0 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 23 Feb 2026 21:07:06 -0500 Subject: [PATCH] wip: gemini doing gui_2.py catchup track --- ai_client.py | 2 +- conductor/tracks.md | 2 +- conductor/workflow.md | 1 + config.toml | 3 +- gui_2.py | 90 ++++++++++++++++++--------- manual_slop.toml | 8 +-- manualslop_layout.ini | 134 ++++++++++++++++++++-------------------- tests/temp_project.toml | 7 ++- tests/test_gui2_mcp.py | 78 +++++++++++++++++++++++ 9 files changed, 215 insertions(+), 110 deletions(-) create mode 100644 tests/test_gui2_mcp.py diff --git a/ai_client.py b/ai_client.py index 3b69f1a..b2dd868 100644 --- a/ai_client.py +++ b/ai_client.py @@ -1276,4 +1276,4 @@ def get_history_bleed_stats() -> dict: "limit": 0, "current": 0, "percentage": 0, - } \ No newline at end of file + } diff --git a/conductor/tracks.md b/conductor/tracks.md index 91c301d..066a2a0 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -15,5 +15,5 @@ This file tracks all major tracks for the project. Each track has its own detail --- -- [ ] **Track: get gui_2 working with latest changes to the project.** +- [~] **Track: get gui_2 working with latest changes to the project.** *Link: [./tracks/gui2_feature_parity_20260223/](./tracks/gui2_feature_parity_20260223/)* diff --git a/conductor/workflow.md b/conductor/workflow.md index 7cd681e..b73ab75 100644 --- a/conductor/workflow.md +++ b/conductor/workflow.md @@ -136,6 +136,7 @@ For features involving the GUI or complex internal state, unit tests are often i # The GUI is now running on port 8999 ... ``` + Note: pytest must be run with `uv`. 3. **Verify via ApiHookClient:** Use the `ApiHookClient` in `api_hook_client.py` to interact with the running application. It includes robust retry logic and health checks. diff --git a/config.toml b/config.toml index f71c8f2..0172fdb 100644 --- a/config.toml +++ b/config.toml @@ -1,7 +1,6 @@ -# config.toml [ai] provider = "gemini" -model = "gemini-1.5-pro-latest" +model = "gemini-2.0-flash" temperature = 0.0 max_tokens = 8192 history_trunc_limit = 8000 diff --git a/gui_2.py b/gui_2.py index d5c6b6c..8d6bfc7 100644 --- a/gui_2.py +++ b/gui_2.py @@ -590,6 +590,35 @@ class App: # ---------------------------------------------------------------- gui + def _show_menus(self): + if imgui.begin_menu("Windows"): + for w in self.show_windows.keys(): + _, self.show_windows[w] = imgui.menu_item(w, "", self.show_windows[w]) + imgui.end_menu() + if imgui.begin_menu("Project"): + if imgui.menu_item("Save All", "", False)[0]: + self._flush_to_project() + self._save_active_project() + self._flush_to_config() + save_config(self.config) + self.ai_status = "config saved" + if imgui.menu_item("Reset Session", "", False)[0]: + ai_client.reset_session() + ai_client.clear_comms_log() + self._tool_log.clear() + self._comms_log.clear() + self.ai_status = "session reset" + self.ai_response = "" + if imgui.menu_item("Generate MD Only", "", False)[0]: + try: + md, path, *_ = self._do_generate() + self.last_md = md + self.last_md_path = path + self.ai_status = f"md written: {path.name}" + except Exception as e: + self.ai_status = f"error: {e}" + imgui.end_menu() + def _gui_func(self): self.perf_monitor.start_frame() @@ -611,35 +640,35 @@ class App: self.disc_entries.append(item) self._pending_history_adds.clear() - if imgui.begin_main_menu_bar(): - if imgui.begin_menu("Windows"): - for w in self.show_windows.keys(): - _, self.show_windows[w] = imgui.menu_item(w, "", self.show_windows[w]) - imgui.end_menu() - if imgui.begin_menu("Project"): - if imgui.menu_item("Save All", "", False)[0]: - self._flush_to_project() - self._save_active_project() - self._flush_to_config() - save_config(self.config) - self.ai_status = "config saved" - if imgui.menu_item("Reset Session", "", False)[0]: - ai_client.reset_session() - ai_client.clear_comms_log() - self._tool_log.clear() - self._comms_log.clear() - self.ai_status = "session reset" - self.ai_response = "" - if imgui.menu_item("Generate MD Only", "", False)[0]: - try: - md, path, *_ = self._do_generate() - self.last_md = md - self.last_md_path = path - self.ai_status = f"md written: {path.name}" - except Exception as e: - self.ai_status = f"error: {e}" - imgui.end_menu() - imgui.end_main_menu_bar() + # if imgui.begin_main_menu_bar(): + # if imgui.begin_menu("Windows"): + # for w in self.show_windows.keys(): + # _, self.show_windows[w] = imgui.menu_item(w, "", self.show_windows[w]) + # imgui.end_menu() + # if imgui.begin_menu("Project"): + # if imgui.menu_item("Save All", "", False)[0]: + # self._flush_to_project() + # self._save_active_project() + # self._flush_to_config() + # save_config(self.config) + # self.ai_status = "config saved" + # if imgui.menu_item("Reset Session", "", False)[0]: + # ai_client.reset_session() + # ai_client.clear_comms_log() + # self._tool_log.clear() + # self._comms_log.clear() + # self.ai_status = "session reset" + # self.ai_response = "" + # if imgui.menu_item("Generate MD Only", "", False)[0]: + # try: + # md, path, *_ = self._do_generate() + # self.last_md = md + # self.last_md_path = path + # self.ai_status = f"md written: {path.name}" + # except Exception as e: + # self.ai_status = f"error: {e}" + # imgui.end_menu() + # imgui.end_main_menu_bar() # ---- Projects if self.show_windows["Projects"]: @@ -1590,9 +1619,12 @@ class App: self.runner_params.app_window_params.window_geometry.size = (1680, 1200) self.runner_params.imgui_window_params.enable_viewports = True self.runner_params.imgui_window_params.default_imgui_window_type = hello_imgui.DefaultImGuiWindowType.provide_full_screen_dock_space + self.runner_params.imgui_window_params.show_menu_bar = True self.runner_params.ini_folder_type = hello_imgui.IniFolderType.current_folder self.runner_params.ini_filename = "manualslop_layout.ini" + self.runner_params.callbacks.show_gui = self._gui_func + self.runner_params.callbacks.show_menus = self._show_menus self.runner_params.callbacks.load_additional_fonts = self._load_fonts self.runner_params.callbacks.post_init = self._post_init diff --git a/manual_slop.toml b/manual_slop.toml index 55b19a4..9525b55 100644 --- a/manual_slop.toml +++ b/manual_slop.toml @@ -1,7 +1,3 @@ -# manual_slop.toml -# Main project file for Manual Slop. -# This file is managed by the application and can be edited manually. - [project] name = "manual_slop" git_dir = "C:/projects/manual_slop" @@ -47,8 +43,6 @@ roles = [ active = "test for gemini conductor" auto_add = true -[discussion.discussions] - [discussion.discussions.main] git_commit = "9265f94d9756b1a37a7b8e195725654032d84747" last_updated = "2026-02-21T18:23:13" @@ -71,7 +65,7 @@ history = [ [discussion.discussions."test for gemini conductor"] git_commit = "ccdba69214aea169a4e707da7b425ae0c6139fca" -last_updated = "2026-02-23T19:03:19" +last_updated = "2026-02-23T21:03:27" history = [ "User:\nadded a file to yoru exposed files read it.", "User:\nI have read the `MainContext.md` file. It contains extensive documentation about the \"Manual Slop\" project.\n\nWas `MainContext.md` the file you were referring to? If not, please specify the file's name or path.", diff --git a/manualslop_layout.ini b/manualslop_layout.ini index cc2bfc9..fc0da1c 100644 --- a/manualslop_layout.ini +++ b/manualslop_layout.ini @@ -8,70 +8,81 @@ Size=400,400 Collapsed=0 [Window][Projects] -Pos=209,396 -Size=387,337 +ViewportPos=43,95 +ViewportId=0x78C57832 +Size=897,649 Collapsed=0 -DockId=0x00000014,0 +DockId=0x0000000D,0 [Window][Files] -Pos=0,0 -Size=207,1200 +ViewportPos=3125,170 +ViewportId=0x26D64416 +Size=593,581 Collapsed=0 -DockId=0x00000011,0 +DockId=0x00000009,0 [Window][Screenshots] -Pos=209,0 -Size=387,171 -Collapsed=0 -DockId=0x00000015,0 - -[Window][Discussion History] -Pos=598,128 -Size=554,619 -Collapsed=0 -DockId=0x0000000E,0 - -[Window][Provider] -Pos=209,913 -Size=387,287 +ViewportPos=3125,170 +ViewportId=0x26D64416 +Pos=0,583 +Size=593,574 Collapsed=0 DockId=0x0000000A,0 -[Window][Message] -Pos=598,749 -Size=554,451 +[Window][Discussion History] +Pos=0,17 +Size=1680,730 Collapsed=0 DockId=0x0000000C,0 -[Window][Response] -Pos=209,735 -Size=387,176 +[Window][Provider] +ViewportPos=43,95 +ViewportId=0x78C57832 +Pos=0,651 +Size=897,468 Collapsed=0 -DockId=0x00000010,0 +DockId=0x0000000E,0 + +[Window][Message] +Pos=0,749 +Size=1680,451 +Collapsed=0 +DockId=0x0000000F,0 + +[Window][Response] +Pos=0,749 +Size=1680,451 +Collapsed=0 +DockId=0x0000000F,1 [Window][Tool Calls] -Pos=1154,733 -Size=526,144 +ViewportPos=43,95 +ViewportId=0x78C57832 +Pos=0,1121 +Size=897,775 Collapsed=0 -DockId=0x00000008,0 +DockId=0x00000001,1 [Window][Comms History] -Pos=1154,879 -Size=526,321 +ViewportPos=43,95 +ViewportId=0x78C57832 +Pos=0,1121 +Size=897,775 Collapsed=0 -DockId=0x00000006,0 +DockId=0x00000001,0 [Window][System Prompts] -Pos=1154,0 -Size=286,731 +Pos=0,749 +Size=1680,451 Collapsed=0 -DockId=0x00000017,0 +DockId=0x0000000F,2 [Window][Theme] -Pos=209,173 -Size=387,221 +ViewportPos=43,95 +ViewportId=0x78C57832 +Size=897,649 Collapsed=0 -DockId=0x00000016,0 +DockId=0x0000000D,2 [Window][Text Viewer - Entry #7] Pos=379,324 @@ -79,37 +90,24 @@ Size=900,700 Collapsed=0 [Window][Diagnostics] -Pos=1442,0 -Size=238,731 +ViewportPos=43,95 +ViewportId=0x78C57832 +Size=897,649 Collapsed=0 -DockId=0x00000018,0 +DockId=0x0000000D,1 [Docking][Data] -DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=346,232 Size=1680,1200 Split=X - DockNode ID=0x00000011 Parent=0xAFC85805 SizeRef=207,1200 Selected=0x0469CA7A - DockNode ID=0x00000012 Parent=0xAFC85805 SizeRef=1559,1200 Split=X - DockNode ID=0x00000003 Parent=0x00000012 SizeRef=943,1200 Split=X - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=387,1200 Split=Y Selected=0x8CA2375C - DockNode ID=0x00000009 Parent=0x00000001 SizeRef=405,911 Split=Y Selected=0x8CA2375C - DockNode ID=0x0000000F Parent=0x00000009 SizeRef=405,733 Split=Y Selected=0x8CA2375C - DockNode ID=0x00000013 Parent=0x0000000F SizeRef=405,394 Split=Y Selected=0x8CA2375C - DockNode ID=0x00000015 Parent=0x00000013 SizeRef=405,171 Selected=0xDF822E02 - DockNode ID=0x00000016 Parent=0x00000013 SizeRef=405,221 Selected=0x8CA2375C - DockNode ID=0x00000014 Parent=0x0000000F SizeRef=405,337 Selected=0xDA22FEDA - DockNode ID=0x00000010 Parent=0x00000009 SizeRef=405,176 Selected=0x0D5A5273 - DockNode ID=0x0000000A Parent=0x00000001 SizeRef=405,287 Selected=0xA07B5F14 - DockNode ID=0x00000002 Parent=0x00000003 SizeRef=554,1200 Split=Y - DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1010,747 Split=Y - DockNode ID=0x0000000D Parent=0x0000000B SizeRef=1010,126 CentralNode=1 - DockNode ID=0x0000000E Parent=0x0000000B SizeRef=1010,619 Selected=0x5D11106F - DockNode ID=0x0000000C Parent=0x00000002 SizeRef=1010,451 Selected=0x66CFB56E - DockNode ID=0x00000004 Parent=0x00000012 SizeRef=526,1200 Split=Y Selected=0xDD6419BC - DockNode ID=0x00000005 Parent=0x00000004 SizeRef=261,877 Split=Y Selected=0xDD6419BC - DockNode ID=0x00000007 Parent=0x00000005 SizeRef=261,731 Split=X Selected=0xDD6419BC - DockNode ID=0x00000017 Parent=0x00000007 SizeRef=286,731 Selected=0xDD6419BC - DockNode ID=0x00000018 Parent=0x00000007 SizeRef=238,731 Selected=0xB4CBF21A - DockNode ID=0x00000008 Parent=0x00000005 SizeRef=261,144 Selected=0x1D56B311 - DockNode ID=0x00000006 Parent=0x00000004 SizeRef=261,321 Selected=0x8B4EBFA6 +DockNode ID=0x00000007 Pos=43,95 Size=897,1896 Split=Y + DockNode ID=0x00000002 Parent=0x00000007 SizeRef=1029,1119 Split=Y + DockNode ID=0x0000000D Parent=0x00000002 SizeRef=1029,649 Selected=0xB4CBF21A + DockNode ID=0x0000000E Parent=0x00000002 SizeRef=1029,468 Selected=0xA07B5F14 + DockNode ID=0x00000001 Parent=0x00000007 SizeRef=1029,775 Selected=0x8B4EBFA6 +DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y + DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A + DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02 +DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=1052,572 Size=1680,1183 Split=Y + DockNode ID=0x0000000C Parent=0xAFC85805 SizeRef=1362,1041 CentralNode=1 Selected=0x5D11106F + DockNode ID=0x0000000F Parent=0xAFC85805 SizeRef=1362,451 Selected=0xDD6419BC ;;;<<>>;;; ;;;<<>>;;; @@ -119,6 +117,6 @@ Name=Default Show=false ShowFps=true [Theme] -Name=DarculaDarker +Name=SoDark_AccentRed ;;;<<>>;;; {"gImGuiSplitIDs":{"MainDockSpace":2949142533}} diff --git a/tests/temp_project.toml b/tests/temp_project.toml index dc51355..934f1db 100644 --- a/tests/temp_project.toml +++ b/tests/temp_project.toml @@ -4,6 +4,7 @@ git_dir = "C:\\projects\\manual_slop" system_prompt = "" main_context = "" word_wrap = true +summary_only = false [output] output_dir = "./md_gen" @@ -37,5 +38,7 @@ auto_add = true [discussion.discussions.main] git_commit = "" -last_updated = "2026-02-23T19:53:17" -history = [] +last_updated = "2026-02-23T20:56:57" +history = [ + "@2026-02-23T20:12:12\nSystem:\n[PERFORMANCE ALERT] CPU usage high: 121.9%. Please consider optimizing recent changes or reducing load.", +] diff --git a/tests/test_gui2_mcp.py b/tests/test_gui2_mcp.py new file mode 100644 index 0000000..a91ed5a --- /dev/null +++ b/tests/test_gui2_mcp.py @@ -0,0 +1,78 @@ +import pytest +from unittest.mock import patch, MagicMock +from gui_2 import App +import ai_client +from events import EventEmitter + +@pytest.fixture +def app_instance(): + if not hasattr(ai_client, 'events') or ai_client.events is None: + ai_client.events = EventEmitter() + + with ( + patch('gui_2.load_config', return_value={'ai': {}, 'projects': {}}), + patch('gui_2.save_config'), + patch('gui_2.project_manager'), + patch('gui_2.session_logger'), + patch('gui_2.immapp.run'), + patch.object(App, '_load_active_project'), + patch.object(App, '_fetch_models'), + patch.object(App, '_load_fonts'), + patch.object(App, '_post_init') + ): + yield App() + +def test_mcp_tool_call_is_dispatched(app_instance): + """ + This test verifies that when the AI returns a tool call for an MCP function, + the ai_client correctly dispatches it to mcp_client. + This will fail until mcp_client is properly integrated. + """ + # 1. Define the mock tool call from the AI + mock_fc = MagicMock() + mock_fc.name = "read_file" + mock_fc.args = {"file_path": "test.txt"} + + # 2. Construct the mock AI response (Gemini format) + mock_response_with_tool = MagicMock() + mock_part = MagicMock() + mock_part.function_call = mock_fc + mock_candidate = MagicMock() + mock_candidate.content.parts = [mock_part] + mock_candidate.finish_reason.name = "TOOL_CALLING" + mock_response_with_tool.candidates = [mock_candidate] + + mock_usage_metadata = MagicMock() + mock_usage_metadata.prompt_token_count = 100 + mock_usage_metadata.candidates_token_count = 10 + mock_usage_metadata.cached_content_token_count = 0 + mock_response_with_tool.usage_metadata = mock_usage_metadata + + # 3. Create a mock for the final AI response after the tool call + mock_response_final = MagicMock() + mock_response_final.text = "Final answer" + mock_response_final.candidates = [] + mock_response_final.usage_metadata = mock_usage_metadata + + # 4. Patch the necessary components + with patch("ai_client._ensure_gemini_client"), \ + patch("ai_client._gemini_client"), \ + patch("ai_client._gemini_chat") as mock_chat, \ + patch('mcp_client.dispatch', return_value="file content") as mock_dispatch: + + mock_chat.send_message.side_effect = [mock_response_with_tool, mock_response_final] + ai_client._gemini_chat = mock_chat + + ai_client.set_provider("gemini", "mock-model") + + # 5. Call the send function + ai_client.send( + md_content="some context", + user_message="read the file", + base_dir=".", + file_items=[], + discussion_history="" + ) + + # 6. Assert that the MCP dispatch function was called + mock_dispatch.assert_called_once_with("read_file", {"file_path": "test.txt"})