move hotkey handlers from Mind to event_loop

cycle_reasoning, kill_processes, and AdjustSampling only need the
Agent lock — they're pure Agent operations. Handle them directly
in the UI event loop instead of routing through Mind.

Mind now only receives Interrupt and CycleAutonomy as hotkeys,
which genuinely need Mind state (turn handles, DMN state).

mind/mod.rs: 957 → 688 lines across the session.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2026-04-05 02:44:58 -04:00
parent 64add58caa
commit 05d6bbc912
2 changed files with 58 additions and 53 deletions

View file

@ -454,45 +454,6 @@ impl Mind {
}
/// Cycle reasoning effort: none → low → high → none.
fn cycle_reasoning(&mut self) {
if let Ok(mut agent_guard) = self.agent.try_lock() {
let next = match agent_guard.reasoning_effort.as_str() {
"none" => "low",
"low" => "high",
_ => "none",
};
agent_guard.reasoning_effort = next.to_string();
let label = match next {
"none" => "off (monologue hidden)",
"low" => "low (brief monologue)",
"high" => "high (full monologue)",
_ => next,
};
let _ = self.ui_tx.send(UiMessage::Info(format!("Reasoning: {} — ^R to cycle", label)));
} else {
let _ = self.ui_tx.send(UiMessage::Info(
"(agent busy — reasoning change takes effect next turn)".into(),
));
}
}
/// Show and kill running tool calls (Ctrl+K).
async fn kill_processes(&mut self) {
let active_tools = self.agent.lock().await.active_tools.clone();
let mut tools = active_tools.lock().unwrap();
if tools.is_empty() {
let _ = self.ui_tx.send(UiMessage::Info("(no running tool calls)".into()));
} else {
for entry in tools.drain(..) {
let elapsed = entry.started.elapsed();
let _ = self.ui_tx.send(UiMessage::Info(format!(
" killing {} ({:.0}s): {}", entry.name, elapsed.as_secs_f64(), entry.detail,
)));
entry.handle.abort();
}
}
}
/// Cycle DMN autonomy: foraging → resting → paused → off → foraging.
fn cycle_autonomy(&mut self) {
let (new_state, label) = match &self.dmn {
@ -578,20 +539,9 @@ impl Mind {
MindMessage::UserInput(input) => self.submit_input(input),
MindMessage::Hotkey(action) => {
match action {
HotkeyAction::CycleReasoning => self.cycle_reasoning(),
HotkeyAction::KillProcess => self.kill_processes().await,
HotkeyAction::Interrupt => self.interrupt().await,
HotkeyAction::CycleAutonomy => self.cycle_autonomy(),
HotkeyAction::AdjustSampling(param, delta) => {
if let Ok(mut agent) = self.agent.try_lock() {
match param {
0 => agent.temperature = (agent.temperature + delta).clamp(0.0, 2.0),
1 => agent.top_p = (agent.top_p + delta).clamp(0.0, 1.0),
2 => agent.top_k = (agent.top_k as f32 + delta).max(0.0) as u32,
_ => {}
}
}
}
_ => {} // Other hotkeys handled directly by UI
}
}
MindMessage::NewSession => self.cmd_new().await,