Shared forked agent — UI reads subconscious entries live

The forked agent is now behind Arc<tokio::sync::Mutex<Agent>>,
stored on SubconsciousAgent and passed to the spawned task. The
subconscious detail screen locks it via try_lock() to read entries
from the fork point — live during runs, persisted after completion.

Removes last_run_entries snapshot. Backend::Forked now holds the
shared Arc, all push operations go through the lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-07 03:09:06 -04:00
parent 77b68ecc50
commit 93f5f8b0c7
3 changed files with 78 additions and 81 deletions

View file

@ -115,7 +115,10 @@ impl SubconsciousScreen {
else { format!("{:.1}h ago", s / 3600.0) }
})
.unwrap_or_else(|| "never".to_string());
let entries = snap.last_run_entries.len();
let entries = snap.forked_agent.as_ref()
.and_then(|a| a.try_lock().ok())
.map(|ag| ag.context.entries.len().saturating_sub(snap.fork_point))
.unwrap_or(0);
vec![
Span::styled(
format!("{}{:<30}", prefix, snap.name),
@ -160,11 +163,17 @@ impl SubconsciousScreen {
lines.push(Line::styled(" (Esc/← back, ↑/↓/PgUp/PgDn scroll)", hint));
lines.push(Line::raw(""));
if snap.last_run_entries.is_empty() {
// Read entries from the forked agent (from fork point onward)
let entries: Vec<ConversationEntry> = snap.forked_agent.as_ref()
.and_then(|agent| agent.try_lock().ok())
.map(|ag| ag.context.entries[snap.fork_point..].to_vec())
.unwrap_or_default();
if entries.is_empty() {
lines.push(Line::styled(" (no run data)", hint));
}
for entry in &snap.last_run_entries {
for entry in &entries {
if entry.is_log() {
if let ConversationEntry::Log(text) = entry {
lines.push(Line::styled(
@ -189,14 +198,12 @@ impl SubconsciousScreen {
.collect::<Vec<_>>().join(", ")
});
// Role header
let header = match &tool_info {
Some(tools) => format!(" [{}{}]", role_str, tools),
None => format!(" [{}]", role_str),
};
lines.push(Line::styled(header, Style::default().fg(role_color)));
// Content (truncated per line)
if !text.is_empty() {
for line in text.lines().take(20) {
lines.push(Line::styled(