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

View File

@@ -64,7 +64,7 @@ py_set_signature = false
py_set_var_declaration = false
[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]
epic = ""

View File

@@ -44,22 +44,19 @@ Collapsed=0
DockId=0x00000006,0
[Window][Message]
Pos=2058,1284
Size=1633,667
Pos=2830,1055
Size=954,371
Collapsed=0
[Window][Response]
Pos=1142,771
Size=567,866
Pos=2941,1527
Size=718,484
Collapsed=0
[Window][Tool Calls]
ViewportPos=43,95
ViewportId=0x78C57832
Pos=0,1121
Size=897,775
Pos=1300,926
Size=700,440
Collapsed=0
DockId=0x00000001,1
[Window][Comms History]
ViewportPos=43,95
@@ -67,7 +64,7 @@ ViewportId=0x78C57832
Pos=0,1121
Size=897,775
Collapsed=0
DockId=0x00000001,0
DockId=0x0000000B,0
[Window][System Prompts]
Pos=0,749
@@ -77,7 +74,7 @@ DockId=0xAFC85805,2
[Window][Theme]
Pos=0,17
Size=705,927
Size=705,960
Collapsed=0
DockId=0x00000005,1
@@ -88,13 +85,13 @@ Collapsed=0
[Window][Diagnostics]
Pos=707,17
Size=1122,443
Size=1358,379
Collapsed=0
DockId=0x0000001A,0
[Window][Context Hub]
Pos=0,17
Size=705,927
Size=705,960
Collapsed=0
DockId=0x00000005,0
@@ -105,26 +102,26 @@ Collapsed=0
DockId=0x0000000D,0
[Window][Discussion Hub]
Pos=1831,17
Size=1156,1507
Pos=2067,17
Size=920,1883
Collapsed=0
DockId=0x00000013,0
[Window][Operations Hub]
Pos=707,462
Size=1122,1062
Pos=707,398
Size=1358,1502
Collapsed=0
DockId=0x0000001B,0
[Window][Files & Media]
Pos=0,946
Size=705,1191
Pos=0,979
Size=705,1158
Collapsed=0
DockId=0x00000006,1
[Window][AI Settings]
Pos=0,946
Size=705,1191
Pos=0,979
Size=705,1158
Collapsed=0
DockId=0x00000006,0
@@ -151,26 +148,26 @@ Size=262,209
Collapsed=0
[Window][Tier 1: Strategy]
Pos=707,1526
Size=463,611
Pos=707,1902
Size=463,235
Collapsed=0
DockId=0x00000014,0
[Window][Tier 2: Tech Lead]
Pos=1172,1526
Size=730,611
Pos=1172,1902
Size=730,235
Collapsed=0
DockId=0x00000016,0
[Window][Tier 4: QA]
Pos=2453,1526
Size=534,611
Pos=2453,1902
Size=534,235
Collapsed=0
DockId=0x00000019,0
[Window][Tier 3: Workers]
Pos=1904,1526
Size=547,611
Pos=1904,1902
Size=547,235
Collapsed=0
DockId=0x00000018,0
@@ -184,6 +181,21 @@ Pos=60,60
Size=800,600
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]
RefScale=13
Column 0 Width=80
@@ -221,33 +233,47 @@ Column 1 Width=60
Column 2 Weight=1.0000
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]
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,17 Size=3840,2120 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=0x00000002 Parent=0x0000000B SizeRef=1029,1119 Split=X Selected=0xF4139CA2
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=705,858 Split=Y Selected=0x8CA2375C
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,927 Selected=0xF4139CA2
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,1191 CentralNode=1 Selected=0x7BD57D6A
DockNode ID=0x0000000E Parent=0x00000002 SizeRef=2280,858 Split=Y Selected=0x418C7449
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1507 Split=X Selected=0x418C7449
DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1122,402 Split=Y Selected=0xB4CBF21A
DockNode ID=0x0000001A Parent=0x00000012 SizeRef=1141,443 Selected=0xB4CBF21A
DockNode ID=0x0000001B Parent=0x00000012 SizeRef=1141,1062 Selected=0x418C7449
DockNode ID=0x00000013 Parent=0x00000010 SizeRef=1156,402 Selected=0x6F2B5B04
DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,611 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=463,837 Selected=0xBB346584
DockNode ID=0x00000015 Parent=0x00000011 SizeRef=1815,837 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000016 Parent=0x00000015 SizeRef=730,837 Selected=0x390E7942
DockNode ID=0x00000017 Parent=0x00000015 SizeRef=1083,837 Split=X Selected=0x655BC6E9
DockNode ID=0x00000018 Parent=0x00000017 SizeRef=547,874 Selected=0x655BC6E9
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=0x00000004 Parent=0xAFC85805 SizeRef=851,1183 Selected=0x3AEC3498
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,17 Size=3840,2120 Split=X
DockNode ID=0x00000003 Parent=0xAFC85805 SizeRef=2987,1183 Split=X
DockNode ID=0x0000000B Parent=0x00000003 SizeRef=404,1186 Split=X Selected=0xF4139CA2
DockNode ID=0x00000007 Parent=0x0000000B SizeRef=705,858 Split=Y Selected=0x8CA2375C
DockNode ID=0x00000005 Parent=0x00000007 SizeRef=295,960 Selected=0xF4139CA2
DockNode ID=0x00000006 Parent=0x00000007 SizeRef=295,1158 CentralNode=1 Selected=0x7BD57D6A
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=2280,858 Split=Y Selected=0x418C7449
DockNode ID=0x00000010 Parent=0x0000000E SizeRef=868,1883 Split=X Selected=0x418C7449
DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1358,402 Split=Y Selected=0xB4CBF21A
DockNode ID=0x0000001A Parent=0x00000012 SizeRef=1141,379 Selected=0xB4CBF21A
DockNode ID=0x0000001B Parent=0x00000012 SizeRef=1141,1502 Selected=0x418C7449
DockNode ID=0x00000013 Parent=0x00000010 SizeRef=920,402 Selected=0x6F2B5B04
DockNode ID=0x00000011 Parent=0x0000000E SizeRef=868,235 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=463,837 Selected=0xBB346584
DockNode ID=0x00000015 Parent=0x00000011 SizeRef=1815,837 Split=X Selected=0x5CDB7A4B
DockNode ID=0x00000016 Parent=0x00000015 SizeRef=730,837 Selected=0x390E7942
DockNode ID=0x00000017 Parent=0x00000015 SizeRef=1083,837 Split=X Selected=0x655BC6E9
DockNode ID=0x00000018 Parent=0x00000017 SizeRef=547,874 Selected=0x655BC6E9
DockNode ID=0x00000019 Parent=0x00000017 SizeRef=534,874 Selected=0x5CDB7A4B
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=435,1186 Selected=0x363E93D6
DockNode ID=0x00000004 Parent=0xAFC85805 SizeRef=851,1183 Selected=0x3AEC3498
;;;<<<Layout_655921752_Default>>>;;;
;;;<<<HelloImGui_Misc>>>;;;

