diff --git a/config.toml b/config.toml index 6321fc06..75937173 100644 --- a/config.toml +++ b/config.toml @@ -50,7 +50,7 @@ separate_external_tools = false "Operations Hub" = true Message = false Response = false -"Tool Calls" = true +"Tool Calls" = false Theme = true "Log Management" = false Diagnostics = false diff --git a/manual_slop.toml b/manual_slop.toml index b08fea66..eb20c2aa 100644 --- a/manual_slop.toml +++ b/manual_slop.toml @@ -215,6 +215,22 @@ ts_c_get_skeleton = true ts_cpp_get_skeleton = true ts_c_get_code_outline = true ts_cpp_get_code_outline = true +edit_file = true +py_remove_def = true +py_add_def = true +py_move_def = true +py_region_wrap = true +ts_c_get_definition = true +ts_cpp_get_definition = true +ts_c_get_signature = true +ts_cpp_get_signature = true +ts_c_update_definition = true +ts_cpp_update_definition = true +derive_code_path = true +bd_create = true +bd_update = true +bd_list = true +bd_ready = true [gemini_cli] binary_path = "gemini" diff --git a/manual_slop_history.toml b/manual_slop_history.toml index 9c375057..3cb08888 100644 --- a/manual_slop_history.toml +++ b/manual_slop_history.toml @@ -9,616 +9,11 @@ auto_add = true [discussions.main] git_commit = "9265f94d9756b1a37a7b8e195725654032d84747" -last_updated = "2026-05-11T22:08:19" +last_updated = "2026-05-14T20:28:27" history = [ "@2026-02-21T18:22:58\nUser:\nI will now try to generate a response from the AI. I will then try to run a tool call. Finally, I will try to generate a response from the AI again.", ] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/auxiliary/builder.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/auxiliary/builder.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/auxiliary/gen_template.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/auxiliary/scanner.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/auxiliary/scanner.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/ast.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/ast.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/ast_case_macros.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/ast_types.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/code_serialization.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] -typedef_to_strbuilder_ref = "hide" - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/code_types.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/constants.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/gen/ast_inlines.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/gen/ecodetypes.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/gen/eoperator.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/gen/especifier.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/gen/etoktype.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/header_end.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/header_start.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/inlines.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/interface.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/interface.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/interface.parsing.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/interface.untyped.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/interface.upfront.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/lexer.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/parser.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/parser_case_macros.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/parser_types.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/src_start.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/static_data.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/components/types.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/basic_types.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/containers.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/debug.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/debug.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/filesystem.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/filesystem.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/hashing.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/hashing.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/macros.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/memory.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/memory.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/parsing.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/parsing.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/platform.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/printing.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/printing.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/src_start.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/string_ops.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/string_ops.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/strings.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/strings.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/timing.cpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] - -[[discussions.main.context_snapshot]] -path = "C:/projects/gencpp/base/dependencies/timing.hpp" -auto_aggregate = false -force_full = false -view_mode = "full" -ast_signatures = false -ast_definitions = false -custom_slices = [] - -[discussions.main.context_snapshot.ast_mask] +context_snapshot = [] [discussions.docs] git_commit = "68e895cb8a0144061d1e3b959b7c9f7f98a0c7ed" diff --git a/manualslop_layout.ini b/manualslop_layout.ini index 81906567..48f4a3c3 100644 --- a/manualslop_layout.ini +++ b/manualslop_layout.ini @@ -75,7 +75,7 @@ DockId=0xAFC85805,2 [Window][Theme] Pos=0,28 -Size=1237,1737 +Size=1171,1793 Collapsed=0 DockId=0x00000010,3 @@ -103,26 +103,26 @@ Collapsed=0 DockId=0x0000000D,0 [Window][Discussion Hub] -Pos=1239,28 -Size=895,1737 +Pos=1173,28 +Size=1359,1793 Collapsed=0 -DockId=0x00000006,1 +DockId=0x00000006,2 [Window][Operations Hub] Pos=0,28 -Size=1237,1737 +Size=1171,1793 Collapsed=0 DockId=0x00000010,2 [Window][Files & Media] -Pos=1239,28 -Size=895,1737 +Pos=1173,28 +Size=1359,1793 Collapsed=0 DockId=0x00000006,0 [Window][AI Settings] Pos=0,28 -Size=1237,1737 +Size=1171,1793 Collapsed=0 DockId=0x00000010,1 @@ -132,10 +132,10 @@ Size=416,325 Collapsed=0 [Window][MMA Dashboard] -Pos=1239,28 -Size=895,1737 +Pos=1173,28 +Size=1359,1793 Collapsed=0 -DockId=0x00000006,2 +DockId=0x00000006,1 [Window][Log Management] Pos=1203,28 @@ -330,8 +330,8 @@ Size=967,499 Collapsed=0 [Window][Usage Analytics] -Pos=3380,28 -Size=460,2132 +Pos=2222,28 +Size=488,1613 Collapsed=0 DockId=0x00000001,0 @@ -409,13 +409,13 @@ DockId=0x00000006,1 [Window][Project Settings] Pos=0,28 -Size=1237,1737 +Size=1171,1793 Collapsed=0 DockId=0x00000010,0 [Window][Undo/Redo History] -Pos=1871,28 -Size=488,1418 +Pos=1612,28 +Size=488,1592 Collapsed=0 DockId=0x00000002,0 @@ -653,14 +653,14 @@ Column 2 Width=150 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=0,28 Size=2134,1737 Split=X +DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,28 Size=2532,1793 Split=X DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2357,1183 Split=X DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2 DockNode ID=0x00000007 Parent=0x0000000B SizeRef=1512,858 Split=X Selected=0x8CA2375C - DockNode ID=0x00000005 Parent=0x00000007 SizeRef=769,1681 Split=Y Selected=0x3F1379AF - DockNode ID=0x00000010 Parent=0x00000005 SizeRef=983,1140 CentralNode=1 Selected=0x418C7449 + DockNode ID=0x00000005 Parent=0x00000007 SizeRef=1171,1681 Split=Y Selected=0x3F1379AF + DockNode ID=0x00000010 Parent=0x00000005 SizeRef=983,1140 CentralNode=1 Selected=0x7BD57D6A DockNode ID=0x00000011 Parent=0x00000005 SizeRef=983,184 Selected=0x432BAE4E - DockNode ID=0x00000006 Parent=0x00000007 SizeRef=895,1681 Selected=0x6F2B5B04 + DockNode ID=0x00000006 Parent=0x00000007 SizeRef=1359,1681 Selected=0x6F2B5B04 DockNode ID=0x0000000E Parent=0x0000000B SizeRef=1777,858 Selected=0x1D56B311 DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6 DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=488,1183 Split=X Selected=0x3AEC3498 diff --git a/project_history.toml b/project_history.toml index 649aab5f..a32c4e10 100644 --- a/project_history.toml +++ b/project_history.toml @@ -9,5 +9,5 @@ active = "main" [discussions.main] git_commit = "" -last_updated = "2026-05-14T00:33:48" +last_updated = "2026-05-16T01:16:09" history = [] diff --git a/src/api_hook_client.py b/src/api_hook_client.py index 56712cd2..accc6d21 100644 --- a/src/api_hook_client.py +++ b/src/api_hook_client.py @@ -33,6 +33,7 @@ See Also: """ from __future__ import annotations import requests # type: ignore[import-untyped] +import sys import time from typing import Any diff --git a/src/api_hooks.py b/src/api_hooks.py index b9679aac..742a045a 100644 --- a/src/api_hooks.py +++ b/src/api_hooks.py @@ -43,19 +43,28 @@ See Also: def _get_app_attr(app: Any, name: str, default: Any = None) -> Any: """Retrieves an attribute from the App or its Controller.""" - try: + if hasattr(app, name): val = getattr(app, name) return val - except AttributeError: - return default + if hasattr(app, 'controller') and hasattr(app.controller, name): + val = getattr(app.controller, name) + return val + return default def _has_app_attr(app: Any, name: str) -> bool: """Checks if an attribute exists on the App or its Controller.""" - return hasattr(app, name) + if hasattr(app, name): return True + if hasattr(app, 'controller') and hasattr(app.controller, name): return True + return False def _set_app_attr(app: Any, name: str, value: Any) -> None: """Sets an attribute on the App or its Controller.""" - setattr(app, name, value) + if hasattr(app, name): + setattr(app, name, value) + elif hasattr(app, 'controller'): + setattr(app.controller, name, value) + else: + setattr(app, name, value) class HookServerInstance(ThreadingHTTPServer): """Custom HTTPServer that carries a reference to the main App instance.""" @@ -145,7 +154,10 @@ class HookHandler(BaseHTTPRequestHandler): if field_tag in combined: attr = combined[field_tag] val = _get_app_attr(app, attr, None) - result["value"] = _serialize_for_api(val) + res_val = _serialize_for_api(val) + sys.stderr.write(f"[DEBUG] get_val: attr={attr}, val_type={type(val).__name__}, res_val={res_val}\n") + sys.stderr.flush() + result["value"] = res_val else: sys.stderr.write(f"Hook API: field {field_tag} not found in settable or gettable\n") sys.stderr.flush() @@ -355,7 +367,7 @@ class HookHandler(BaseHTTPRequestHandler): settable = _get_app_attr(app, "_settable_fields", {}) if field_tag in settable: attr = settable[field_tag] - result["value"] = _get_app_attr(app, attr, None) + result["value"] = _serialize_for_api(_get_app_attr(app, attr, None)) finally: event.set() lock = _get_app_attr(app, "_pending_gui_tasks_lock") tasks = _get_app_attr(app, "_pending_gui_tasks") diff --git a/src/api_hooks_helpers.py b/src/api_hooks_helpers.py new file mode 100644 index 00000000..e22d0878 --- /dev/null +++ b/src/api_hooks_helpers.py @@ -0,0 +1,24 @@ +def _get_app_attr(app: Any, name: str, default: Any = None) -> Any: + """Retrieves an attribute from the App or its Controller.""" + if hasattr(app, name): + val = getattr(app, name) + return val + if hasattr(app, 'controller') and hasattr(app.controller, name): + val = getattr(app.controller, name) + return val + return default + +def _has_app_attr(app: Any, name: str) -> bool: + """Checks if an attribute exists on the App or its Controller.""" + if hasattr(app, name): return True + if hasattr(app, 'controller') and hasattr(app.controller, name): return True + return False + +def _set_app_attr(app: Any, name: str, value: Any) -> None: + """Sets an attribute on the App or its Controller.""" + if hasattr(app, name): + setattr(app, name, value) + elif hasattr(app, 'controller'): + setattr(app.controller, name, value) + else: + setattr(app, name, value) \ No newline at end of file diff --git a/src/app_controller.py b/src/app_controller.py index 4526563d..00fb19f0 100644 --- a/src/app_controller.py +++ b/src/app_controller.py @@ -270,55 +270,97 @@ def _api_generate(controller: 'AppController', req: GenerateRequest) -> dict[str with controller._send_thread_lock: start_time = time.time() try: - md, path, file_items, stable_md, disc_text = controller._do_generate() + # 1. Build context + from src import aggregate + full_md, path, file_items, stable_md, disc_text = controller._do_generate() controller._last_stable_md = stable_md - controller.last_md = md + controller.last_md = full_md controller.last_md_path = path controller.last_file_items = file_items - except Exception as e: - raise HTTPException(status_code=500, detail=f"Context aggregation failure: {e}") - user_msg = req.prompt - base_dir = controller.active_project_root - csp = filter(bool, [controller.ui_global_system_prompt.strip(), controller.ui_project_system_prompt.strip()]) - ai_client.set_custom_system_prompt("\n\n".join(csp)) - ai_client.set_base_system_prompt(controller.ui_base_system_prompt) - ai_client.set_use_default_base_prompt(controller.ui_use_default_base_prompt) - ai_client.set_project_context_marker(controller.ui_project_context_marker) - temp = req.temperature if req.temperature is not None else controller.temperature - top_p = req.top_p if req.top_p is not None else controller.top_p - tokens = req.max_tokens if req.max_tokens is not None else controller.max_tokens - ai_client.set_model_params(temp, tokens, controller.history_trunc_limit, top_p) - ai_client.set_agent_tools(controller.ui_agent_tools) - if req.auto_add_history: - with controller._pending_history_adds_lock: - controller._pending_history_adds.append({ - "role": "User", - "content": user_msg, - "collapsed": True, - "ts": project_manager.now_ts() - }) - try: - resp = ai_client.send(stable_md, user_msg, base_dir, controller.last_file_items, disc_text, rag_engine=controller.rag_engine) + + user_msg = req.prompt + + # 2. RAG Retrieval + if controller.rag_engine and controller.rag_config and controller.rag_config.enabled: + try: + chunks = controller.rag_engine.search(user_msg) + if chunks: + context_block = "## Retrieved Context\n\n" + for i, chunk in enumerate(chunks): + path = chunk.get("metadata", {}).get("path", "unknown") + context_block += f"### Chunk {i+1} (Source: {path})\n{chunk.get('document', '')}\n\n" + user_msg = context_block + user_msg + except Exception as e: + sys.stderr.write(f"RAG search error: {e}\n") + sys.stderr.flush() + + # 3. Symbol Resolution + try: + from src.markdown_helper import parse_symbols, get_symbol_definition + symbols = parse_symbols(user_msg) + file_paths = [f.path if hasattr(f, "path") else f.get("path") if isinstance(f, dict) else str(f) for f in controller.last_file_items] + for symbol in symbols: + res = get_symbol_definition(symbol, file_paths) + if res: + file_path, definition, line = res + user_msg += f'\n\n[Definition: {symbol} from {file_path} (line {line})]\n```python\n{definition}\n```' + except Exception as e: + sys.stderr.write(f"Symbol resolution error: {e}\n") + sys.stderr.flush() + + base_dir = controller.active_project_root + csp = filter(bool, [controller.ui_global_system_prompt.strip(), controller.ui_project_system_prompt.strip()]) + ai_client.set_custom_system_prompt("\n\n".join(csp)) + ai_client.set_base_system_prompt(controller.ui_base_system_prompt) + ai_client.set_use_default_base_prompt(controller.ui_use_default_base_prompt) + ai_client.set_project_context_marker(controller.ui_project_context_marker) + temp = req.temperature if req.temperature is not None else controller.temperature + top_p = req.top_p if req.top_p is not None else controller.top_p + tokens = req.max_tokens if req.max_tokens is not None else controller.max_tokens + ai_client.set_model_params(temp, tokens, controller.history_trunc_limit, top_p) + ai_client.set_agent_tools(controller.ui_agent_tools) + if req.auto_add_history: with controller._pending_history_adds_lock: controller._pending_history_adds.append({ - "role": "AI", - "content": resp, + "role": "User", + "content": user_msg, "collapsed": True, "ts": project_manager.now_ts() }) - controller._recalculate_session_usage() - duration = time.time() - start_time - return { - "text": resp, - "metadata": { - "provider": controller.current_provider, - "model": controller.current_model, - "duration_sec": round(duration, 3), - "timestamp": project_manager.now_ts() - }, - "usage": controller.session_usage - } + + try: + resp = ai_client.send(stable_md, user_msg, base_dir, controller.last_file_items, disc_text, rag_engine=None) + + if req.auto_add_history: + with controller._pending_history_adds_lock: + controller._pending_history_adds.append({ + "role": "AI", + "content": resp, + "collapsed": True, + "ts": project_manager.now_ts() + }) + + controller._recalculate_session_usage() + duration = time.time() - start_time + return { + "text": resp, + "metadata": { + "provider": controller.current_provider, + "model": controller.current_model, + "duration_sec": round(duration, 3), + "timestamp": project_manager.now_ts() + }, + "usage": controller.session_usage + } + except ai_client.ProviderError as e: + raise HTTPException(status_code=500, detail=e.ui_message()) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + except Exception as e: + import traceback + traceback.print_exc() + raise HTTPException(status_code=500, detail=str(e)) except ai_client.ProviderError as e: raise HTTPException(status_code=502, detail=f"AI Provider Error: {e.ui_message()}") except Exception as e: diff --git a/src/app_controller.py_tmp2 b/src/app_controller.py_tmp2 new file mode 100644 index 00000000..87272565 --- /dev/null +++ b/src/app_controller.py_tmp2 @@ -0,0 +1,102 @@ +def _api_generate(controller: 'AppController', req: GenerateRequest) -> dict[str, Any]: + """ + + Triggers an AI generation request using the current project context. + [SDM: src/app_controller.py:_api_generate] + """ + if not req.prompt.strip(): + raise HTTPException(status_code=400, detail="Prompt cannot be empty") + with controller._send_thread_lock: + start_time = time.time() + try: + # 1. Build context + from src import aggregate + full_md, path, file_items, stable_md, disc_text = controller._do_generate() + controller._last_stable_md = stable_md + controller.last_md = md + controller.last_md_path = path + controller.last_file_items = file_items + + user_msg = req.prompt + + # 2. RAG Retrieval + if controller.rag_engine and controller.rag_config and controller.rag_config.enabled: + try: + chunks = controller.rag_engine.search(user_msg) + if chunks: + context_block = "## Retrieved Context\n\n" + for i, chunk in enumerate(chunks): + path = chunk.get("metadata", {}).get("path", "unknown") + context_block += f"### Chunk {i+1} (Source: {path})\n{chunk.get('document', '')}\n\n" + user_msg = context_block + user_msg + except Exception as e: + sys.stderr.write(f"RAG search error: {e}\n") + sys.stderr.flush() + + # 3. Symbol Resolution + try: + from src.markdown_helper import parse_symbols, get_symbol_definition + symbols = parse_symbols(user_msg) + file_paths = [f.path if hasattr(f, "path") else f.get("path") if isinstance(f, dict) else str(f) for f in controller.last_file_items] + for symbol in symbols: + res = get_symbol_definition(symbol, file_paths) + if res: + file_path, definition, line = res + user_msg += f'\n\n[Definition: {symbol} from {file_path} (line {line})]\n```python\n{definition}\n```' + except Exception as e: + sys.stderr.write(f"Symbol resolution error: {e}\n") + sys.stderr.flush() + + base_dir = controller.active_project_root + csp = filter(bool, [controller.ui_global_system_prompt.strip(), controller.ui_project_system_prompt.strip()]) + ai_client.set_custom_system_prompt("\n\n".join(csp)) + ai_client.set_base_system_prompt(controller.ui_base_system_prompt) + ai_client.set_use_default_base_prompt(controller.ui_use_default_base_prompt) + ai_client.set_project_context_marker(controller.ui_project_context_marker) + temp = req.temperature if req.temperature is not None else controller.temperature + top_p = req.top_p if req.top_p is not None else controller.top_p + tokens = req.max_tokens if req.max_tokens is not None else controller.max_tokens + ai_client.set_model_params(temp, tokens, controller.history_trunc_limit, top_p) + ai_client.set_agent_tools(controller.ui_agent_tools) + + if req.auto_add_history: + with controller._pending_history_adds_lock: + controller._pending_history_adds.append({ + "role": "User", + "content": user_msg, + "collapsed": True, + "ts": project_manager.now_ts() + }) + + try: + resp = ai_client.send(stable_md, user_msg, base_dir, controller.last_file_items, disc_text, rag_engine=None) + + if req.auto_add_history: + with controller._pending_history_adds_lock: + controller._pending_history_adds.append({ + "role": "AI", + "content": resp, + "collapsed": True, + "ts": project_manager.now_ts() + }) + + controller._recalculate_session_usage() + duration = time.time() - start_time + return { + "text": resp, + "metadata": { + "provider": controller.current_provider, + "model": controller.current_model, + "duration_sec": round(duration, 3), + "timestamp": project_manager.now_ts() + }, + "usage": controller.session_usage + } + except ai_client.ProviderError as e: + raise HTTPException(status_code=500, detail=e.ui_message()) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + except Exception as e: + import traceback + traceback.print_exc() + raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file diff --git a/src/gui_2.py b/src/gui_2.py index fb000319..6f4f7dd2 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -380,35 +380,11 @@ class App: def __getattr__(self, name: str) -> Any: if name == 'controller': raise AttributeError(name) - try: - ctrl = object.__getattribute__(self, 'controller') - except AttributeError: - raise AttributeError(name) - - if ctrl is not None: - try: - val = getattr(ctrl, name) - sys.stderr.write(f"[DEBUG __getattr__] name={name}, val_type={type(val).__name__}\n") - sys.stderr.flush() - return val - except AttributeError: - pass - - raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") + return getattr(self.controller, name) def __setattr__(self, name: str, value: Any) -> None: - if name == 'controller': - object.__setattr__(self, name, value) - return - - try: - # Use object.__getattribute__ to avoid recursion - ctrl = object.__getattribute__(self, 'controller') - except AttributeError: - ctrl = None - - if ctrl is not None and hasattr(ctrl, name): - setattr(ctrl, name, value) + if name != 'controller' and hasattr(self, 'controller') and hasattr(self.controller, name): + setattr(self.controller, name, value) else: object.__setattr__(self, name, value) @@ -696,7 +672,7 @@ class App: if show_content: h = 150 if is_standalone else 100 - with imscope.child(f"thinking_content_{entry_index}", imgui.ImVec2(0, h), True): + with imscope.child(f"thinking_content_{entry_index}", 0, h, True): for idx, seg in enumerate(segments): content = seg.get("content", "") marker = seg.get("marker", "thinking") @@ -1014,7 +990,7 @@ class App: imgui.same_line() if imgui.button("Redo") and self.history.can_redo: self._handle_redo() imgui.separator() - with imscope.child("history_list", imgui.ImVec2(0, 0), True): + with imscope.child("history_list", 0, 0, True): history = self.history.get_history() if not history: imgui.text("No history available.") else: iterate_history() @@ -2558,7 +2534,7 @@ class App: if not hasattr(self, 'files_screenshots_split'): self.files_screenshots_split = 0.65 split_y = int(avail * self.files_screenshots_split) if imgui.collapsing_header("Files", imgui.TreeNodeFlags_.default_open): - with imscope.child("Files_child", imgui.ImVec2(-1, split_y), True): + with imscope.child("Files_child", -1, split_y, True): if not hasattr(self, 'files_last_selected'): self.files_last_selected = -1 with imscope.table("files_table", 5, imgui.TableFlags_.resizable | imgui.TableFlags_.borders): @@ -2647,7 +2623,7 @@ class App: imgui.separator() if imgui.collapsing_header("Screenshots", imgui.TreeNodeFlags_.default_open): - with imscope.child("Shots_child", imgui.ImVec2(-1, -1), True): + with imscope.child("Shots_child", -1, -1, True): for i, s in enumerate(self.screenshots): if imgui.button(f"x##s{i}"): self.screenshots.pop(i) @@ -3751,7 +3727,7 @@ class App: with imscope.style_color(imgui.Col_.frame_bg, blink_color) if is_blinking else nullcontext(): with imscope.style_color(imgui.Col_.child_bg, blink_color) if is_blinking else nullcontext(): - with imscope.child("response_scroll_area", imgui.ImVec2(0, -40), True): + with imscope.child("response_scroll_area", 0, -40, True): with theme.ai_text_style(): segments, parsed_response = thinking_parser.parse_thinking_trace(self.ai_response) if segments: diff --git a/src/gui_2.py_tmp b/src/gui_2.py_tmp new file mode 100644 index 00000000..2ff87802 --- /dev/null +++ b/src/gui_2.py_tmp @@ -0,0 +1,5 @@ + def __setattr__(self, name: str, value: Any) -> None: + if name != 'controller' and hasattr(self, 'controller') and hasattr(self.controller, name): + setattr(self.controller, name, value) + else: + object.__setattr__(self, name, value) \ No newline at end of file diff --git a/src/rag_engine.py b/src/rag_engine.py index 7ca05f72..e3412d9b 100644 --- a/src/rag_engine.py +++ b/src/rag_engine.py @@ -108,7 +108,8 @@ class RAGEngine: def _init_vector_store(self): vs_config = self.config.vector_store if vs_config.provider == 'chroma': - db_path = os.path.abspath(os.path.join(self.base_dir, ".slop_cache", "rag_chroma")) + # Use a collection-specific path to avoid dimension conflicts and locks between tests + db_path = os.path.abspath(os.path.join(self.base_dir, ".slop_cache", f"chroma_{vs_config.collection_name}")) os.makedirs(db_path, exist_ok=True) chroma_module = _get_chromadb() if chroma_module is None: diff --git a/tests/test_gui_window_controls.py b/tests/test_gui_window_controls.py index 86a790f9..a23a5725 100644 --- a/tests/test_gui_window_controls.py +++ b/tests/test_gui_window_controls.py @@ -38,8 +38,9 @@ def test_gui_window_controls_minimize_maximize_close(): # Let's say _render_custom_title_bar uses imgui.button # We will test the close button logic # Since it's UI code, we just simulate the conditions - mock_imgui.button.return_value = True # Simulate all buttons being clicked - + mock_imgui.button.return_value = True + mock_imgui.menu_item.return_value = (False, False) + # Simulate all buttons being clicked # Avoid hitting actual menu logic that requires real runner_params mock_imgui.begin_menu.return_value = False diff --git a/tests/test_live_gui_integration_v2.py b/tests/test_live_gui_integration_v2.py index 6acd5529..a306385a 100644 --- a/tests/test_live_gui_integration_v2.py +++ b/tests/test_live_gui_integration_v2.py @@ -54,10 +54,11 @@ def test_user_request_integration_flow(mock_app: App) -> None: # 3. Verify ai_client.send was called assert mock_send.called, "ai_client.send was not called" - # 4. Now the 'response' event is in app.controller.event_queue - # But NO ONE is consuming it because _process_event_queue is in the mocked start_services thread. - # Let's manually run one tick of the event queue processing logic - # In _process_event_queue: event_name, payload = self.event_queue.get() + # 4. First event should be 'comms' (request logging) + event_name, payload = app.controller.event_queue.get() + assert event_name == "comms" + + # 5. Next event should be 'response' event_name, payload = app.controller.event_queue.get() assert event_name == "response" @@ -102,6 +103,9 @@ def test_user_request_error_handling(mock_app: App) -> None: app.controller._handle_request_event(event) # Manually consume from queue + event_name, payload = app.controller.event_queue.get() + assert event_name == "comms" + event_name, payload = app.controller.event_queue.get() assert event_name == "response" assert payload["status"] == "error" diff --git a/tests/test_rag_integration.py b/tests/test_rag_integration.py index 733cc8e8..3f3126c9 100644 --- a/tests/test_rag_integration.py +++ b/tests/test_rag_integration.py @@ -93,7 +93,8 @@ def test_rag_integration(mock_project): # Verify that ai_client.send was called by AppController assert mock_send.called _, kwargs = mock_send.call_args - assert kwargs['rag_engine'] == mock_rag_engine + # rag_engine is now handled inside _handle_request_event, so send() gets None + assert kwargs['rag_engine'] is None # Verify that the internal provider call was made assert mock_provider.called