Restore context tree display with SectionView UI type

Introduced SectionView {name, tokens, content, children} as a
UI-only tree node, separate from the data ContextSection. The widget
SectionTree renders SectionView with the old recursive expand/collapse
behavior — children for sub-sections, content for text expansion.

section_to_view() converts data sections to UI views, using
ConversationEntry::label() for names and content_text() for
expandable content.

read_context_views() builds the same tree the old context_state_summary
did: System, Identity, Journal, Memory nodes (scored/unscored counts,
expandable to show content), Conversation entries.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-07 22:06:10 -04:00
parent 613704720b
commit 07b400c95c
3 changed files with 132 additions and 105 deletions

View file

@ -15,9 +15,7 @@ use ratatui::{
};
use super::{App, ScreenView, screen_legend};
use super::widgets::{SectionTree, pane_block_focused, render_scrollable, tree_legend, format_age, format_ts_age};
use crate::agent::context::{ContextSection, ContextEntry, ConversationEntry};
use crate::agent::api::Message;
use super::widgets::{SectionTree, SectionView, section_to_view, pane_block_focused, render_scrollable, tree_legend, format_age, format_ts_age};
#[derive(Clone, Copy, PartialEq)]
enum Pane { Agents, Outputs, History, Context }
@ -130,23 +128,22 @@ impl SubconsciousScreen {
self.history_scroll = 0;
}
fn output_sections(&self, app: &App) -> Vec<ContextSection> {
fn output_sections(&self, app: &App) -> Vec<SectionView> {
let snap = match app.agent_state.get(self.selected()) {
Some(s) => s,
None => return Vec::new(),
};
snap.state.iter().map(|(key, val)| {
let mut section = ContextSection::new(key.clone());
section.push(ContextEntry {
entry: ConversationEntry::Message(Message::user(val)),
SectionView {
name: key.clone(),
tokens: 0,
timestamp: None,
});
section
content: val.clone(),
children: Vec::new(),
}
}).collect()
}
fn read_sections(&self, app: &App) -> Vec<ContextSection> {
fn read_sections(&self, app: &App) -> Vec<SectionView> {
let snap = match app.agent_state.get(self.selected()) {
Some(s) => s,
None => return Vec::new(),
@ -154,13 +151,12 @@ impl SubconsciousScreen {
snap.forked_agent.as_ref()
.and_then(|agent| agent.try_lock().ok())
.map(|ag| {
// Build a single section from the forked conversation entries
let entries = ag.conversation_entries_from(snap.fork_point);
let mut section = ContextSection::new("Conversation");
for e in entries {
section.push(e.clone());
}
vec![section]
let conv = ag.context.conversation.clone();
// Only show entries from fork point onward
let mut view = section_to_view(&conv);
let fork = snap.fork_point.min(view.children.len());
view.children = view.children.split_off(fork);
vec![view]
})
.unwrap_or_default()
}
@ -281,7 +277,7 @@ impl SubconsciousScreen {
&self,
frame: &mut Frame,
area: Rect,
sections: &[ContextSection],
sections: &[SectionView],
app: &App,
) {
let mut lines: Vec<Line> = Vec::new();