Private
Public Access
0
0

more gui_2.py

This commit is contained in:
2026-06-13 12:00:33 -04:00
parent b61a2db01d
commit 9fc2c21e82
+104 -132
View File
@@ -3603,7 +3603,7 @@ def render_ast_inspector_modal(app: App) -> None:
if getattr(app, 'show_structural_editor_modal', False):
imgui.open_popup('Structural File Editor')
app.show_structural_editor_modal = False
imgui.set_next_window_size(imgui.ImVec2(1400, 900), imgui.Cond_.first_use_ever)
expanded, opened = imgui.begin_popup_modal('Structural File Editor', True, imgui.WindowFlags_.none)
if opened:
@@ -3613,19 +3613,19 @@ def render_ast_inspector_modal(app: App) -> None:
else:
f_item = app.ui_editing_slices_file
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
if f_path != getattr(app, '_cached_ast_file_path', None):
outline = ""
try:
proj_dir = str(Path(app.controller.active_project_path).parent.resolve()) if getattr(app, 'controller', None) and app.controller.active_project_path else None
mcp_client.configure([{"path": f_path}], [proj_dir] if proj_dir else None)
if f_path.lower().endswith('.py'): outline = mcp_client.py_get_code_outline(f_path)
elif f_path.lower().endswith(('.c', '.h')): outline = mcp_client.ts_c_get_code_outline(f_path)
elif f_path.lower().endswith(('.cpp', '.hpp', '.cxx', '.cc')): outline = mcp_client.ts_cpp_get_code_outline(f_path)
except Exception as e:
outline = f"Error fetching outline: {e}"
app._cached_ast_nodes = []
import re #TODO(Ed): Review local import
pattern = re.compile(r'^(\s*)\[(.*?)\] (.*?) \(Lines (\d+)-(\d+)\)')
@@ -3639,34 +3639,34 @@ def render_ast_inspector_modal(app: App) -> None:
stack.append((indent, name))
full_path = '::'.join([s[1] for s in stack])
app._cached_ast_nodes.append({
'indent': indent,
'kind': kind,
'name': name,
'full_path': full_path,
'indent': indent,
'kind': kind,
'name': name,
'full_path': full_path,
'start_line': int(start_ln),
'end_line': int(end_ln)
'end_line': int(end_ln)
})
try:
content = mcp_client.read_file(f_path)
content = mcp_client.read_file(f_path)
app._cached_ast_file_lines = content.splitlines()
app.text_viewer_content = content
app.text_viewer_content = content
except Exception:
app._cached_ast_file_lines = ["Error loading file content."]
app.text_viewer_content = "Error loading file content."
app._cached_ast_file_path = f_path
app.text_viewer_content = "Error loading file content."
app._cached_ast_file_path = f_path
imgui.text(f"Editing Structure: {f_path}")
imgui.separator()
avail = imgui.get_content_region_avail()
avail = imgui.get_content_region_avail()
table_height = max(100.0, avail.y - imgui.get_frame_height_with_spacing() * 2 - 20)
if imgui.begin_table('structure_dual_pane', 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders_inner_v, imgui.ImVec2(0, table_height)):
imgui.table_setup_column("AST & Slices", imgui.TableColumnFlags_.width_fixed, 400)
imgui.table_setup_column("AST & Slices", imgui.TableColumnFlags_.width_fixed, 400)
imgui.table_setup_column("Content Preview", imgui.TableColumnFlags_.width_stretch)
imgui.table_next_row()
imgui.table_next_column()
# --- LEFT COLUMN: AST Tree & Slice Management ---
imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 0), True)
# if True:
@@ -3700,7 +3700,7 @@ def render_ast_inspector_modal(app: App) -> None:
# if do_align: imgui.same_line((avail_width - btn_width))
# else: imgui.same_line()
# imgui.same_line((avail_width - btn_width) * 0.925)
if not hasattr(f_item, 'ast_mask'): f_item.ast_mask = {}
current_mode = f_item.ast_mask.get(full_path, 'hide')
@@ -3721,12 +3721,15 @@ def render_ast_inspector_modal(app: App) -> None:
s_line = min(app._slice_sel_start, app._slice_sel_end)
e_line = max(app._slice_sel_start, app._slice_sel_end)
from src.fuzzy_anchor import FuzzyAnchor
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
slice_data = FuzzyAnchor.create_slice(app.text_viewer_content, s_line, e_line)
slice_data['tag'] = ""; slice_data['comment'] = ""
f_item.custom_slices.append(slice_data)
app._slice_sel_start = -1; app._slice_sel_end = -1
app._slice_sel_start = -1
app._slice_sel_end = -1
imgui.same_line()
if imgui.button("Clear Selection"): app._slice_sel_start = -1; app._slice_sel_end = -1
if imgui.button("Clear Selection"):
app._slice_sel_start = -1
app._slice_sel_end = -1
imgui.same_line()
if imgui.button("Auto-Populate"): app._populate_auto_slices(f_item)
@@ -3747,9 +3750,9 @@ def render_ast_inspector_modal(app: App) -> None:
imgui.pop_id()
if to_remove != -1: f_item.custom_slices.pop(to_remove)
imgui.end_child()
imgui.table_next_column()
# --- RIGHT COLUMN: Content Preview with Highlights ---
with imscope.child("ast_content_scroll", imgui.ImVec2(0, 0), True):
if not getattr(app, '_cached_ast_file_lines', None):
@@ -3758,10 +3761,10 @@ def render_ast_inspector_modal(app: App) -> None:
draw_list = imgui.get_window_draw_list()
for i, line_text in enumerate(app._cached_ast_file_lines):
line_num = i + 1
pos = imgui.get_cursor_screen_pos()
pos = imgui.get_cursor_screen_pos()
line_height = imgui.get_text_line_height()
avail_width = imgui.get_content_region_avail().x
# 1. AST Highlight
deepest_node = None
for node in app._cached_ast_nodes:
@@ -3769,31 +3772,29 @@ def render_ast_inspector_modal(app: App) -> None:
if deepest_node is None or node['indent'] > deepest_node['indent']: deepest_node = node
mode = 'hide'
if deepest_node: mode = getattr(f_item, 'ast_mask', {}).get(deepest_node['full_path'], 'hide')
if mode == 'def':
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
elif mode == 'sig':
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.15)))
if mode == 'def': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.15)))
elif mode == 'sig': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.15)))
elif deepest_node and deepest_node['full_path'] == getattr(app, '_hovered_ast_node', None):
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("status_warning", alpha=0.2)))
# 2. Slice Highlight
if hasattr(f_item, 'custom_slices'):
is_auto = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') == 'auto-ast')
is_man = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') != 'auto-ast')
is_man = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in f_item.custom_slices if slc.get('tag') != 'auto-ast')
if is_man: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_manual", alpha=0.2)))
elif is_auto and mode == 'hide': draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_auto", alpha=0.1)))
# 3. Active Selection Highlight
if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1:
s, e = min(app._slice_sel_start, app._slice_sel_end), max(app._slice_sel_start, app._slice_sel_end)
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + avail_width, pos.y + line_height), imgui.get_color_u32(theme.get_color("slice_selection", alpha=0.3)))
imgui.selectable(f"{line_num:4} | {line_text}##ln{line_num}", False)
if imgui.is_item_clicked(): app._slice_sel_start = line_num; app._slice_sel_end = line_num
if imgui.is_item_hovered(imgui.HoveredFlags_.allow_when_blocked_by_active_item) and imgui.is_mouse_down(0): app._slice_sel_end = line_num
imgui.end_table()
imgui.separator()
if imgui.button("Close", imgui.ImVec2(120, 0)):
app.ui_editing_slices_file = None
@@ -3806,11 +3807,9 @@ def render_ast_inspector_modal(app: App) -> None:
app.ui_inspecting_ast_file = None
def render_save_workspace_profile_modal(app: App) -> None:
"""
Renders a popup modal for saving the current workspace profile (projects, layout, configuration).
"""Renders a popup modal for saving the current workspace profile (projects, layout, configuration).
SSDL Shape:
`[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
SSDL: `[I:name_input] -> [B:scope_radio] -> [B:save_button] => [B:cancel_button]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -3831,7 +3830,7 @@ def render_save_workspace_profile_modal(app: App) -> None:
imgui.text("Scope:")
if imgui.radio_button("Project", app._new_workspace_profile_scope == "project"): app._new_workspace_profile_scope = "project"
imgui.same_line()
if imgui.radio_button("Global", app._new_workspace_profile_scope == "global"): app._new_workspace_profile_scope = "global"
if imgui.radio_button("Global", app._new_workspace_profile_scope == "global"): app._new_workspace_profile_scope = "global"
imgui.separator()
if imgui.button("Save", (120, 0)):
@@ -3848,12 +3847,10 @@ def render_save_workspace_profile_modal(app: App) -> None:
imgui.end_popup()
def render_context_presets_panel(app: App) -> None:
"""
Renders the Context Presets configuration panel. Enables naming, saving, loading,
"""Renders the Context Presets configuration panel. Enables naming, saving, loading,
and deleting context presets.
SSDL Shape:
`[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
SSDL: `[I:presets_list] -> [B:save_new_preset] => [B:presets_action_buttons]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -3885,11 +3882,9 @@ def render_context_presets_panel(app: App) -> None:
if imgui.button(f"Delete##{name}"): app.delete_context_preset(name)
def render_context_screenshots(app: App) -> None:
"""
Renders a list of the currently attached screenshot image files.
"""Renders a list of the currently attached screenshot image files.
SSDL Shape:
`[I:screenshots]`
SSDL: `[I:screenshots]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -3900,12 +3895,10 @@ def render_context_screenshots(app: App) -> None:
for i, s in enumerate(app.screenshots): imgui.text(s)
def render_context_files_table(app: App) -> None:
"""
Renders a two-column table mapping active context files to their AST view modes
"""Renders a two-column table mapping active context files to their AST view modes
(Definition, Signature, Hide) and slice indicators. Grouped by directories.
SSDL Shape:
`[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
SSDL: `[I:group_by_dir] -> o-> [I:dir_node] -> o-> [I:file_row]`
ASCII Layout Map:
+-------------------------------------------------------------+
@@ -3921,7 +3914,7 @@ def render_context_files_table(app: App) -> None:
with imscope.table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders) as active:
if active:
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
imgui.table_headers_row()
@@ -4017,11 +4010,9 @@ def render_context_files_table(app: App) -> None:
imgui.text_colored(theme.get_color("status_warning"), "[Slices Active]")
def render_context_presets(app: App) -> None:
"""
Renders context preset management controls (combobox selector, update button, save-as, and delete active).
"""Renders context preset management controls (combobox selector, update button, save-as, and delete active).
SSDL Shape:
`[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
SSDL: `[I:presets] -> [B:presets_combo] -> [B:save_as_button] => [B:delete_active]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -4055,12 +4046,12 @@ def render_context_presets(app: App) -> None:
for f in app.context_files:
import copy
from src import models
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=active, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
@@ -4082,12 +4073,9 @@ def render_context_presets(app: App) -> None:
root = app.controller.active_project_root
for f in app.context_files:
path = f.path if hasattr(f, "path") else str(f)
if not os.path.isabs(path):
full_path = os.path.join(root, path)
else:
full_path = path
if not os.path.exists(full_path):
missing.append(path)
if not os.path.isabs(path): full_path = os.path.join(root, path)
else: full_path = path
if not os.path.exists(full_path): missing.append(path)
if missing:
app.missing_context_files = missing
@@ -4098,12 +4086,12 @@ def render_context_presets(app: App) -> None:
for f in app.context_files:
import copy
from src import models
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
@@ -4118,11 +4106,9 @@ def render_context_presets(app: App) -> None:
app.ui_active_context_preset = ""
def render_snapshot_tab(app: App) -> None:
"""
Renders the Snapshot tab-bar, containing the resolved aggregate markdown and active system prompts.
"""Renders the Snapshot tab-bar, containing the resolved aggregate markdown and active system prompts.
SSDL Shape:
`[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
SSDL: `[I:aggregate_text] -> [B:copy_buttons] => [I:preview_panes]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -4150,13 +4136,13 @@ def render_snapshot_tab(app: App) -> None:
display_md = app._focus_md_cache[cp_name]
else:
flat = src.project_manager.flat_config(app.controller.project, app.active_discussion)
cp = app.controller.project.get('context_presets', {}).get(cp_name)
cp = app.controller.project.get('context_presets', {}).get(cp_name)
if cp:
flat["files"]["paths"] = cp.get("files", [])
flat["files"]["paths"] = cp.get("files", [])
flat["screenshots"]["paths"] = cp.get("screenshots", [])
full_md, _, _ = src.aggregate.run(flat)
full_md, _, _ = src.aggregate.run(flat)
app._focus_md_cache[cp_name] = full_md
display_md = full_md
display_md = full_md
if imgui.button("Copy"): imgui.set_clipboard_text(display_md)
with imscope.child("last_agg_md", 0, 0, True):
markdown_helper.render(display_md, context_id="snapshot_agg")
@@ -4167,11 +4153,9 @@ def render_snapshot_tab(app: App) -> None:
markdown_helper.render(app.last_resolved_system_prompt, context_id="snapshot_sys")
def render_empty_context_modal(app: App) -> None:
"""
Renders a popup modal warning the user when the context composition is empty.
"""Renders a popup modal warning the user when the context composition is empty.
SSDL Shape:
`[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
SSDL: `[I:warning_text] -> [B:proceed_button] => [B:cancel_button]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -4192,8 +4176,8 @@ def render_empty_context_modal(app: App) -> None:
imgui.text("This may result in poor AI performance or loss of project context.")
imgui.separator()
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
if app._pending_generation_action == 'generate': app.controller._handle_generate_send()
elif app._pending_generation_action == 'md_only': app.controller._handle_md_only()
app._pending_generation_action = None
imgui.close_current_popup()
imgui.same_line()
@@ -4202,12 +4186,10 @@ def render_empty_context_modal(app: App) -> None:
imgui.end_popup()
def render_context_modals(app: App) -> None:
"""
Dispatches rendering calls to sub-modals relating to context management
"""Dispatches rendering calls to sub-modals relating to context management
(empty context warning, file picker, missing files warning, and AST inspector).
SSDL Shape:
`[I] -> [I:modals_dispatch]`
SSDL: `[I] -> [I:modals_dispatch]`
ASCII Layout Map:
Conditionally opens (in order):
@@ -4239,12 +4221,12 @@ def render_context_modals(app: App) -> None:
for f in app.context_files:
import copy
from src import models
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
slc = copy.deepcopy(f.custom_slices) if hasattr(f, 'custom_slices') else []
msk = copy.deepcopy(f.ast_mask) if hasattr(f, 'ast_mask') else {}
sig = f.ast_signatures if hasattr(f, 'ast_signatures') else False
dfn = f.ast_definitions if hasattr(f, 'ast_definitions') else False
preset_files.append(models.ContextFileEntry(path=p, view_mode=vm, custom_slices=slc, ast_mask=msk, ast_signatures=sig, ast_definitions=dfn))
preset = models.ContextPreset(name=name, files=preset_files, screenshots=list(app.screenshots))
app.controller.save_context_preset(preset)
@@ -4262,10 +4244,10 @@ def render_context_modals(app: App) -> None:
def _get_context_composition_state(app: App) -> tuple:
files_state = []
for f in app.context_files:
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
p = f.path if hasattr(f, 'path') else str(f)
vm = f.view_mode if hasattr(f, 'view_mode') else 'summary'
agg = f.auto_aggregate if hasattr(f, 'auto_aggregate') else False
slc = tuple((s.get('start_line'), s.get('end_line'), s.get('tag'), s.get('comment')) for s in getattr(f, 'custom_slices', []))
mask = tuple(sorted(getattr(f, 'ast_mask', {}).items()))
files_state.append((p, vm, agg, slc, mask))
screenshots_state = tuple(app.screenshots)
@@ -4287,8 +4269,8 @@ def _check_auto_refresh_context_preview(app: App) -> None:
def worker():
try:
app.controller.context_files = app.context_files
res = app.controller._do_generate()
app.context_preview_text = res[0]
res = app.controller._do_generate()
app.context_preview_text = res[0]
except Exception:
app.context_preview_text = "Error generating context preview."
finally:
@@ -4303,12 +4285,10 @@ def _check_auto_refresh_context_preview(app: App) -> None:
app.controller.submit_io(worker)
def render_context_preview_window(app: App) -> None:
"""
Renders the Context Preview window. Automatically refreshes aggregated context previews in the background
"""Renders the Context Preview window. Automatically refreshes aggregated context previews in the background
and renders formatted markdown text.
SSDL Shape:
`[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
SSDL: `[I:preview_text] -> [B:clipboard_button] => [I:preview_box]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -4330,7 +4310,7 @@ def render_context_preview_window(app: App) -> None:
if exp:
if imgui.button("Close"):
app.show_windows["Context Preview"] = False
app.ui_separate_context_preview = False
app.ui_separate_context_preview = False
imgui.same_line()
if imgui.button("Copy to Clipboard"):
imgui.set_clipboard_text(app.context_preview_text)
@@ -4342,12 +4322,10 @@ def render_context_preview_window(app: App) -> None:
#region: Discussions
def render_discussion_hub(app: App) -> None:
"""
Top-level hub for the Discussion panel. Houses tabs for Discussion, Context Composition,
"""Top-level hub for the Discussion panel. Houses tabs for Discussion, Context Composition,
Context Preview (inline or detached), Snapshot, and Takes.
SSDL Shape:
`[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
SSDL: `[B:pop_out_toggle] -> [I:tab_bar] => [I:active_tab_content]`
ASCII Layout Map:
+---------------------------------------------------------+
@@ -4383,12 +4361,10 @@ def render_discussion_hub(app: App) -> None:
return
def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
"""
Renders a collapsible thinking-trace section within a discussion entry bubble.
"""Renders a collapsible thinking-trace section within a discussion entry bubble.
Displays each reasoning segment labeled by its marker tag (e.g. [thinking]).
SSDL Shape:
`[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
SSDL: `[I:segment_list] -> [B:read_pure_toggle] => [I:trace_child]`
ASCII Layout Map:
+----------------------------------------------------------+
@@ -4426,22 +4402,18 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind
imgui.text_colored(C_TC(), f"[{marker}]")
if thinking_read_mode:
if app.ui_word_wrap:
with imscope.text_wrap(imgui.get_content_region_avail().x):
imgui.text(content)
else:
imgui.text(content)
with imscope.text_wrap(imgui.get_content_region_avail().x): imgui.text(content)
else: imgui.text(content)
else:
render_selectable_label(app, f"think_text_{entry_index}_{idx}", content, multiline=True, height=-1)
imgui.separator()
def render_discussion_entry(app: App, entry: dict, index: int) -> None:
"""
Renders a single discussion message entry as a colored visual bubble.
"""Renders a single discussion message entry as a colored visual bubble.
Supports collapsible states, read/edit mode toggles, role selection,
input/output token metrics, and action footers.
SSDL Shape:
`[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
SSDL: `[I:header] -> [B:collapsed] => [I:preview] | [I:body] -> [I:footer]`
ASCII Layout Map:
+-------------------------------------------------------------+
@@ -7139,13 +7111,13 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer
imgui.end_combo()
if imgui.button("Create"):
new_ticket = {
"id": app.ui_new_ticket_id,
"id": app.ui_new_ticket_id,
"description": app.ui_new_ticket_desc,
"status": "todo",
"priority": app.ui_new_ticket_priority,
"status": "todo",
"priority": app.ui_new_ticket_priority,
"assigned_to": "tier3-worker",
"target_file": app.ui_new_ticket_target,
"depends_on": [d.strip() for d in app.ui_new_ticket_deps.split(",") if d.strip()]
"depends_on": [d.strip() for d in app.ui_new_ticket_deps.split(",") if d.strip()]
}
app.active_tickets.append(new_ticket)
app._show_add_ticket_form = False