From 4eb0c891c410e1ab08b98a4d6ce89b2d258da1ab Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sun, 5 Apr 2026 03:08:36 -0400 Subject: [PATCH] mind: move DMN commands to event_loop, remove MindMessage variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /dmn, /sleep, /wake, /pause now lock MindState directly from the UI event loop. No MindMessage roundtrip needed — they're just state transitions + info display. MindMessage reduced to: Hotkey (Interrupt, CycleAutonomy), NewSession, Score. Everything else handled directly by UI. Co-Authored-By: Kent Overstreet --- src/mind/mod.rs | 113 ++++++++++++++++------------------------- src/user/event_loop.rs | 24 ++++++--- 2 files changed, 60 insertions(+), 77 deletions(-) diff --git a/src/mind/mod.rs b/src/mind/mod.rs index cf9b301..3296571 100644 --- a/src/mind/mod.rs +++ b/src/mind/mod.rs @@ -347,76 +347,51 @@ impl Mind { biased; Some(msg) = input_rx.recv() => { - { - let mut s = self.shared.lock().unwrap(); - match msg { - MindMessage::Hotkey(HotkeyAction::CycleAutonomy) => { - let label = s.cycle_autonomy(); - let _ = self.ui_tx.send(UiMessage::Info( - format!("DMN → {} (Ctrl+P to cycle)", label), - )); - } - MindMessage::NewSession => { - s.dmn_sleep(); - let _ = self.ui_tx.send(UiMessage::Info("New session started.".into())); - } - MindMessage::Score => { - if !s.scoring_in_flight { - s.scoring_in_flight = true; - } else { - let _ = self.ui_tx.send(UiMessage::Info("(scoring already in progress)".into())); - } - } - MindMessage::DmnQuery => { - let _ = self.ui_tx.send(UiMessage::Info(format!("DMN: {:?} ({}/{})", s.dmn, s.dmn_turns, s.max_dmn_turns))); - } - MindMessage::DmnSleep => { - s.dmn_sleep(); - let _ = self.ui_tx.send(UiMessage::Info("DMN sleeping.".into())); - } - MindMessage::DmnWake => { - s.dmn_wake(); - let _ = self.ui_tx.send(UiMessage::Info("DMN foraging.".into())); - } - MindMessage::DmnPause => { - s.dmn_pause(); - let _ = self.ui_tx.send(UiMessage::Info("DMN paused.".into())); - } - MindMessage::Hotkey(HotkeyAction::Interrupt) => { - s.interrupt(); - } - _ => {} + match msg { + MindMessage::Hotkey(HotkeyAction::CycleAutonomy) => { + let label = self.shared.lock().unwrap().cycle_autonomy(); + let _ = self.ui_tx.send(UiMessage::Info( + format!("DMN → {} (Ctrl+P to cycle)", label), + )); } - } - // Handle interrupt — kill processes and abort turn - if matches!(msg, MindMessage::Hotkey(HotkeyAction::Interrupt)) { - let ag = self.agent.lock().await; - let mut tools = ag.active_tools.lock().unwrap(); - for entry in tools.drain(..) { entry.handle.abort(); } - drop(tools); drop(ag); - if let Some(h) = self.turn_handle.take() { h.abort(); } - self.shared.lock().unwrap().turn_active = false; - let _ = self.turn_watch.send(false); - let _ = self.ui_tx.send(UiMessage::Info("(interrupted)".into())); - } - // Handle /new — reset agent - if matches!(msg, MindMessage::NewSession) { - let new_log = log::ConversationLog::new( - self.config.session_dir.join("conversation.jsonl"), - ).ok(); - let mut ag = self.agent.lock().await; - let shared_ctx = ag.shared_context.clone(); - let shared_tools = ag.active_tools.clone(); - *ag = Agent::new( - ApiClient::new(&self.config.api_base, &self.config.api_key, &self.config.model), - self.config.system_prompt.clone(), self.config.context_parts.clone(), - self.config.app.clone(), self.config.prompt_file.clone(), - new_log, shared_ctx, shared_tools, - ); - } - // Handle /score — spawn scoring - if matches!(msg, MindMessage::Score) && self.shared.lock().unwrap().scoring_in_flight { - self.start_memory_scoring(); + MindMessage::Hotkey(HotkeyAction::Interrupt) => { + self.shared.lock().unwrap().interrupt(); + let ag = self.agent.lock().await; + let mut tools = ag.active_tools.lock().unwrap(); + for entry in tools.drain(..) { entry.handle.abort(); } + drop(tools); drop(ag); + if let Some(h) = self.turn_handle.take() { h.abort(); } + self.shared.lock().unwrap().turn_active = false; + let _ = self.turn_watch.send(false); + let _ = self.ui_tx.send(UiMessage::Info("(interrupted)".into())); + } + MindMessage::NewSession => { + self.shared.lock().unwrap().dmn_sleep(); + let new_log = log::ConversationLog::new( + self.config.session_dir.join("conversation.jsonl"), + ).ok(); + let mut ag = self.agent.lock().await; + let shared_ctx = ag.shared_context.clone(); + let shared_tools = ag.active_tools.clone(); + *ag = Agent::new( + ApiClient::new(&self.config.api_base, &self.config.api_key, &self.config.model), + self.config.system_prompt.clone(), self.config.context_parts.clone(), + self.config.app.clone(), self.config.prompt_file.clone(), + new_log, shared_ctx, shared_tools, + ); + let _ = self.ui_tx.send(UiMessage::Info("New session started.".into())); + } + MindMessage::Score => { + let mut s = self.shared.lock().unwrap(); + if !s.scoring_in_flight { + s.scoring_in_flight = true; + drop(s); + self.start_memory_scoring(); + } else { + let _ = self.ui_tx.send(UiMessage::Info("(scoring already in progress)".into())); + } + } + _ => {} } // Check for pending input let action = self.shared.lock().unwrap().take_pending_input(); diff --git a/src/user/event_loop.rs b/src/user/event_loop.rs index 749d953..aeca534 100644 --- a/src/user/event_loop.rs +++ b/src/user/event_loop.rs @@ -20,10 +20,6 @@ use crate::user::ui_channel::{self, UiMessage}; /// Messages from the UI to the Mind. pub enum MindMessage { Hotkey(HotkeyAction), - DmnSleep, - DmnWake, - DmnPause, - DmnQuery, NewSession, Score, } @@ -289,10 +285,22 @@ pub async fn run( } } "/new" | "/clear" => { let _ = mind_tx.send(MindMessage::NewSession); } - "/dmn" => { let _ = mind_tx.send(MindMessage::DmnQuery); } - "/sleep" => { let _ = mind_tx.send(MindMessage::DmnSleep); } - "/wake" => { let _ = mind_tx.send(MindMessage::DmnWake); } - "/pause" => { let _ = mind_tx.send(MindMessage::DmnPause); } + "/dmn" => { + let s = shared_mind.lock().unwrap(); + let _ = ui_tx.send(UiMessage::Info(format!("DMN: {:?} ({}/{})", s.dmn, s.dmn_turns, s.max_dmn_turns))); + } + "/sleep" => { + shared_mind.lock().unwrap().dmn_sleep(); + let _ = ui_tx.send(UiMessage::Info("DMN sleeping.".into())); + } + "/wake" => { + shared_mind.lock().unwrap().dmn_wake(); + let _ = ui_tx.send(UiMessage::Info("DMN foraging.".into())); + } + "/pause" => { + shared_mind.lock().unwrap().dmn_pause(); + let _ = ui_tx.send(UiMessage::Info("DMN paused.".into())); + } "/score" => { let _ = mind_tx.send(MindMessage::Score); } "/retry" => { let agent = agent.clone();