From 1745e0355020db580111c0ec51e08e91730c8c98 Mon Sep 17 00:00:00 2001 From: ProofOfConcept Date: Sun, 5 Apr 2026 21:21:08 -0400 Subject: [PATCH] Kill UiMessage variants replaced by state-driven rendering sync_from_agent reads directly from agent entries, so remove: - UserInput (pending input shown from MindState.input) - ToolCall, ToolResult (shown from entries on completion) - ToolStarted, ToolFinished (replaced by shared active_tools) - replay_session_to_ui (sync_from_agent handles replay) -139 lines. Remaining variants are streaming (TextDelta, Reasoning), status bar state, or ephemeral UI messages (Info, Debug). Co-Authored-By: Proof of Concept --- src/agent/api/mod.rs | 4 -- src/agent/mod.rs | 8 --- src/user/chat.rs | 18 ------- src/user/mod.rs | 7 +-- src/user/ui_channel.rs | 107 ++--------------------------------------- 5 files changed, 5 insertions(+), 139 deletions(-) diff --git a/src/agent/api/mod.rs b/src/agent/api/mod.rs index bde1704..5f9af04 100644 --- a/src/agent/api/mod.rs +++ b/src/agent/api/mod.rs @@ -651,10 +651,6 @@ pub async fn collect_stream( let args: serde_json::Value = serde_json::from_str(&call.function.arguments).unwrap_or_default(); let args_summary = summarize_args(&call.function.name, &args); - let _ = ui_tx.send(UiMessage::ToolCall { - name: call.function.name.clone(), - args_summary: args_summary.clone(), - }); let is_background = args.get("run_in_background") .and_then(|v| v.as_bool()) .unwrap_or(false); diff --git a/src/agent/mod.rs b/src/agent/mod.rs index 0e56e70..9c94c1e 100644 --- a/src/agent/mod.rs +++ b/src/agent/mod.rs @@ -510,10 +510,6 @@ impl Agent { let args_summary = summarize_args(&call.function.name, &args); let _ = ui_tx.send(UiMessage::Activity(format!("calling: {}", call.function.name))); - let _ = ui_tx.send(UiMessage::ToolCall { - name: call.function.name.clone(), - args_summary: args_summary.clone(), - }); // Spawn tool, track it let call_clone = call.clone(); @@ -561,10 +557,6 @@ impl Agent { ds.tool_errors += 1; } - let _ = ui_tx.send(UiMessage::ToolResult { - name: call.function.name.clone(), - result: output.clone(), - }); self.active_tools.lock().unwrap().retain(|t| t.id != call.id); // Tag memory_render results for context deduplication diff --git a/src/user/chat.rs b/src/user/chat.rs index 83424c2..b76a853 100644 --- a/src/user/chat.rs +++ b/src/user/chat.rs @@ -602,24 +602,6 @@ impl InteractScreen { self.autonomous.append_text(text); } }, - UiMessage::UserInput(text) => { - self.conversation.push_line_with_marker(text.clone(), Color::Cyan, Marker::User); - self.turn_started = Some(std::time::Instant::now()); - self.needs_assistant_marker = true; - app.status.turn_tools = 0; - } - UiMessage::ToolCall { name, args_summary } => { - app.status.turn_tools += 1; - let line = if args_summary.is_empty() { format!("[{}]", name) } - else { format!("[{}] {}", name, args_summary) }; - self.tools.push_line(line, Color::Yellow); - } - UiMessage::ToolResult { result, .. } => { - for line in result.lines() { - self.tools.push_line(format!(" {}", line), Color::DarkGray); - } - self.tools.push_line(String::new(), Color::Reset); - } UiMessage::DmnAnnotation(text) => { self.autonomous.push_line(text.clone(), Color::Yellow); self.turn_started = Some(std::time::Instant::now()); diff --git a/src/user/mod.rs b/src/user/mod.rs index 5108986..c4100f0 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -459,13 +459,10 @@ pub async fn run( idle_state.decay_ewma(); app.update_idle(&idle_state); - // One-time: replay conversation after Mind init + // One-time: mark startup done after Mind init if !startup_done { if let Ok(ag) = agent.try_lock() { - if !ag.entries().is_empty() { - ui_channel::replay_session_to_ui(ag.entries(), &ui_tx); - let _ = ui_tx.send(UiMessage::Info("--- restored from conversation log ---".into())); - } + // sync_from_agent handles conversation replay let _ = ui_tx.send(UiMessage::Info(format!(" model: {}", ag.model()))); startup_done = true; dirty = true; diff --git a/src/user/ui_channel.rs b/src/user/ui_channel.rs index 28e5bec..0233729 100644 --- a/src/user/ui_channel.rs +++ b/src/user/ui_channel.rs @@ -71,54 +71,28 @@ pub struct ContextInfo { #[derive(Debug, Clone)] #[allow(dead_code)] pub enum UiMessage { - /// Streaming text delta — routed to conversation or autonomous pane - /// based on the current StreamTarget. + /// Streaming text delta — routed to conversation or autonomous pane. TextDelta(String, StreamTarget), - /// User's input echoed to conversation pane. - UserInput(String), - - /// Tool call header: [tool_name] with args summary. - ToolCall { - name: String, - args_summary: String, - }, - - /// Full tool result — goes to tools pane. - ToolResult { - name: String, - result: String, - }, - /// DMN state annotation: [dmn: foraging (3/20)]. DmnAnnotation(String), /// Status bar update. StatusUpdate(StatusInfo), - /// Live activity indicator for the status bar — shows what the - /// agent is doing right now ("thinking...", "calling: bash", etc). - /// Empty string clears the indicator. + /// Live activity indicator for the status bar. Activity(String), /// Reasoning/thinking tokens from the model (internal monologue). - /// Routed to the autonomous pane so the user can peek at what - /// the model is thinking about during long tool chains. Reasoning(String), - /// A tool call started — shown as a live overlay above the status bar. - ToolStarted { id: String, name: String, detail: String }, - - /// A tool call finished — removes it from the live overlay. - ToolFinished { id: String }, - /// Debug message (only shown when POC_DEBUG is set). Debug(String), /// Informational message — goes to conversation pane (command output, etc). Info(String), - /// Context loading details — stored for the debug screen (Ctrl+D). + /// Context loading details — stored for the debug screen. ContextInfoUpdate(ContextInfo), /// Agent cycle state update — refreshes the F2 agents screen. @@ -157,78 +131,3 @@ pub fn channel() -> (UiSender, UiReceiver) { /// Replay a restored session into the TUI panes so the user can see /// conversation history immediately on restart. Shows user input, -/// assistant responses, and brief tool call summaries. Skips the system -/// prompt, context message, DMN plumbing, and image injection messages. -pub fn replay_session_to_ui(entries: &[crate::agent::context::ConversationEntry], ui_tx: &UiSender) { - use crate::agent::api::types::Role; - - crate::dbglog!("[replay] replaying {} entries to UI", entries.len()); - for (i, e) in entries.iter().enumerate() { - let m = e.message(); - let preview: String = m.content_text().chars().take(60).collect(); - crate::dbglog!("[replay] [{}] {:?} mem={} tc={} tcid={:?} {:?}", - i, m.role, e.is_memory(), m.tool_calls.as_ref().map_or(0, |t| t.len()), - m.tool_call_id.as_deref(), preview); - } - - let mut seen_first_user = false; - let mut target = StreamTarget::Conversation; - - for entry in entries { - if entry.is_memory() { continue; } - let msg = entry.message(); - match msg.role { - Role::System => {} - Role::User => { - if !seen_first_user { - seen_first_user = true; - continue; - } - let text = msg.content_text(); - if text.starts_with("Your context was just compacted") - || text.starts_with("Your context was just rebuilt") - || text.starts_with("[Earlier in this conversation") - || text.starts_with("Here is the image") - || text.contains("[image aged out") - { - continue; - } - if text.starts_with("[dmn]") { - target = StreamTarget::Autonomous; - let first_line = text.lines().next().unwrap_or("[dmn]"); - let _ = ui_tx.send(UiMessage::DmnAnnotation(first_line.to_string())); - } else { - target = StreamTarget::Conversation; - let _ = ui_tx.send(UiMessage::UserInput(text.to_string())); - } - } - Role::Assistant => { - if let Some(ref calls) = msg.tool_calls { - for call in calls { - let _ = ui_tx.send(UiMessage::ToolCall { - name: call.function.name.clone(), - args_summary: String::new(), - }); - } - } - let text = msg.content_text(); - if !text.is_empty() { - let _ = ui_tx.send(UiMessage::TextDelta(format!("{}\n", text), target)); - } - } - Role::Tool => { - let text = msg.content_text(); - let preview: String = text.lines().take(3).collect::>().join("\n"); - let truncated = if text.lines().count() > 3 { - format!("{}...", preview) - } else { - preview - }; - let _ = ui_tx.send(UiMessage::ToolResult { - name: String::new(), - result: truncated, - }); - } - } - } -}