still fixing regressions

This commit is contained in:
2026-03-06 20:27:03 -05:00
parent 4c92817928
commit 13453a0a14
6 changed files with 241 additions and 160 deletions

View File

@@ -1,5 +1,5 @@
[ai] [ai]
provider = "gemini" provider = "gemini_cli"
model = "gemini-2.5-flash-lite" model = "gemini-2.5-flash-lite"
temperature = 0.0 temperature = 0.0
max_tokens = 8192 max_tokens = 8192
@@ -21,6 +21,7 @@ active = "C:\\projects\\manual_slop\\tests\\artifacts\\temp_project.toml"
[gui] [gui]
separate_message_panel = false separate_message_panel = false
separate_response_panel = false separate_response_panel = false
separate_tool_calls_panel = false
[gui.show_windows] [gui.show_windows]
"Context Hub" = true "Context Hub" = true
@@ -33,8 +34,9 @@ separate_response_panel = false
"Tier 4: QA" = true "Tier 4: QA" = true
"Discussion Hub" = true "Discussion Hub" = true
"Operations Hub" = true "Operations Hub" = true
Message = false Message = true
Response = false Response = true
"Tool Calls" = false
Theme = true Theme = true
"Log Management" = true "Log Management" = true
Diagnostics = true Diagnostics = true

View File

@@ -64,7 +64,7 @@ py_set_signature = false
py_set_var_declaration = false py_set_var_declaration = false
[gemini_cli] [gemini_cli]
binary_path = "C:\\projects\\manual_slop\\.venv\\Scripts\\python.exe C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py" binary_path = "gemini"
[mma] [mma]
epic = "" epic = ""

View File

