From 5be6ef88f8336881e95e0f671df3cb3c1dff71b8 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Tue, 12 May 2026 18:26:39 -0400 Subject: [PATCH] broken: discussion compression --- src/gui_2.py | 318 +-------------------------------------------------- 1 file changed, 5 insertions(+), 313 deletions(-) diff --git a/src/gui_2.py b/src/gui_2.py index 8a129e3..e2b0e0d 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -3799,326 +3799,18 @@ def hello(): if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_discussion_panel") return - if not self.is_viewing_prior_session and imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): - names = self._get_discussion_names() - grouped_discussions = {} - for name in names: - base = name.split("_take_")[0] - grouped_discussions.setdefault(base, []).append(name) - - active_base = self.active_discussion.split("_take_")[0] - if active_base not in grouped_discussions: - active_base = names[0] if names else "" - - base_names = sorted(grouped_discussions.keys()) - if imgui.begin_combo("##disc_sel", active_base): - for bname in base_names: - is_selected = (bname == active_base) - if imgui.selectable(bname, is_selected)[0]: - target = bname if bname in names else grouped_discussions[bname][0] - if target != self.active_discussion: - self._switch_discussion(target) - if is_selected: - imgui.set_item_default_focus() - imgui.end_combo() - - # Sync variables in case combo selection changed self.active_discussion - active_base = self.active_discussion.split("_take_")[0] - current_takes = grouped_discussions.get(active_base, []) - - if imgui.begin_tab_bar("discussion_takes_tabs"): - for take_name in current_takes: - label = "Original" if take_name == active_base else take_name.replace(f"{active_base}_", "").replace("_", " ").title() - flags = imgui.TabItemFlags_.set_selected if take_name == self.active_discussion else 0 - res = imgui.begin_tab_item(f"{label}###{take_name}", None, flags) - if res[0]: - if take_name != self.active_discussion: - self._switch_discussion(take_name) - imgui.end_tab_item() - - res_s = imgui.begin_tab_item("Synthesis###Synthesis") - if res_s[0]: - self._render_synthesis_panel() - imgui.end_tab_item() - - imgui.end_tab_bar() - - if "_take_" in self.active_discussion: - if imgui.button("Promote Take"): - base_name = self.active_discussion.split("_take_")[0] - new_name = f"{base_name}_promoted" - counter = 1 - while new_name in names: - new_name = f"{base_name}_promoted_{counter}" - counter += 1 - project_manager.promote_take(self.project, self.active_discussion, new_name) - self._switch_discussion(new_name) - imgui.same_line() - - if self.active_track: - imgui.same_line() - changed, self._track_discussion_active = imgui.checkbox("Track Discussion", self._track_discussion_active) - if changed: - if self._track_discussion_active: - self._flush_disc_entries_to_project() - history_strings = project_manager.load_track_history(self.active_track.id, self.active_project_root) - with self._disc_entries_lock: - self.disc_entries = models.parse_history_entries(history_strings, self.disc_roles) - self.ai_status = f"track discussion: {self.active_track.id}" - else: - self._flush_disc_entries_to_project() - # Restore project discussion - self._switch_discussion(self.active_discussion) - self.ai_status = "track discussion disabled" - - disc_sec = self.project.get("discussion", {}) - disc_data = disc_sec.get("discussions", {}).get(self.active_discussion, {}) - git_commit = disc_data.get("git_commit", "") - last_updated = disc_data.get("last_updated", "") - - imgui.text_colored(C_LBL, "commit:") - imgui.same_line() - self._render_selectable_label('git_commit_val', git_commit[:12] if git_commit else '(none)', width=100, color=(C_IN if git_commit else C_LBL)) - imgui.same_line() - if imgui.button("Update Commit"): - git_dir = self.ui_project_git_dir - if git_dir: - cmt = project_manager.get_git_commit(git_dir) - if cmt: - disc_data["git_commit"] = cmt - disc_data["last_updated"] = project_manager.now_ts() - self.ai_status = f"commit: {cmt[:12]}" - - imgui.text_colored(C_LBL, "updated:") - imgui.same_line() - imgui.text_colored(C_SUB, last_updated if last_updated else "(never)") - - ch, self.ui_disc_new_name_input = imgui.input_text("##new_disc", self.ui_disc_new_name_input) - imgui.same_line() - if imgui.button("Create"): - nm = self.ui_disc_new_name_input.strip() - if nm: self._create_discussion(nm); self.ui_disc_new_name_input = "" - imgui.same_line() - if imgui.button("Rename"): - nm = self.ui_disc_new_name_input.strip() - if nm: self._rename_discussion(self.active_discussion, nm); self.ui_disc_new_name_input = "" - imgui.same_line() - if imgui.button("Delete"): - self._delete_discussion(self.active_discussion) + self._render_discussion_selector() if not self.is_viewing_prior_session: imgui.separator() - if imgui.button("+ Entry"): - self.disc_entries.append({"role": self.disc_roles[0] if self.disc_roles else "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()}) - imgui.same_line() - if imgui.button("-All"): - for e in self.disc_entries: e["collapsed"] = True - imgui.same_line() - if imgui.button("+All"): - for e in self.disc_entries: e["collapsed"] = False - imgui.same_line() - if imgui.button("Clear All"): - self.disc_entries.clear() - imgui.same_line() - if imgui.button("Save"): - self._flush_to_project() - self._flush_to_config() - models.save_config(self.config) - self.ai_status = "discussion saved" - - ch, self.ui_auto_add_history = imgui.checkbox("Auto-add message & response to history", self.ui_auto_add_history) - # Truncation controls - imgui.text("Keep Pairs:") - imgui.same_line() - imgui.set_next_item_width(80) - ch, self.ui_disc_truncate_pairs = imgui.input_int("##trunc_pairs", self.ui_disc_truncate_pairs, 1) - if self.ui_disc_truncate_pairs < 1: self.ui_disc_truncate_pairs = 1 - imgui.same_line() - if imgui.button("Truncate"): - with self._disc_entries_lock: - self.disc_entries = truncate_entries(self.disc_entries, self.ui_disc_truncate_pairs) - self.ai_status = f"history truncated to {self.ui_disc_truncate_pairs} pairs" + self._render_discussion_entry_controls() imgui.separator() - if imgui.collapsing_header("Roles"): - imgui.begin_child("roles_scroll", imgui.ImVec2(0, 100), True) - for i, r in enumerate(self.disc_roles): - imgui.push_id(f"role_{i}") - if imgui.button("X"): - self.disc_roles.pop(i) - imgui.pop_id() - break - imgui.same_line() - imgui.text(r) - imgui.pop_id() - imgui.end_child() - ch, self.ui_disc_new_role_input = imgui.input_text("##new_role", self.ui_disc_new_role_input) - imgui.same_line() - if imgui.button("Add"): - r = self.ui_disc_new_role_input.strip() - if r and r not in self.disc_roles: - self.disc_roles.append(r) - self.ui_disc_new_role_input = "" + self._render_discussion_roles() imgui.separator() - imgui.begin_child("disc_scroll", imgui.ImVec2(0, 0), False) - - # Filter entries based on focused agent persona - display_entries = self.disc_entries - if self.ui_focus_agent: - tier_usage = self.mma_tier_usage.get(self.ui_focus_agent) - if tier_usage: - persona_name = tier_usage.get("persona") - if persona_name: - # Show User messages and the focused agent's responses - display_entries = [e for e in self.disc_entries if e.get("role") == persona_name or e.get("role") == "User"] - - clipper = imgui.ListClipper() - clipper.begin(len(display_entries)) - while clipper.step(): - for i in range(clipper.display_start, clipper.display_end): - entry = display_entries[i] - # Use the index in the original list for ID if possible, but here i is index in display_entries - imgui.push_id(f"disc_{i}") - collapsed = entry.get("collapsed", False) - read_mode = entry.get("read_mode", False) - 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: - if imgui.selectable(r, r == entry["role"])[0]: - entry["role"] = r - imgui.end_combo() - - if not collapsed: - imgui.same_line() - if imgui.button("[Edit]" if read_mode else "[Read]"): - entry["read_mode"] = not read_mode - - ts_str = entry.get("ts", "") - if ts_str: - imgui.same_line() - imgui.text_colored(vec4(120, 120, 100), str(ts_str)) - # Visual indicator for file injections - e_dt = project_manager.parse_ts(ts_str) - if e_dt: - e_unix = e_dt.timestamp() - next_unix = float('inf') - if i + 1 < len(self.disc_entries): - n_ts = self.disc_entries[i+1].get("ts", "") - n_dt = project_manager.parse_ts(n_ts) - if n_dt: next_unix = n_dt.timestamp() - injected_here = [f for f in self.files if hasattr(f, 'injected_at') and f.injected_at and e_unix <= f.injected_at < next_unix] - if injected_here: - imgui.same_line() - imgui.text_colored(vec4(100, 255, 100), f"[{len(injected_here)}+]") - if imgui.is_item_hovered(): - tooltip = "Files injected at this point:\n" + "\n".join([f.path for f in injected_here]) - imgui.set_tooltip(tooltip) - - if collapsed: - imgui.same_line() - if imgui.button("Ins"): - self.disc_entries.insert(i, {"role": "User", "content": "", "collapsed": True, "ts": project_manager.now_ts()}) - imgui.same_line() - if imgui.button("Del"): - self.disc_entries.pop(i) - imgui.pop_id() - break # Break from inner loop, clipper will re-step - imgui.same_line() - if imgui.button("Branch"): - self._branch_discussion(i) - imgui.same_line() - preview = entry["content"].replace("\n", " ")[:60] - if len(entry["content"]) > 60: preview += "..." - if not preview.strip() and entry.get("thinking_segments"): - preview = entry["thinking_segments"][0]["content"].replace("\n", " ")[:60] - if len(entry["thinking_segments"][0]["content"]) > 60: preview += "..." - imgui.text_colored(vec4(160, 160, 150), preview) - if not collapsed: - thinking_segments = entry.get("thinking_segments", []) - has_content = bool(entry.get("content", "").strip()) - is_standalone = bool(thinking_segments) and not has_content - if thinking_segments: - self._render_thinking_trace(thinking_segments, i, is_standalone=is_standalone) - if read_mode: - content = entry["content"] - if content.strip(): - if '## Retrieved Context' in content: - rag_match = re.search(r'## Retrieved Context\n\n([\s\S]*?)(?=\n\n#|\Z)', content) - if rag_match: - rag_section = rag_match.group(1) - if imgui.collapsing_header('Retrieved Context'): - chunks = re.finditer(r'### Chunk (\d+) \(Source: (.*?)\)\n([\s\S]*?)(?=\n### Chunk|\Z)', rag_section) - for chunk_match in chunks: - idx = chunk_match.group(1) - path = chunk_match.group(2) - chunk_content = chunk_match.group(3) - if imgui.collapsing_header(f'Chunk {idx}: {path}'): - if imgui.button(f'[Source]##rag_{i}_{idx}'): - res = mcp_client.read_file(path) - if res: - self.text_viewer_title = path - self.text_viewer_content = res - self.text_viewer_type = Path(path).suffix.lstrip('.') if Path(path).suffix else 'text' - self.show_text_viewer = True - imgui.text_unformatted(chunk_content) - content = content[:rag_match.start()] + content[rag_match.end():] - pattern = re.compile(r"\[Definition: (.*?) from (.*?) \(line (\d+)\)\](\s+```[\s\S]*?```)?") - matches = list(pattern.finditer(content)) - is_nerv = theme.is_nerv_active() - if not matches: - if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) - markdown_helper.render(content, context_id=f'disc_{i}') - if is_nerv: imgui.pop_style_color() - else: - imgui.begin_child(f"read_content_{i}", imgui.ImVec2(0, 150), True) - if self.ui_word_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) - last_idx = 0 - for m_idx, match in enumerate(matches): - before = content[last_idx:match.start()] - if before: - if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) - markdown_helper.render(before, context_id=f'disc_{i}_b_{m_idx}') - if is_nerv: imgui.pop_style_color() - header_text = match.group(0).split("\n")[0].strip() - path = match.group(2) - code_block = match.group(4) - if imgui.collapsing_header(header_text): - if imgui.button(f"[Source]##{i}_{match.start()}"): - res = mcp_client.read_file(path) - if res: - self.text_viewer_title = path - self.text_viewer_content = res - self.text_viewer_type = Path(path).suffix.lstrip('.') if Path(path).suffix else 'text' - self.show_text_viewer = True - if code_block: - if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) - markdown_helper.render(code_block, context_id=f'disc_{i}_c_{m_idx}') - if is_nerv: imgui.pop_style_color() - last_idx = match.end() - after = content[last_idx:] - if after: - if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80)) - markdown_helper.render(after, context_id=f'disc_{i}_a') - if is_nerv: imgui.pop_style_color() - if self.ui_word_wrap: imgui.pop_text_wrap_pos() - imgui.end_child() - else: - if not is_standalone: - ch, entry["content"] = imgui.input_text_multiline("##content", entry["content"], imgui.ImVec2(-1, 150)) - imgui.separator() - imgui.pop_id() - - if self._scroll_disc_to_bottom: - imgui.set_scroll_here_y(1.0) - self._scroll_disc_to_bottom = False - - imgui.end_child() + self._render_discussion_entries() + if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_discussion_panel") def _render_synthesis_panel(self) -> None: