fix(gui): Resolve AttributeError in imscope.indent and stabilize render loop

- Add 'indent' context manager to src/imgui_scopes.py.
- Refactor manual imgui.indent/unindent calls in src/gui_2.py to use imscope.indent.
- Fix cascading ImGui assertion failures caused by Open/Close mismatches during exceptions.
- Finalize 'Selectable Thinking Monologs' track.
This commit is contained in:
ed
2026-06-01 19:26:53 -04:00
parent c84777e582
commit 7a434adb7c
4 changed files with 62 additions and 53 deletions
+1 -1
View File
@@ -278,5 +278,5 @@ This file tracks all major tracks for the project. Each track has its own detail
--- ---
- [~] **Track: Selectable Thinking Monologs** - [x] **Track: Selectable Thinking Monologs**
*Link: [./tracks/selectable_thinking_monologs_20260601/](./tracks/selectable_thinking_monologs_20260601/)* *Link: [./tracks/selectable_thinking_monologs_20260601/](./tracks/selectable_thinking_monologs_20260601/)*
@@ -11,8 +11,8 @@
- [x] If `thinking_read_mode` is `False` (Pure mode), use `render_selectable_label(app, f"think_text_...", content, multiline=True, height=-1)` to make the text selectable and copyable. - [x] If `thinking_read_mode` is `False` (Pure mode), use `render_selectable_label(app, f"think_text_...", content, multiline=True, height=-1)` to make the text selectable and copyable.
## Phase 2: Verification ## Phase 2: Verification
- [ ] Task: Verification - [x] Task: Verification
- [ ] Verify that thinking traces in the Discussion Hub can be toggled between Pure and Read modes. - [x] Verify that thinking traces in the Discussion Hub can be toggled between Pure and Read modes.
- [ ] Verify that text can be selected and copied via Ctrl+C in Pure mode. - [x] Verify that text can be selected and copied via Ctrl+C in Pure mode.
- [ ] Verify that the change does not crash other areas rendering thinking traces (like Comms History). - [x] Verify that the change does not crash other areas rendering thinking traces (like Comms History).
- [ ] Task: Conductor - User Manual Verification 'Phase 2: Verification' (Protocol in workflow.md) - [x] Task: Conductor - User Manual Verification 'Phase 2: Verification' (Protocol in workflow.md)
+2 -4
View File
@@ -2517,7 +2517,7 @@ def render_persona_editor_window(app: App, is_embedded: bool = False) -> None:
imgui.same_line(imgui.get_content_region_avail().x - 30); imgui.same_line(imgui.get_content_region_avail().x - 30);
if imgui.button("x"): to_remove.append(i) if imgui.button("x"): to_remove.append(i)
if is_expanded: if is_expanded:
imgui.indent(20) with imscope.indent(20):
if imgui.begin_table("model_settings", 2, imgui.TableFlags_.borders_inner_v): if imgui.begin_table("model_settings", 2, imgui.TableFlags_.borders_inner_v):
imgui.table_setup_column("Label", imgui.TableColumnFlags_.width_fixed, 120); imgui.table_setup_column("Control", imgui.TableColumnFlags_.width_stretch) imgui.table_setup_column("Label", imgui.TableColumnFlags_.width_fixed, 120); imgui.table_setup_column("Control", imgui.TableColumnFlags_.width_stretch)
imgui.table_next_row(); imgui.table_next_column(); imgui.text("Provider:"); imgui.table_next_column(); imgui.set_next_item_width(-1) imgui.table_next_row(); imgui.table_next_column(); imgui.text("Provider:"); imgui.table_next_column(); imgui.set_next_item_width(-1)
@@ -2536,7 +2536,6 @@ def render_persona_editor_window(app: App, is_embedded: bool = False) -> None:
imgui.table_next_row(); imgui.table_next_column(); imgui.text("Max Tokens:"); imgui.table_next_column(); imgui.set_next_item_width(-1); _, entry["max_output_tokens"] = imgui.input_int("##maxt", entry.get("max_output_tokens", 4096)) imgui.table_next_row(); imgui.table_next_column(); imgui.text("Max Tokens:"); imgui.table_next_column(); imgui.set_next_item_width(-1); _, entry["max_output_tokens"] = imgui.input_int("##maxt", entry.get("max_output_tokens", 4096))
imgui.table_next_row(); imgui.table_next_column(); imgui.text("History Limit:"); imgui.table_next_column(); imgui.set_next_item_width(-1); _, entry["history_trunc_limit"] = imgui.input_int("##hist", entry.get("history_trunc_limit", 900000)) imgui.table_next_row(); imgui.table_next_column(); imgui.text("History Limit:"); imgui.table_next_column(); imgui.set_next_item_width(-1); _, entry["history_trunc_limit"] = imgui.input_int("##hist", entry.get("history_trunc_limit", 900000))
imgui.end_table() imgui.end_table()
imgui.unindent(20)
imgui.pop_id() imgui.pop_id()
for i in reversed(to_remove): app._editing_persona_preferred_models_list.pop(i) for i in reversed(to_remove): app._editing_persona_preferred_models_list.pop(i)
imgui.end_child() imgui.end_child()
@@ -4654,7 +4653,7 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind
return return
with imscope.style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)), \ with imscope.style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)), \
theme.ai_text_style(): theme.ai_text_style():
imgui.indent() with imscope.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}"
@@ -4681,7 +4680,6 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind
else: else:
render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1) render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1)
imgui.separator() imgui.separator()
imgui.unindent()
def render_selectable_label(app: App, 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(app: App, label: str, value: str, width: float = 0.0, multiline: bool = False, height: float = 0.0, color: Optional[imgui.ImVec4] = None) -> None:
with imscope.id(label + str(hash(value))): with imscope.id(label + str(hash(value))):
+11
View File
@@ -1,4 +1,5 @@
from __future__ import annotations from __future__ import annotations
from typing import Any
from imgui_bundle import imgui from imgui_bundle import imgui
from imgui_bundle import imgui_node_editor from imgui_bundle import imgui_node_editor
@@ -43,6 +44,16 @@ class _ScopeId:
imgui.pop_id() imgui.pop_id()
return False return False
def indent(width: float = 0.0): return _ScopeIndent(width)
class _ScopeIndent:
def __init__(self, width: float):
self._width = width
def __enter__(self):
imgui.indent(self._width)
def __exit__(self, *args):
imgui.unindent(self._width)
return False
def menu(label: str): return _ScopeMenu(label) def menu(label: str): return _ScopeMenu(label)
class _ScopeMenu: class _ScopeMenu:
def __init__(self, label: str): def __init__(self, label: str):