View File

@@ -584,3 +584,51 @@ System:
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,
"Message": False,
"Response": False,
"Tool Calls": False,
"Theme": True,
"Log Management": False,
"Diagnostics": False,
@@ -1714,6 +1715,7 @@ class AppController:
"show_windows": self.show_windows,
"separate_message_panel": getattr(self, "ui_separate_message_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)

View File

@@ -107,11 +107,13 @@ class App:
gui_cfg = self.config.get("gui", {})
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_tool_calls_panel = gui_cfg.get("separate_tool_calls_panel", False)
self._comms_log_cache: list[dict[str, Any]] = []
self._comms_log_dirty: bool = True
self._tool_log_cache: list[dict[str, Any]] = []
self._tool_log_dirty: bool = True
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:
"""UI-level wrapper for approving a pending tool execution ask."""
@@ -426,15 +428,22 @@ class App:
if imgui.button("x##clear_focus"):
self.ui_focus_agent = None
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_item("Comms History")[0]:
self._render_comms_history_panel()
imgui.end_tab_item()
if imgui.begin_tab_item("Tool Calls")[0]:
self._render_tool_calls_panel()
imgui.end_tab_item()
if show_tc_tab:
if imgui.begin_tab_item("Tool Calls")[0]:
self._render_tool_calls_panel()
imgui.end_tab_item()
imgui.end_tab_bar()
imgui.end()
if self.ui_separate_message_panel and self.show_windows.get("Message", False):
@@ -451,6 +460,13 @@ class App:
self._render_response_panel()
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):
self._render_log_management()
if self.show_windows["Diagnostics"]:
@@ -863,7 +879,18 @@ class App:
if not exp:
imgui.end()
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
if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
imgui.table_setup_column("Session ID")
@@ -1145,6 +1172,8 @@ class App:
if imgui.button("+" if collapsed else "-"):
entry["collapsed"] = not collapsed
imgui.same_line()
self._render_text_viewer(f"Entry #{i+1}", entry["content"])
imgui.same_line()
imgui.set_next_item_width(120)
if imgui.begin_combo("##role", entry["role"]):
for r in self.disc_roles:
@@ -1164,8 +1193,6 @@ class App:
if imgui.button("Ins"):
self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()})
imgui.same_line()
self._render_text_viewer(f"Entry #{i+1}", entry["content"])
imgui.same_line()
if imgui.button("Del"):
self.disc_entries.pop(i)
imgui.pop_id()
@@ -1405,113 +1432,88 @@ class App:
self.ai_status = "idle"
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
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)
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()
clipper = imgui.ListClipper()
clipper.begin(len(log_to_render))
while clipper.step():
for i in range(clipper.display_start, clipper.display_end):
entry = log_to_render[i]
imgui.push_id(f"comms_entry_{i}")
i_display = i + 1
ts = entry.get("ts", "00:00:00")
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", {})
if not payload and kind not in ("request", "response", "tool_call", "tool_result"):
payload = entry # legacy
def payload_to_str(msg_kind, payload):
if msg_kind == "request":
return payload.get("message", "")
elif msg_kind == "response":
# Row 1: #Idx TS DIR KIND Provider/Model [Tier]
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}]")
# Optimized content rendering using _render_heavy_text logic
if kind == "request":
self._render_heavy_text("message", payload.get("message", ""))
elif kind == "response":
r = payload.get("round", 0)
sr = payload.get("stop_reason", "STOP")
text = payload.get("text", "")
imgui.text_colored(C_LBL, f"round: {r} stop_reason: {sr}")
self._render_heavy_text("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)
if tcs:
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:
self._render_heavy_text("data", str(payload))
clipper = imgui.ListClipper()
clipper.begin(len(log_to_render))
while clipper.step():
for i in range(clipper.display_start, clipper.display_end):
entry = log_to_render[i]
imgui.table_next_row()
i_display = i + 1
source = entry.get("source_tier", "main")
msg_kind = entry.get("kind", entry.get("type", "?")) # Handle legacy 'type'
payload = entry.get("payload", {})
if not payload and msg_kind not in ("request", "response", "tool_call", "tool_result"):
payload = entry # Legacy format where entry IS the payload
full_content = payload_to_str(msg_kind, payload)
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.table_next_column()
imgui.text_colored(C_SUB, f"[{source}]")
imgui.table_next_column()
imgui.text_colored(fg, msg_kind)
imgui.table_next_column()
elapsed = time.time() - entry.get("local_ts", 0)
if elapsed < 3.0:
blink = (math.sin(elapsed * 15) * 0.5 + 0.5)
imgui.text_colored(vec4(255, 255, 0, blink), "*")
else:
imgui.text("")
imgui.table_next_column()
if self.ui_word_wrap:
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()
imgui.separator()
imgui.pop_id()
if self._scroll_comms_to_bottom:
# Table with scroll_y handles its own scrolling
# We might need ed.set_scroll_y or similar if we wanted precise control
# but usually imgui.set_scroll_here_y works inside the table
pass
imgui.set_scroll_here_y(1.0)
self._scroll_comms_to_bottom = False
imgui.end_child()
if self.is_viewing_prior_session:
imgui.pop_style_color()
@@ -1993,9 +1995,10 @@ class App:
imgui.separator()
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)
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 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.text("Font")
imgui.push_item_width(-150)