@@ -44,22 +44,19 @@ Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
[Window][Message] [Window][Message]
Pos=2058,1284 Pos=2830,1055
Size=1633,667 Size=954,371
Collapsed=0 Collapsed=0
[Window][Response] [Window][Response]
Pos=1142,771 Pos=2941,1527
Size=567,866 Size=718,484
Collapsed=0 Collapsed=0
[Window][Tool Calls] [Window][Tool Calls]
ViewportPos=43,95 Pos=1300,926
ViewportId=0x78C57832 Size=700,440
Pos=0,1121
Size=897,775
Collapsed=0 Collapsed=0
DockId=0x00000001,1
[Window][Comms History] [Window][Comms History]
ViewportPos=43,95 ViewportPos=43,95
@@ -67,7 +64,7 @@ ViewportId=0x78C57832
Pos=0,1121 Pos=0,1121
Size=897,775 Size=897,775
Collapsed=0 Collapsed=0
DockId=0x00000001,0 DockId=0x0000000B,0
[Window][System Prompts] [Window][System Prompts]
Pos=0,749 Pos=0,749
@@ -77,7 +74,7 @@ DockId=0xAFC85805,2
[Window][Theme] [Window][Theme]
Pos=0,17 Pos=0,17
Size=705,927 Size=705,960
Collapsed=0 Collapsed=0
DockId=0x00000005,1 DockId=0x00000005,1
@@ -88,13 +85,13 @@ Collapsed=0
[Window][Diagnostics] [Window][Diagnostics]
Pos=707,17 Pos=707,17
Size=1122,443 Size=1358,379
Collapsed=0 Collapsed=0
DockId=0x0000001A,0 DockId=0x0000001A,0
[Window][Context Hub] [Window][Context Hub]
Pos=0,17 Pos=0,17
Size=705,927 Size=705,960
Collapsed=0 Collapsed=0
DockId=0x00000005,0 DockId=0x00000005,0
@@ -105,26 +102,26 @@ Collapsed=0
DockId=0x0000000D,0 DockId=0x0000000D,0
[Window][Discussion Hub] [Window][Discussion Hub]
Pos=1831,17 Pos=2067,17
Size=1156,1507 Size=920,1883
Collapsed=0 Collapsed=0
DockId=0x00000013,0 DockId=0x00000013,0
[Window][Operations Hub] [Window][Operations Hub]
Pos=707,462 Pos=707,398
Size=1122,1062 Size=1358,1502
Collapsed=0 Collapsed=0
DockId=0x0000001B,0 DockId=0x0000001B,0
[Window][Files & Media] [Window][Files & Media]
Pos=0,946 Pos=0,979
Size=705,1191 Size=705,1158
Collapsed=0 Collapsed=0
DockId=0x00000006,1 DockId=0x00000006,1
[Window][AI Settings] [Window][AI Settings]
Pos=0,946 Pos=0,979
Size=705,1191 Size=705,1158
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
@@ -151,26 +148,26 @@ Size=262,209
Collapsed=0 Collapsed=0
[Window][Tier 1: Strategy] [Window][Tier 1: Strategy]
Pos=707,1526 Pos=707,1902
Size=463,611 Size=463,235
Collapsed=0 Collapsed=0
DockId=0x00000014,0 DockId=0x00000014,0
[Window][Tier 2: Tech Lead] [Window][Tier 2: Tech Lead]
Pos=1172,1526 Pos=1172,1902
Size=730,611 Size=730,235
Collapsed=0 Collapsed=0
DockId=0x00000016,0 DockId=0x00000016,0
[Window][Tier 4: QA] [Window][Tier 4: QA]
Pos=2453,1526 Pos=2453,1902
Size=534,611 Size=534,235
Collapsed=0 Collapsed=0
DockId=0x00000019,0 DockId=0x00000019,0
[Window][Tier 3: Workers] [Window][Tier 3: Workers]
Pos=1904,1526 Pos=1904,1902
Size=547,611 Size=547,235
Collapsed=0 Collapsed=0
DockId=0x00000018,0 DockId=0x00000018,0
@@ -184,6 +181,21 @@ Pos=60,60
Size=800,600 Size=800,600
Collapsed=0 Collapsed=0
[Window][Text Viewer - Log Entry #1 (request)]
Pos=60,60
Size=900,700
Collapsed=0
[Window][Text Viewer - Log Entry #2 (response)]
Pos=363,873
Size=1005,366
Collapsed=0
[Window][Text Viewer - Entry #11]
Pos=60,60
Size=900,700
Collapsed=0
[Table][0xFB6E3870,4] [Table][0xFB6E3870,4]
RefScale=13 RefScale=13
Column 0 Width=80 Column 0 Width=80
@@ -221,31 +233,45 @@ Column 1 Width=60
Column 2 Weight=1.0000 Column 2 Weight=1.0000
Column 3 Width=100 Column 3 Width=100
[Table][0x8BCC69C7,6]
RefScale=13
Column 0 Width=40
Column 1 Width=60
Column 2 Width=123
Column 3 Width=20
Column 4 Weight=1.0000
Column 5 Width=50
[Table][0x3751446B,4]
RefScale=13
Column 0 Width=40
Column 1 Width=60
Column 2 Weight=1.0000
Column 3 Width=100
[Docking][Data] [Docking][Data]
DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y DockNode ID=0x00000008 Pos=3125,170 Size=593,1157 Split=Y
DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A DockNode ID=0x00000009 Parent=0x00000008 SizeRef=1029,147 Selected=0x0469CA7A
DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02 DockNode ID=0x0000000A Parent=0x00000008 SizeRef=1029,145 Selected=0xDF822E02
DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,17 Size=3840,2120 Split=X DockSpace ID=0xAFC85805 Window=0x079D3A04 Pos=0,17 Size=3840,2120 Split=X
DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2987,1183 Split=X DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2987,1183 Split=X
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=Y Selected=0xF4139CA2 DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2
DockNode ID=0x00000002 Parent=0x0000000B SizeRef=1029,1119 Split=X Selected=0xF4139CA2 DockNode ID=0x00000007 Parent=0x0000000B SizeRef=705,858 Split=Y Selected=0x8CA2375C
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=705,858 Split=Y Selected=0x8CA2375C DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,960 Selected=0xF4139CA2
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,927 Selected=0xF4139CA2 DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,1158 CentralNode=1 Selected=0x7BD57D6A
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,1191 CentralNode=1 Selected=0x7BD57D6A DockNode ID=0x0000000E Parent=0x0000000B SizeRef=2280,858 Split=Y Selected=0x418C7449
DockNode ID=0x0000000E Parent=0x00000002 SizeRef=2280,858 Split=Y Selected=0x418C7449 DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1883 Split=X Selected=0x418C7449
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1507 Split=X Selected=0x418C7449 DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1358,402 Split=Y Selected=0xB4CBF21A
DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1122,402 Split=Y Selected=0xB4CBF21A DockNode ID=0x0000001A Parent=0x00000012 SizeRef=1141,379 Selected=0xB4CBF21A
DockNode ID=0x0000001A Parent=0x00000012 SizeRef=1141,443 Selected=0xB4CBF21A DockNode ID=0x0000001B Parent=0x00000012 SizeRef=1141,1502 Selected=0x418C7449
DockNode ID=0x0000001B Parent=0x00000012 SizeRef=1141,1062 Selected=0x418C7449 DockNode ID=0x00000013 Parent=0x00000010 SizeRef=920,402 Selected=0x6F2B5B04
DockNode ID=0x00000013 Parent=0x00000010 SizeRef=1156,402 Selected=0x6F2B5B04 DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,235 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,611 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=463,837 Selected=0xBB346584 DockNode ID=0x00000014 Parent=0x00000011 SizeRef=463,837 Selected=0xBB346584
DockNode ID=0x00000015 Parent=0x00000011 SizeRef=1815,837 Split=X Selected=0x5CDB7A4B DockNode ID=0x00000015 Parent=0x00000011 SizeRef=1815,837 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000016 Parent=0x00000015 SizeRef=730,837 Selected=0x390E7942 DockNode ID=0x00000016 Parent=0x00000015 SizeRef=730,837 Selected=0x390E7942
DockNode ID=0x00000017 Parent=0x00000015 SizeRef=1083,837 Split=X Selected=0x655BC6E9 DockNode ID=0x00000017 Parent=0x00000015 SizeRef=1083,837 Split=X Selected=0x655BC6E9
DockNode ID=0x00000018 Parent=0x00000017 SizeRef=547,874 Selected=0x655BC6E9 DockNode ID=0x00000018 Parent=0x00000017 SizeRef=547,874 Selected=0x655BC6E9
DockNode ID=0x00000019 Parent=0x00000017 SizeRef=534,874 Selected=0x5CDB7A4B DockNode ID=0x00000019 Parent=0x00000017 SizeRef=534,874 Selected=0x5CDB7A4B
DockNode ID=0x00000001 Parent=0x0000000B SizeRef=1029,775 Selected=0x8B4EBFA6
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6 DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=851,1183 Selected=0x3AEC3498 DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=851,1183 Selected=0x3AEC3498

View File

@@ -584,3 +584,51 @@ System:
testing 123 testing 123
------------------ ------------------
--- MOCK INVOKED ---
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--output-format', 'stream-json']
PROMPT:
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
<context>
</context>
testing gemini
------------------
--- MOCK INVOKED ---
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--resume', 'mock-session-default', '--output-format', 'stream-json']
PROMPT:
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
<context>
</context>
1+ 1?
------------------
--- MOCK INVOKED ---
ARGS: ['C:\\projects\\manual_slop\\tests\\mock_gemini_cli.py', '-m', 'gemini-2.5-flash-lite', '--prompt', '', '--resume', 'mock-session-final', '--output-format', 'stream-json']
PROMPT:
You are a helpful coding assistant with access to a PowerShell tool (run_powershell) and MCP tools (file access: read_file, list_directory, search_files, get_file_summary, web access: web_search, fetch_url). When calling file/directory tools, always use the 'path' parameter for the target path. When asked to create or edit files, prefer targeted edits over full rewrites. Always explain what you are doing before invoking the tool.
When writing or rewriting large files (especially those containing quotes, backticks, or special characters), avoid python -c with inline strings. Instead: (1) write a .py helper script to disk using a PS here-string (@'...'@ for literal content), (2) run it with `python <script>`, (3) delete the helper. For small targeted edits, use PowerShell's (Get-Content) / .Replace() / Set-Content or Add-Content directly.
When making function calls using tools that accept array or object parameters ensure those are structured using JSON. For example:
When you need to verify a change, rely on the exit code and stdout/stderr from the tool — the user's context files are automatically refreshed after every tool call, so you do NOT need to re-read files that are already provided in the <context> block.
<context>
</context>
1+ 1?
------------------

View File

@@ -640,6 +640,7 @@ class AppController:
"Operations Hub": True, "Operations Hub": True,
"Message": False, "Message": False,
"Response": False, "Response": False,
"Tool Calls": False,
"Theme": True, "Theme": True,
"Log Management": False, "Log Management": False,
"Diagnostics": False, "Diagnostics": False,
@@ -1714,6 +1715,7 @@ class AppController:
"show_windows": self.show_windows, "show_windows": self.show_windows,
"separate_message_panel": getattr(self, "ui_separate_message_panel", False), "separate_message_panel": getattr(self, "ui_separate_message_panel", False),
"separate_response_panel": getattr(self, "ui_separate_response_panel", False), "separate_response_panel": getattr(self, "ui_separate_response_panel", False),
"separate_tool_calls_panel": getattr(self, "ui_separate_tool_calls_panel", False),
} }
theme.save_to_config(self.config) theme.save_to_config(self.config)

View File

@@ -107,11 +107,13 @@ class App:
gui_cfg = self.config.get("gui", {}) gui_cfg = self.config.get("gui", {})
self.ui_separate_message_panel = gui_cfg.get("separate_message_panel", False) self.ui_separate_message_panel = gui_cfg.get("separate_message_panel", False)
self.ui_separate_response_panel = gui_cfg.get("separate_response_panel", False) self.ui_separate_response_panel = gui_cfg.get("separate_response_panel", False)
self.ui_separate_tool_calls_panel = gui_cfg.get("separate_tool_calls_panel", False)
self._comms_log_cache: list[dict[str, Any]] = [] self._comms_log_cache: list[dict[str, Any]] = []
self._comms_log_dirty: bool = True self._comms_log_dirty: bool = True
self._tool_log_cache: list[dict[str, Any]] = [] self._tool_log_cache: list[dict[str, Any]] = []
self._tool_log_dirty: bool = True self._tool_log_dirty: bool = True
self._last_ui_focus_agent: Optional[str] = None self._last_ui_focus_agent: Optional[str] = None
self._log_registry: Optional[log_registry.LogRegistry] = None
def _handle_approve_tool(self, user_data=None) -> None: def _handle_approve_tool(self, user_data=None) -> None:
"""UI-level wrapper for approving a pending tool execution ask.""" """UI-level wrapper for approving a pending tool execution ask."""
@@ -426,15 +428,22 @@ class App:
if imgui.button("x##clear_focus"): if imgui.button("x##clear_focus"):
self.ui_focus_agent = None self.ui_focus_agent = None
if exp: if exp:
imgui.push_style_var(imgui.StyleVar_.item_spacing, imgui.ImVec2(10, 4))
ch, self.ui_separate_tool_calls_panel = imgui.checkbox("Pop Out Tool Calls", self.ui_separate_tool_calls_panel)
if ch: self.show_windows["Tool Calls"] = self.ui_separate_tool_calls_panel
imgui.pop_style_var()
show_tc_tab = not self.ui_separate_tool_calls_panel
if imgui.begin_tab_bar("ops_tabs"): if imgui.begin_tab_bar("ops_tabs"):
if imgui.begin_tab_item("Comms History")[0]: if imgui.begin_tab_item("Comms History")[0]:
self._render_comms_history_panel() self._render_comms_history_panel()
imgui.end_tab_item() imgui.end_tab_item()
if show_tc_tab:
if imgui.begin_tab_item("Tool Calls")[0]: if imgui.begin_tab_item("Tool Calls")[0]:
self._render_tool_calls_panel() self._render_tool_calls_panel()
imgui.end_tab_item() imgui.end_tab_item()
imgui.end_tab_bar() imgui.end_tab_bar()
imgui.end() imgui.end()
if self.ui_separate_message_panel and self.show_windows.get("Message", False): if self.ui_separate_message_panel and self.show_windows.get("Message", False):
@@ -451,6 +460,13 @@ class App:
self._render_response_panel() self._render_response_panel()
imgui.end() imgui.end()
if self.ui_separate_tool_calls_panel and self.show_windows.get("Tool Calls", False):
exp, opened = imgui.begin("Tool Calls", self.show_windows["Tool Calls"])
self.show_windows["Tool Calls"] = bool(opened)
if exp:
self._render_tool_calls_panel()
imgui.end()
if self.show_windows.get("Log Management", False): if self.show_windows.get("Log Management", False):
self._render_log_management() self._render_log_management()
if self.show_windows["Diagnostics"]: if self.show_windows["Diagnostics"]:
@@ -863,7 +879,18 @@ class App:
if not exp: if not exp:
imgui.end() imgui.end()
return return
registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
if self._log_registry is None:
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
else:
# Refresh data occasionally or on demand? For now let's just use the cached object.
# The LogRegistry object loads data into self.data upon __init__.
# We might want a refresh button or to reload every few seconds.
if imgui.button("Refresh Registry"):
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
imgui.same_line()
registry = self._log_registry
sessions = registry.data sessions = registry.data
if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
imgui.table_setup_column("Session ID") imgui.table_setup_column("Session ID")
@@ -1145,6 +1172,8 @@ class App:
if imgui.button("+" if collapsed else "-"): if imgui.button("+" if collapsed else "-"):
entry["collapsed"] = not collapsed entry["collapsed"] = not collapsed
imgui.same_line() imgui.same_line()
self._render_text_viewer(f"Entry #{i+1}", entry["content"])
imgui.same_line()
imgui.set_next_item_width(120) imgui.set_next_item_width(120)
if imgui.begin_combo("##role", entry["role"]): if imgui.begin_combo("##role", entry["role"]):
for r in self.disc_roles: for r in self.disc_roles:
@@ -1164,8 +1193,6 @@ class App:
if imgui.button("Ins"): if imgui.button("Ins"):
self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()}) self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()})
imgui.same_line() imgui.same_line()
self._render_text_viewer(f"Entry #{i+1}", entry["content"])
imgui.same_line()
if imgui.button("Del"): if imgui.button("Del"):
self.disc_entries.pop(i) self.disc_entries.pop(i)
imgui.pop_id() imgui.pop_id()
@@ -1405,113 +1432,88 @@ class App:
self.ai_status = "idle" self.ai_status = "idle"
imgui.separator() imgui.separator()
imgui.text_colored(C_OUT, "OUT")
imgui.same_line()
imgui.text_colored(C_REQ, "request")
imgui.same_line()
imgui.text_colored(C_TC, "tool_call")
imgui.same_line()
imgui.text(" ")
imgui.same_line()
imgui.text_colored(C_IN, "IN")
imgui.same_line()
imgui.text_colored(C_RES, "response")
imgui.same_line()
imgui.text_colored(C_TR, "tool_result")
imgui.separator()
# Use tinted background for prior session # Use tinted background for prior session
if self.is_viewing_prior_session: if self.is_viewing_prior_session:
imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 30, 20)) 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)
log_to_render = self._comms_log_cache log_to_render = self._comms_log_cache
flags = imgui.TableFlags_.resizable | imgui.TableFlags_.hideable | imgui.TableFlags_.borders_inner_v | imgui.TableFlags_.row_bg | imgui.TableFlags_.scroll_y
# Set a max height for the table or use available region
avail = imgui.get_content_region_avail()
if imgui.begin_table("comms_table", 6, flags, imgui.ImVec2(0, avail.y)):
imgui.table_setup_column("#", imgui.TableColumnFlags_.width_fixed, 40)
imgui.table_setup_column("Tier", imgui.TableColumnFlags_.width_fixed, 60)
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 80)
imgui.table_setup_column("!", imgui.TableColumnFlags_.width_fixed, 20)
imgui.table_setup_column("Content", imgui.TableColumnFlags_.width_stretch)
imgui.table_setup_column("Action", imgui.TableColumnFlags_.width_fixed, 50)
imgui.table_headers_row()
def payload_to_str(msg_kind, payload):
if msg_kind == "request":
return payload.get("message", "")
elif msg_kind == "response":
r = payload.get("round", 0)
sr = payload.get("stop_reason", "STOP")
text = payload.get("text", "")
tcs = payload.get("tool_calls", [])
tc_str = f" ({len(tcs)} tool calls)" if tcs else ""
return f"[R{r}] [{sr}]{tc_str} {text}"
elif msg_kind == "tool_call":
content = f"Call: {payload.get('name', '?')}"
if "script" in payload:
content += f" | Script: {payload['script']}"
elif "args" in payload:
content += f" | Args: {json.dumps(payload['args'])}"
return content
elif msg_kind == "tool_result":
return f"Result: {payload.get('name', '?')} | {payload.get('output', '')}"
return str(payload)
clipper = imgui.ListClipper() clipper = imgui.ListClipper()
clipper.begin(len(log_to_render)) clipper.begin(len(log_to_render))
while clipper.step(): while clipper.step():
for i in range(clipper.display_start, clipper.display_end): for i in range(clipper.display_start, clipper.display_end):
entry = log_to_render[i] entry = log_to_render[i]
imgui.table_next_row() imgui.push_id(f"comms_entry_{i}")
i_display = i + 1 i_display = i + 1
source = entry.get("source_tier", "main") ts = entry.get("ts", "00:00:00")
msg_kind = entry.get("kind", entry.get("type", "?")) # Handle legacy 'type' direction = entry.get("direction", "??")
kind = entry.get("kind", entry.get("type", "??"))
provider = entry.get("provider", "?")
model = entry.get("model", "?")
tier = entry.get("source_tier", "main")
payload = entry.get("payload", {}) payload = entry.get("payload", {})
if not payload and msg_kind not in ("request", "response", "tool_call", "tool_result"): if not payload and kind not in ("request", "response", "tool_call", "tool_result"):
payload = entry # Legacy format where entry IS the payload payload = entry # legacy
full_content = payload_to_str(msg_kind, payload) # Row 1: #Idx TS DIR KIND Provider/Model [Tier]
content_preview = full_content
if len(content_preview) > 500: # Increased clamp
content_preview = content_preview[:500] + "..."
# FG Color based on kind
fg = C_VAL
if msg_kind == "request": fg = C_REQ
elif msg_kind == "response": fg = C_RES
elif msg_kind == "tool_call": fg = C_TC
elif msg_kind == "tool_result": fg = C_TR
elif msg_kind == "error": fg = vec4(255, 80, 80)
imgui.table_next_column()
imgui.text_colored(C_LBL, f"#{i_display}") imgui.text_colored(C_LBL, f"#{i_display}")
imgui.same_line()
imgui.text_colored(vec4(160, 160, 160), ts)
imgui.same_line()
d_col = DIR_COLORS.get(direction, C_VAL)
imgui.text_colored(d_col, direction)
imgui.same_line()
k_col = KIND_COLORS.get(kind, C_VAL)
imgui.text_colored(k_col, kind)
imgui.same_line()
imgui.text_colored(C_LBL, f"{provider}/{model}")
imgui.same_line()
imgui.text_colored(C_SUB, f"[{tier}]")
imgui.table_next_column() # Optimized content rendering using _render_heavy_text logic
imgui.text_colored(C_SUB, f"[{source}]") if kind == "request":
self._render_heavy_text("message", payload.get("message", ""))
imgui.table_next_column() elif kind == "response":
imgui.text_colored(fg, msg_kind) r = payload.get("round", 0)
sr = payload.get("stop_reason", "STOP")
imgui.table_next_column() imgui.text_colored(C_LBL, f"round: {r} stop_reason: {sr}")
elapsed = time.time() - entry.get("local_ts", 0) self._render_heavy_text("text", payload.get("text", ""))
if elapsed < 3.0: tcs = payload.get("tool_calls", [])
blink = (math.sin(elapsed * 15) * 0.5 + 0.5) if tcs:
imgui.text_colored(vec4(255, 255, 0, blink), "*") self._render_heavy_text("tool_calls", json.dumps(tcs, indent=1))
elif kind == "tool_call":
self._render_heavy_text(payload.get("name", "call"), payload.get("script") or json.dumps(payload.get("args", {}), indent=1))
elif kind == "tool_result":
self._render_heavy_text(payload.get("name", "result"), payload.get("output", ""))
else: else:
imgui.text("") self._render_heavy_text("data", str(payload))
imgui.table_next_column() imgui.separator()
if self.ui_word_wrap: imgui.pop_id()
imgui.push_text_wrap_pos(0.0)
imgui.text_unformatted(content_preview)
imgui.pop_text_wrap_pos()
else:
imgui.text_unformatted(content_preview)
imgui.table_next_column()
if imgui.button(f"View##{i}"):
self.text_viewer_title = f"Log Entry #{i_display} ({msg_kind})"
self.text_viewer_content = full_content
self.show_text_viewer = True
imgui.end_table()
if self._scroll_comms_to_bottom: if self._scroll_comms_to_bottom:
# Table with scroll_y handles its own scrolling imgui.set_scroll_here_y(1.0)
# We might need ed.set_scroll_y or similar if we wanted precise control self._scroll_comms_to_bottom = False
# but usually imgui.set_scroll_here_y works inside the table
pass
imgui.end_child()
if self.is_viewing_prior_session: if self.is_viewing_prior_session:
imgui.pop_style_color() imgui.pop_style_color()
@@ -1993,9 +1995,10 @@ class App:
imgui.separator() imgui.separator()
ch1, self.ui_separate_message_panel = imgui.checkbox("Separate Message Panel", self.ui_separate_message_panel) ch1, self.ui_separate_message_panel = imgui.checkbox("Separate Message Panel", self.ui_separate_message_panel)
ch2, self.ui_separate_response_panel = imgui.checkbox("Separate Response Panel", self.ui_separate_response_panel) ch2, self.ui_separate_response_panel = imgui.checkbox("Separate Response Panel", self.ui_separate_response_panel)
ch3, self.ui_separate_tool_calls_panel = imgui.checkbox("Separate Tool Calls Panel", self.ui_separate_tool_calls_panel)
if ch1: self.show_windows["Message"] = self.ui_separate_message_panel if ch1: self.show_windows["Message"] = self.ui_separate_message_panel
if ch2: self.show_windows["Response"] = self.ui_separate_response_panel if ch2: self.show_windows["Response"] = self.ui_separate_response_panel
if ch3: self.show_windows["Tool Calls"] = self.ui_separate_tool_calls_panel
imgui.separator() imgui.separator()
imgui.text("Font") imgui.text("Font")
imgui.push_item_width(-150) imgui.push_item_width(-150)