gemini 3.1 fails

This commit is contained in:
2026-05-12 19:50:46 -04:00
parent 87aeee3322
commit ff1a9d77f7
2 changed files with 425 additions and 438 deletions
+389 -438
View File
@@ -15,7 +15,7 @@ import threading
import time import time
# from defer import defer # from defer import defer
import tomli_w import tomli_w
# from contextlib import ExitStack # from contextlib import ExitStack, nullcontext
import traceback import traceback
import typing import typing
from pathlib import Path from pathlib import Path
@@ -605,53 +605,53 @@ class App:
def _render_thinking_trace(self, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None: def _render_thinking_trace(self, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
if not segments: if not segments:
return return
imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)) with imscope.style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)), \
imgui.push_style_color(imgui.Col_.text, vec4(200, 200, 150)) imscope.style_color(imgui.Col_.text, vec4(200, 200, 150)):
imgui.indent() imgui.indent()
show_content = True show_content = True
if not is_standalone: if not is_standalone:
header_label = f"Monologue ({len(segments)} traces)###thinking_header_{entry_index}" header_label = f"Monologue ({len(segments)} traces)###thinking_header_{entry_index}"
show_content = imgui.collapsing_header(header_label) show_content = imgui.collapsing_header(header_label)
if show_content: if show_content:
h = 150 if is_standalone else 100 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}", imgui.ImVec2(0, h), True):
for idx, seg in enumerate(segments): for idx, seg in enumerate(segments):
content = seg.get("content", "") content = seg.get("content", "")
marker = seg.get("marker", "thinking") marker = seg.get("marker", "thinking")
with imscope.id(f"think_{entry_index}_{idx}"): with imscope.id(f"think_{entry_index}_{idx}"):
imgui.text_colored(vec4(180, 150, 80), f"[{marker}]") imgui.text_colored(vec4(180, 150, 80), f"[{marker}]")
if self.ui_word_wrap: if self.ui_word_wrap:
imscope.text_wrap(imgui.get_content_region_avail().x) with imscope.text_wrap(imgui.get_content_region_avail().x):
imgui.text_colored(vec4(200, 200, 150), content) imgui.text_colored(vec4(200, 200, 150), content)
else: else:
imgui.text_colored(vec4(200, 200, 150), content) imgui.text_colored(vec4(200, 200, 150), content)
imgui.separator() imgui.separator()
imgui.unindent() imgui.unindent()
imgui.pop_style_color(2)
def _render_selectable_label(self, label: str, value: str, width: float = 0.0, multiline: bool = False, height: float = 0.0, color: Optional[imgui.ImVec4] = None) -> None: def _render_selectable_label(self, label: str, value: str, width: float = 0.0, multiline: bool = False, height: float = 0.0, color: Optional[imgui.ImVec4] = None) -> None:
imgui.push_id(label + str(hash(value))) with imscope.id(label + str(hash(value))):
pops = 4 with imscope.style_color(imgui.Col_.frame_bg, vec4(0, 0, 0, 0)), \
imgui.push_style_color(imgui.Col_.frame_bg, vec4(0, 0, 0, 0)) imscope.style_color(imgui.Col_.frame_bg_hovered, vec4(0, 0, 0, 0)), \
imgui.push_style_color(imgui.Col_.frame_bg_hovered, vec4(0, 0, 0, 0)) imscope.style_color(imgui.Col_.frame_bg_active, vec4(0, 0, 0, 0)), \
imgui.push_style_color(imgui.Col_.frame_bg_active, vec4(0, 0, 0, 0)) imscope.style_color(imgui.Col_.border, vec4(0, 0, 0, 0)):
imgui.push_style_color(imgui.Col_.border, vec4(0, 0, 0, 0)) with imscope.style_var(imgui.StyleVar_.frame_border_size, 0.0), \
if color: imscope.style_var(imgui.StyleVar_.frame_padding, imgui.ImVec2(0, 0)):
imgui.push_style_color(imgui.Col_.text, color) if color:
pops += 1 with imscope.style_color(imgui.Col_.text, color):
imgui.push_style_var(imgui.StyleVar_.frame_border_size, 0.0) if multiline:
imgui.push_style_var(imgui.StyleVar_.frame_padding, imgui.ImVec2(0, 0)) imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only)
if multiline: else:
imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only) if width > 0: imgui.set_next_item_width(width)
else: imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only)
if width > 0: imgui.set_next_item_width(width) else:
imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only) if multiline:
imgui.pop_style_color(pops) imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only)
imgui.pop_style_var(2) else:
imgui.pop_id() if width > 0: imgui.set_next_item_width(width)
imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only)
def _render_window_if_open(self, name: str, render_func: Callable[[], None], flag_condition: bool = True) -> None: def _render_window_if_open(self, name: str, render_func: Callable[[], None], flag_condition: bool = True) -> None:
"""Helper to render a window only if its toggle is active.""" """Helper to render a window only if its toggle is active."""
@@ -1220,34 +1220,30 @@ class App:
imgui.text_colored(c, "THINKING..."); imgui.same_line() imgui.text_colored(c, "THINKING..."); imgui.same_line()
def _render_prior_session_view(self) -> None: def _render_prior_session_view(self) -> None:
imgui.push_style_color(imgui.Col_.child_bg, vec4(50, 40, 20)) with imscope.style_color(imgui.Col_.child_bg, vec4(50, 40, 20)):
if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True
imgui.separator() imgui.separator()
with imscope.child("prior_scroll"): with imscope.child("prior_scroll"):
clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries)) clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries))
while clipper.step(): while clipper.step():
for idx in range(clipper.display_start, clipper.display_end): for idx in range(clipper.display_start, clipper.display_end):
entry = self.prior_disc_entries[idx]; entry = self.prior_disc_entries[idx];
with imscope.id(f"prior_disc_{idx}"): with imscope.id(f"prior_disc_{idx}"):
collapsed = entry.get("collapsed", False) collapsed = entry.get("collapsed", False)
if imgui.button("+" if collapsed else "-"): entry["collapsed"] = not collapsed if imgui.button("+" if collapsed else "-"): entry["collapsed"] = not collapsed
imgui.same_line(); role, ts = entry.get("role", "??"), entry.get("ts", "") imgui.same_line(); role, ts = entry.get("role", "??"), entry.get("ts", "")
imgui.text_colored(C_LBL, f"[{role}]") imgui.text_colored(C_LBL, f"[{role}]")
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts)) if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
content = entry.get("content", "") content = entry.get("content", "")
if collapsed: if collapsed:
imgui.same_line(); preview = content.replace("\n", " ")[:80] imgui.same_line(); preview = content.replace("\n", " ")[:80]
if len(content) > 80: preview += "..." if len(content) > 80: preview += "..."
imgui.text_colored(vec4(180, 180, 180), preview) imgui.text_colored(vec4(180, 180, 180), preview)
else: else:
is_nerv = theme.is_nerv_active() is_nerv = theme.is_nerv_active()
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) with imscope.style_color(imgui.Col_.text, vec4(80, 255, 80)) if is_nerv else nullcontext():
markdown_helper.render(content, context_id=f'prior_disc_{idx}') markdown_helper.render(content, context_id=f'prior_disc_{idx}')
if is_nerv: imgui.pop_style_color() imgui.separator()
imgui.separator()
imgui.pop_style_color()
def _render_discussion_selector(self) -> None:
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return
names = self._get_discussion_names(); grouped = {} names = self._get_discussion_names(); grouped = {}
for name in names: for name in names:
@@ -2204,11 +2200,12 @@ class App:
if not self.show_preset_manager_window and not is_embedded: return if not self.show_preset_manager_window and not is_embedded: return
if not is_embedded: if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
opened, self.show_preset_manager_window = imgui.begin("Prompt Presets Manager", self.show_preset_manager_window) with imscope.window("Prompt Presets Manager", self.show_preset_manager_window) as (opened, visible):
if not opened: self.show_preset_manager_window = visible
imgui.end(); return if opened:
self._render_preset_manager_content(is_embedded=is_embedded) self._render_preset_manager_content(is_embedded=is_embedded)
if not is_embedded: imgui.end() else:
self._render_preset_manager_content(is_embedded=is_embedded)
def _render_tool_preset_manager_content(self, is_embedded: bool = False) -> None: def _render_tool_preset_manager_content(self, is_embedded: bool = False) -> None:
avail = imgui.get_content_region_avail() avail = imgui.get_content_region_avail()
@@ -2382,16 +2379,16 @@ class App:
if not is_embedded: if not is_embedded:
if imgui.button("Close##tp", imgui.ImVec2(100, 0)): self.show_tool_preset_manager_window = False if imgui.button("Close##tp", imgui.ImVec2(100, 0)): self.show_tool_preset_manager_window = False
imgui.end_table() imgui.end_table()
def _render_tool_preset_manager_window(self, is_embedded: bool = False) -> None: def _render_tool_preset_manager_window(self, is_embedded: bool = False) -> None:
if not self.show_tool_preset_manager_window and not is_embedded: return if not self.show_tool_preset_manager_window and not is_embedded: return
if not is_embedded: if not is_embedded:
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever) imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
opened, self.show_tool_preset_manager_window = imgui.begin("Tool Preset Manager", self.show_tool_preset_manager_window) with imscope.window("Tool Preset Manager", self.show_tool_preset_manager_window) as (opened, visible):
if not opened: self.show_tool_preset_manager_window = visible
imgui.end(); return if opened:
self._render_tool_preset_manager_content(is_embedded=is_embedded) self._render_tool_preset_manager_content(is_embedded=is_embedded)
if not is_embedded: imgui.end() else:
self._render_preset_manager_content(is_embedded=is_embedded)
def _render_persona_editor_window(self, is_embedded: bool = False) -> None: def _render_persona_editor_window(self, is_embedded: bool = False) -> None:
if not self.show_persona_editor_window and not is_embedded: return if not self.show_persona_editor_window and not is_embedded: return
@@ -2557,7 +2554,6 @@ class App:
if imgui.button("Close##pers", imgui.ImVec2(100, 0)): if imgui.button("Close##pers", imgui.ImVec2(100, 0)):
self.show_persona_editor_window = False self.show_persona_editor_window = False
imgui.end_table() imgui.end_table()
if not is_embedded: imgui.end()
def _render_projects_panel(self) -> None: def _render_projects_panel(self) -> None:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_projects_panel") if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_projects_panel")
@@ -2908,192 +2904,183 @@ class App:
[C: tests/test_log_management_ui.py:test_render_log_management_logic] [C: tests/test_log_management_ui.py:test_render_log_management_logic]
""" """
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_log_management") if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_log_management")
exp, opened = imgui.begin("Log Management", self.show_windows["Log Management"]) with imscope.window("Log Management", self.show_windows["Log Management"]) as (exp, opened):
self.show_windows["Log Management"] = bool(opened) self.show_windows["Log Management"] = bool(opened)
if not exp: if exp:
imgui.end() if self._log_registry is None:
return self._log_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:
if imgui.button("Refresh Registry"):
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
imgui.same_line()
if imgui.button("Load Log"):
self.cb_load_prior_log()
imgui.same_line()
if imgui.button("Force Prune Logs"):
self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
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")
imgui.table_setup_column("Start Time")
imgui.table_setup_column("Star")
imgui.table_setup_column("Reason")
imgui.table_setup_column("Size (KB)")
imgui.table_setup_column("Msgs")
imgui.table_setup_column("Actions")
imgui.table_headers_row()
for session_id, s_data in sessions.items():
imgui.table_next_row()
imgui.table_next_column()
imgui.text(session_id)
imgui.table_next_column()
imgui.text(s_data.get("start_time", ""))
imgui.table_next_column()
whitelisted = s_data.get("whitelisted", False)
if whitelisted:
imgui.text_colored(vec4(255, 215, 0), "YES")
else: else:
imgui.text("NO") if imgui.button("Refresh Registry"):
metadata = s_data.get("metadata") or {} self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
imgui.table_next_column() imgui.same_line()
imgui.text(metadata.get("reason", "")) if imgui.button("Load Log"):
imgui.table_next_column() self.cb_load_prior_log()
imgui.text(str(metadata.get("size_kb", "")))
imgui.table_next_column()
imgui.text(str(metadata.get("message_count", "")))
imgui.table_next_column()
if imgui.button(f"Load##{session_id}"):
self.cb_load_prior_log(s_data.get("path"))
imgui.same_line() imgui.same_line()
if whitelisted: if imgui.button("Force Prune Logs"):
if imgui.button(f"Unstar##{session_id}"): self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
registry.update_session_metadata(
session_id, registry = self._log_registry
message_count=int(metadata.get("message_count") or 0), sessions = registry.data
errors=int(metadata.get("errors") or 0), if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
size_kb=int(metadata.get("size_kb") or 0), imgui.table_setup_column("Session ID")
whitelisted=False, imgui.table_setup_column("Start Time")
reason=str(metadata.get("reason") or "") imgui.table_setup_column("Star")
) imgui.table_setup_column("Reason")
else: imgui.table_setup_column("Size (KB)")
if imgui.button(f"Star##{session_id}"): imgui.table_setup_column("Msgs")
registry.update_session_metadata( imgui.table_setup_column("Actions")
session_id, imgui.table_headers_row()
message_count=int(metadata.get("message_count") or 0), for session_id, s_data in sessions.items():
errors=int(metadata.get("errors") or 0), imgui.table_next_row()
size_kb=int(metadata.get("size_kb") or 0), imgui.table_next_column()
whitelisted=True, imgui.text(session_id)
reason="Manually whitelisted" imgui.table_next_column()
) imgui.text(s_data.get("start_time", ""))
imgui.end_table() imgui.table_next_column()
whitelisted = s_data.get("whitelisted", False)
if whitelisted:
imgui.text_colored(vec4(255, 215, 0), "YES")
else:
imgui.text("NO")
metadata = s_data.get("metadata") or {}
imgui.table_next_column()
imgui.text(metadata.get("reason", ""))
imgui.table_next_column()
imgui.text(str(metadata.get("size_kb", "")))
imgui.table_next_column()
imgui.text(str(metadata.get("message_count", "")))
imgui.table_next_column()
if imgui.button(f"Load##{session_id}"):
self.cb_load_prior_log(s_data.get("path"))
imgui.same_line()
if whitelisted:
if imgui.button(f"Unstar##{session_id}"):
registry.update_session_metadata(
session_id,
message_count=int(metadata.get("message_count") or 0),
errors=int(metadata.get("errors") or 0),
size_kb=int(metadata.get("size_kb") or 0),
whitelisted=False,
reason=str(metadata.get("reason") or "")
)
else:
if imgui.button(f"Star##{session_id}"):
registry.update_session_metadata(
session_id,
message_count=int(metadata.get("message_count") or 0),
errors=int(metadata.get("errors") or 0),
size_kb=int(metadata.get("size_kb") or 0),
whitelisted=True,
reason="Manually whitelisted"
)
imgui.end_table()
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management")
imgui.end()
def _render_diagnostics_panel(self) -> None: def _render_diagnostics_panel(self) -> None:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_diagnostics_panel") if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_diagnostics_panel")
exp, opened = imgui.begin("Diagnostics", self.show_windows.get("Diagnostics", False)) with imscope.window("Diagnostics", self.show_windows.get("Diagnostics", False)) as (exp, opened):
self.show_windows["Diagnostics"] = bool(opened) self.show_windows["Diagnostics"] = bool(opened)
if not exp: if exp:
imgui.end() metrics = self.perf_monitor.get_metrics()
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel") imgui.text("Performance Telemetry")
return imgui.same_line()
_, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled)
metrics = self.perf_monitor.get_metrics() imgui.separator()
imgui.text("Performance Telemetry")
imgui.same_line() if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h):
_, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled) imgui.table_setup_column("Metric")
imgui.separator() imgui.table_setup_column("Value")
imgui.table_setup_column("Graph")
if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h): imgui.table_headers_row()
imgui.table_setup_column("Metric")
imgui.table_setup_column("Value") for label, key, format_str in [
imgui.table_setup_column("Graph") ("FPS", "fps", "%.1f"),
imgui.table_headers_row() ("Frame Time (ms)", "frame_time_ms", "%.2f"),
("CPU %", "cpu_percent", "%.1f"),
for label, key, format_str in [ ("Input Lag (ms)", "input_lag_ms", "%.1f")
("FPS", "fps", "%.1f"), ]:
("Frame Time (ms)", "frame_time_ms", "%.2f"),
("CPU %", "cpu_percent", "%.1f"),
("Input Lag (ms)", "input_lag_ms", "%.1f")
]:
imgui.table_next_row()
imgui.table_next_column()
imgui.text(label)
imgui.table_next_column()
if key == "fps":
avg_val = imgui.get_io().framerate
else:
avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0))
imgui.text(format_str % avg_val)
imgui.table_next_column()
self.perf_show_graphs.setdefault(key, False)
_, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key])
imgui.end_table()
if self.perf_profiling_enabled:
imgui.separator()
imgui.text("Detailed Component Timings (Moving Average)")
if imgui.begin_table("comp_timings", 6, imgui.TableFlags_.borders):
imgui.table_setup_column("Component")
imgui.table_setup_column("Avg (ms)")
imgui.table_setup_column("Count")
imgui.table_setup_column("Max (ms)")
imgui.table_setup_column("Min (ms)")
imgui.table_setup_column("Graph")
imgui.table_headers_row()
for key, val in metrics.items():
if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"):
comp_name = key[5:-3]
avg_val = metrics.get(f"{key}_avg", val)
count = int(metrics.get(f"count_{comp_name}", 0))
max_val = metrics.get(f"max_{comp_name}_ms", 0.0)
min_val = metrics.get(f"min_{comp_name}_ms", 0.0)
imgui.table_next_row() imgui.table_next_row()
imgui.table_next_column() imgui.table_next_column()
imgui.text(comp_name) imgui.text(label)
imgui.table_next_column() imgui.table_next_column()
if avg_val > 10.0: if key == "fps":
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}") avg_val = imgui.get_io().framerate
else: else:
imgui.text(f"{avg_val:.2f}") avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0))
imgui.text(format_str % avg_val)
imgui.table_next_column() imgui.table_next_column()
imgui.text(f"{count}") self.perf_show_graphs.setdefault(key, False)
imgui.table_next_column() _, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key])
imgui.text(f"{max_val:.2f}") imgui.end_table()
imgui.table_next_column()
imgui.text(f"{min_val:.2f}")
imgui.table_next_column()
self.perf_show_graphs.setdefault(comp_name, False)
_, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name])
imgui.end_table()
imgui.separator() if self.perf_profiling_enabled:
imgui.text("Performance Graphs") imgui.separator()
for key, show in self.perf_show_graphs.items(): imgui.text("Detailed Component Timings (Moving Average)")
if show: if imgui.begin_table("comp_timings", 6, imgui.TableFlags_.borders):
imgui.text(f"History: {key}") imgui.table_setup_column("Component")
hist_data = self.perf_monitor.get_history(key) imgui.table_setup_column("Avg (ms)")
if hist_data: imgui.table_setup_column("Count")
import numpy as np imgui.table_setup_column("Max (ms)")
imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60)) imgui.table_setup_column("Min (ms)")
else: imgui.table_setup_column("Graph")
imgui.text_disabled(f"(no history data for {key})") imgui.table_headers_row()
for key, val in metrics.items():
if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"):
comp_name = key[5:-3]
avg_val = metrics.get(f"{key}_avg", val)
count = int(metrics.get(f"count_{comp_name}", 0))
max_val = metrics.get(f"max_{comp_name}_ms", 0.0)
min_val = metrics.get(f"min_{comp_name}_ms", 0.0)
imgui.table_next_row()
imgui.table_next_column()
imgui.text(comp_name)
imgui.table_next_column()
if avg_val > 10.0:
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}")
else:
imgui.text(f"{avg_val:.2f}")
imgui.table_next_column()
imgui.text(f"{count}")
imgui.table_next_column()
imgui.text(f"{max_val:.2f}")
imgui.table_next_column()
imgui.text(f"{min_val:.2f}")
imgui.table_next_column()
self.perf_show_graphs.setdefault(comp_name, False)
_, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name])
imgui.end_table()
imgui.separator() imgui.separator()
imgui.text("Diagnostic Log") imgui.text("Performance Graphs")
if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable): for key, show in self.perf_show_graphs.items():
imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150) if show:
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100) imgui.text(f"History: {key}")
imgui.table_setup_column("Message") hist_data = self.perf_monitor.get_history(key)
imgui.table_headers_row() if hist_data:
for entry in reversed(self.controller.diagnostic_log): import numpy as np
imgui.table_next_row() imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60))
imgui.table_next_column() else:
imgui.text(entry.get("ts", "")) imgui.text_disabled(f"(no history data for {key})")
imgui.table_next_column()
imgui.text(entry.get("type", "")) imgui.separator()
imgui.table_next_column() imgui.text("Diagnostic Log")
imgui.text_wrapped(entry.get("message", "")) if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
imgui.end_table() imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150)
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100)
imgui.table_setup_column("Message")
imgui.table_headers_row()
for entry in reversed(self.controller.diagnostic_log):
imgui.table_next_row()
imgui.table_next_column()
imgui.text(entry.get("ts", ""))
imgui.table_next_column()
imgui.text(entry.get("type", ""))
imgui.table_next_column()
imgui.text_wrapped(entry.get("message", ""))
imgui.end_table()
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel")
imgui.end()
def _render_discussion_tab(self) -> None: def _render_discussion_tab(self) -> None:
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h)) imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
@@ -3215,118 +3202,116 @@ class App:
grouped_files = aggregate.group_files_by_dir(self.context_files) grouped_files = aggregate.group_files_by_dir(self.context_files)
if imgui.begin_table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders): with imscope.table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders) as active:
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch) if active:
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200) imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
imgui.table_headers_row() imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
imgui.table_headers_row()
file_indices = {id(f): idx for idx, f in enumerate(self.context_files)}
file_indices = {id(f): idx for idx, f in enumerate(self.context_files)}
for dir_name, g_files in grouped_files.items():
imgui.table_next_row() for dir_name, g_files in grouped_files.items():
imgui.table_set_column_index(0) imgui.table_next_row()
is_open = imgui.tree_node_ex(f"{dir_name}##dir_{dir_name}", imgui.TreeNodeFlags_.default_open) imgui.table_set_column_index(0)
imgui.table_set_column_index(1) with imscope.tree_node_ex(f"{dir_name}##dir_{dir_name}", imgui.TreeNodeFlags_.default_open) as is_open:
if is_open:
for f_item in g_files:
i = file_indices[id(f_item)]
imgui.table_next_row()
imgui.table_set_column_index(0)
# Checkbox for selection
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
is_sel = f_path in self.ui_selected_context_files
changed_sel, is_sel = imgui.checkbox(f"##sel{i}", is_sel)
if changed_sel:
if imgui.get_io().key_shift and self._last_selected_context_index != -1:
start = min(self._last_selected_context_index, i)
end = max(self._last_selected_context_index, i)
for idx in range(start, end + 1):
item = self.context_files[idx]
item_path = item.path if hasattr(item, "path") else str(item)
if is_sel:
self.ui_selected_context_files.add(item_path)
else:
self.ui_selected_context_files.discard(item_path)
else:
if is_sel:
self.ui_selected_context_files.add(f_path)
else:
self.ui_selected_context_files.discard(f_path)
self._last_selected_context_index = i
imgui.same_line()
mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0
cache_key = f"{f_path}_{mtime}"
stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0})
f_name = os.path.basename(f_path)
imgui.text(f"{f_name} (L: {stats.get('lines', 0)}, AST: {stats.get('ast_elements', 0)})")
if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')):
imgui.same_line()
if imgui.button(f"[Inspect]##{i}"):
self.ui_inspecting_ast_file = f_item
self._show_ast_inspector = True
imgui.same_line()
if imgui.button(f"[Slices]##{i}"):
self.ui_editing_slices_file = f_item
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
self.text_viewer_title = f"Slices: {f_path}"
try:
self.text_viewer_content = mcp_client.read_file(f_path)
except Exception as e:
self.text_viewer_content = f"Error reading file: {e}"
self.text_viewer_type = 'cpp' if f_path.endswith(('.cpp', '.hpp', '.h')) else 'python' if f_path.endswith('.py') else 'text'
self.show_text_viewer = True
imgui.table_set_column_index(1) imgui.table_set_column_index(1)
if not hasattr(f_item, "view_mode"): if is_open:
f_item.view_mode = "summary" for f_item in g_files:
view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"] i = file_indices[id(f_item)]
try: imgui.table_next_row()
current_idx = view_modes.index(f_item.view_mode) imgui.table_set_column_index(0)
except ValueError:
current_idx = 1 # Checkbox for selection
f_item.view_mode = "summary" f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
imgui.set_next_item_width(120) is_sel = f_path in self.ui_selected_context_files
changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes) changed_sel, is_sel = imgui.checkbox(f"##sel{i}", is_sel)
if changed_vm: if changed_sel:
f_item.view_mode = view_modes[new_idx] if imgui.get_io().key_shift and self._last_selected_context_index != -1:
start = min(self._last_selected_context_index, i)
imgui.same_line() end = max(self._last_selected_context_index, i)
if imgui.button(f"[Save]##vpsave{i}"): for idx in range(start, end + 1):
imgui.open_popup(f"save_vp_popup{i}") item = self.context_files[idx]
item_path = item.path if hasattr(item, "path") else str(item)
if imgui.begin_popup(f"save_vp_popup{i}"): if is_sel:
imgui.text("Preset Name:") self.ui_selected_context_files.add(item_path)
changed_pname, self.ui_new_vp_name = imgui.input_text(f"##pname{i}", self.ui_new_vp_name) else:
if imgui.button("OK"): self.ui_selected_context_files.discard(item_path)
if self.ui_new_vp_name.strip(): else:
self.controller._cb_save_view_preset(self.ui_new_vp_name.strip(), f_item) if is_sel:
self.ui_new_vp_name = "" self.ui_selected_context_files.add(f_path)
imgui.close_current_popup() else:
imgui.end_popup() self.ui_selected_context_files.discard(f_path)
self._last_selected_context_index = i
imgui.same_line()
mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0
cache_key = f"{f_path}_{mtime}"
stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0})
f_name = os.path.basename(f_path)
imgui.text(f"{f_name} (L: {stats.get('lines', 0)}, AST: {stats.get('ast_elements', 0)})")
imgui.same_line() if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')):
if imgui.button(f"[Load]##vpload{i}"): imgui.same_line()
imgui.open_popup(f"load_vp_popup{i}") if imgui.button(f"[Inspect]##{i}"):
self.ui_inspecting_ast_file = f_item
if imgui.begin_popup(f"load_vp_popup{i}"): self._show_ast_inspector = True
vp_names = sorted([vp.name for vp in self.controller.view_presets])
if not vp_names: imgui.same_line()
imgui.text("No presets saved.") if imgui.button(f"[Slices]##{i}"):
for vp_name in vp_names: self.ui_editing_slices_file = f_item
if imgui.selectable(vp_name): f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
self.controller._cb_apply_view_preset(vp_name, f_item) self.text_viewer_title = f"Slices: {f_path}"
imgui.close_current_popup() try:
imgui.end_popup() self.text_viewer_content = mcp_client.read_file(f_path)
if hasattr(f_item, "custom_slices") and f_item.custom_slices: except Exception as e:
imgui.same_line() self.text_viewer_content = f"Error reading file: {e}"
imgui.text_colored(imgui.ImVec4(1.0, 0.5, 0.0, 1.0), "[Slices Active]") self.text_viewer_type = 'cpp' if f_path.endswith(('.cpp', '.hpp', '.h')) else 'python' if f_path.endswith('.py') else 'text'
imgui.tree_pop() self.show_text_viewer = True
imgui.end_table() imgui.table_set_column_index(1)
if not hasattr(f_item, "view_mode"):
f_item.view_mode = "summary"
view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"]
try:
current_idx = view_modes.index(f_item.view_mode)
except ValueError:
current_idx = 1
f_item.view_mode = "summary"
imgui.set_next_item_width(120)
changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes)
if changed_vm:
f_item.view_mode = view_modes[new_idx]
imgui.same_line()
if imgui.button(f"[Save]##vpsave{i}"):
imgui.open_popup(f"save_vp_popup{i}")
if imgui.begin_popup(f"save_vp_popup{i}"):
imgui.text("Preset Name:")
changed_pname, self.ui_new_vp_name = imgui.input_text(f"##pname{i}", self.ui_new_vp_name)
if imgui.button("OK"):
if self.ui_new_vp_name.strip():
self.controller._cb_save_view_preset(self.ui_new_vp_name.strip(), f_item)
self.ui_new_vp_name = ""
imgui.close_current_popup()
imgui.end_popup()
imgui.same_line()
if imgui.button(f"[Load]##vpload{i}"):
imgui.open_popup(f"load_vp_popup{i}")
if imgui.begin_popup(f"load_vp_popup{i}"):
vp_names = sorted([vp.name for vp in self.controller.view_presets])
if not vp_names:
imgui.text("No presets saved.")
for vp_name in vp_names:
if imgui.selectable(vp_name):
self.controller._cb_apply_view_preset(vp_name, f_item)
imgui.close_current_popup()
imgui.end_popup()
if hasattr(f_item, "custom_slices") and f_item.custom_slices:
imgui.same_line()
imgui.text_colored(imgui.ImVec4(1.0, 0.5, 0.0, 1.0), "[Slices Active]")
# Context Composition collasping header # Context Composition collasping header
imgui.separator() imgui.separator()
@@ -4078,53 +4063,47 @@ def hello():
self._handle_reset_session() self._handle_reset_session()
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_message_panel") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_message_panel")
def _render_response_panel(self) -> None: def _render_response_panel(self) -> None:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_response_panel") if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_response_panel")
if self._trigger_blink: if self._trigger_blink:
self._trigger_blink = False self._trigger_blink = False
self._is_blinking = True self._is_blinking = True
self._blink_start_time = time.time() self._blink_start_time = time.time()
try: try:
imgui.set_window_focus("Response") # type: ignore[call-arg] imgui.set_window_focus("Response") # type: ignore[call-arg]
except: except:
pass pass
is_blinking = False is_blinking = False
if self._is_blinking: blink_color = vec4(0, 0, 0, 0)
elapsed = time.time() - self._blink_start_time if self._is_blinking:
if elapsed > 1.5: elapsed = time.time() - self._blink_start_time
self._is_blinking = False if elapsed > 1.5:
else: self._is_blinking = False
is_blinking = True else:
val = math.sin(elapsed * 8 * math.pi) is_blinking = True
alpha = 50/255 if val > 0 else 0 val = math.sin(elapsed * 8 * math.pi)
imgui.push_style_color(imgui.Col_.frame_bg, vec4(0, 255, 0, alpha)) alpha = 50/255 if val > 0 else 0
imgui.push_style_color(imgui.Col_.child_bg, vec4(0, 255, 0, alpha)) blink_color = vec4(0, 255, 0, alpha)
# --- Always Render Content ---
with imscope.style_color(imgui.Col_.frame_bg, blink_color) if is_blinking else nullcontext():
imgui.begin_child("response_scroll_area", imgui.ImVec2(0, -40), True) with imscope.style_color(imgui.Col_.child_bg, blink_color) if is_blinking else nullcontext():
is_nerv = theme.is_nerv_active() with imscope.child("response_scroll_area", imgui.ImVec2(0, -40), True):
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) is_nerv = theme.is_nerv_active()
with imscope.style_color(imgui.Col_.text, vec4(80, 255, 80)) if is_nerv else nullcontext():
segments, parsed_response = thinking_parser.parse_thinking_trace(self.ai_response) segments, parsed_response = thinking_parser.parse_thinking_trace(self.ai_response)
if segments: if segments:
self._render_thinking_trace([{"content": s.content, "marker": s.marker} for s in segments], 9999) self._render_thinking_trace([{"content": s.content, "marker": s.marker} for s in segments], 9999)
markdown_helper.render(parsed_response, context_id="response")
markdown_helper.render(parsed_response, context_id="response")
imgui.separator()
if is_nerv: imgui.pop_style_color() if imgui.button("-> History"):
imgui.end_child() if self.ai_response:
segments, response = thinking_parser.parse_thinking_trace(self.ai_response)
imgui.separator() entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()}
if imgui.button("-> History"): if segments:
if self.ai_response: entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
segments, response = thinking_parser.parse_thinking_trace(self.ai_response) self.disc_entries.append(entry)
entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()} if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel")
if segments:
entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
self.disc_entries.append(entry)
if is_blinking:
imgui.pop_style_color(2)
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel")
def _render_external_tools_panel(self) -> None: def _render_external_tools_panel(self) -> None:
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel") if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel")
@@ -5188,34 +5167,6 @@ def hello():
imgui.end() imgui.end()
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_theme_panel") if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_theme_panel")
def _render_prior_session_view(self) -> None: imgui.push_style_color(imgui.Col_.child_bg, vec4(50, 40, 20))
if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True
imgui.separator()
with imscope.child("prior_scroll"):
clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries))
while clipper.step():
for idx in range(clipper.display_start, clipper.display_end):
entry = self.prior_disc_entries[idx];
with imscope.id(f"prior_disc_{idx}"):
collapsed = entry.get("collapsed", False)
if imgui.button("+" if collapsed else "-"): entry["collapsed"] = not collapsed
imgui.same_line(); role, ts = entry.get("role", "??"), entry.get("ts", "")
imgui.text_colored(C_LBL, f"[{role}]")
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
content = entry.get("content", "")
if collapsed:
imgui.same_line(); preview = content.replace("\n", " ")[:80]
if len(content) > 80: preview += "..."
imgui.text_colored(vec4(180, 180, 180), preview)
else:
is_nerv = theme.is_nerv_active()
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80))
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
if is_nerv: imgui.pop_style_color()
imgui.separator()
imgui.pop_style_color()
def _render_discussion_selector(self) -> None:
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return
names = self._get_discussion_names(); grouped = {} names = self._get_discussion_names(); grouped = {}
for name in names: for name in names:
+36
View File
@@ -160,3 +160,39 @@ class _ScopeTabItem:
if self._expanded: if self._expanded:
imgui.end_tab_item() imgui.end_tab_item()
return False return False
def style_color(col: int, val: Any): return _ScopeStyleColor(col, val)
class _ScopeStyleColor:
def __init__(self, col: int, val: Any):
self._col = col
self._val = val
def __enter__(self):
imgui.push_style_color(self._col, self._val)
def __exit__(self, *args):
imgui.pop_style_color()
return False
def style_var(var: int, val: Any): return _ScopeStyleVar(var, val)
class _ScopeStyleVar:
def __init__(self, var: int, val: Any):
self._var = var
self._val = val
def __enter__(self):
imgui.push_style_var(self._var, self._val)
def __exit__(self, *args):
imgui.pop_style_var()
return False
def tree_node_ex(label: str, flags: int = 0): return _ScopeTreeNodeEx(label, flags)
class _ScopeTreeNodeEx:
def __init__(self, label: str, flags: int):
self._label = label
self._flags = flags
self._opened = False
def __enter__(self):
self._opened = imgui.tree_node_ex(self._label, self._flags)
return self._opened
def __exit__(self, *args):
if self._opened:
imgui.tree_pop()
return False