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:
parent
64add58caa
commit
05d6bbc912
2 changed files with 58 additions and 53 deletions
|
|
@ -454,45 +454,6 @@ impl Mind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cycle reasoning effort: none → low → high → none.
|
/// 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.
|
/// Cycle DMN autonomy: foraging → resting → paused → off → foraging.
|
||||||
fn cycle_autonomy(&mut self) {
|
fn cycle_autonomy(&mut self) {
|
||||||
let (new_state, label) = match &self.dmn {
|
let (new_state, label) = match &self.dmn {
|
||||||
|
|
@ -578,20 +539,9 @@ impl Mind {
|
||||||
MindMessage::UserInput(input) => self.submit_input(input),
|
MindMessage::UserInput(input) => self.submit_input(input),
|
||||||
MindMessage::Hotkey(action) => {
|
MindMessage::Hotkey(action) => {
|
||||||
match action {
|
match action {
|
||||||
HotkeyAction::CycleReasoning => self.cycle_reasoning(),
|
|
||||||
HotkeyAction::KillProcess => self.kill_processes().await,
|
|
||||||
HotkeyAction::Interrupt => self.interrupt().await,
|
HotkeyAction::Interrupt => self.interrupt().await,
|
||||||
HotkeyAction::CycleAutonomy => self.cycle_autonomy(),
|
HotkeyAction::CycleAutonomy => self.cycle_autonomy(),
|
||||||
HotkeyAction::AdjustSampling(param, delta) => {
|
_ => {} // Other hotkeys handled directly by UI
|
||||||
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,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MindMessage::NewSession => self.cmd_new().await,
|
MindMessage::NewSession => self.cmd_new().await,
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,55 @@ async fn cmd_retry(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cmd_cycle_reasoning(agent: &Arc<Mutex<Agent>>, ui_tx: &ui_channel::UiSender) {
|
||||||
|
if let Ok(mut ag) = agent.try_lock() {
|
||||||
|
let next = match ag.reasoning_effort.as_str() {
|
||||||
|
"none" => "low",
|
||||||
|
"low" => "high",
|
||||||
|
_ => "none",
|
||||||
|
};
|
||||||
|
ag.reasoning_effort = next.to_string();
|
||||||
|
let label = match next {
|
||||||
|
"none" => "off (monologue hidden)",
|
||||||
|
"low" => "low (brief monologue)",
|
||||||
|
"high" => "high (full monologue)",
|
||||||
|
_ => next,
|
||||||
|
};
|
||||||
|
let _ = ui_tx.send(UiMessage::Info(format!("Reasoning: {} — ^R to cycle", label)));
|
||||||
|
} else {
|
||||||
|
let _ = ui_tx.send(UiMessage::Info(
|
||||||
|
"(agent busy — reasoning change takes effect next turn)".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cmd_kill_processes(agent: &Arc<Mutex<Agent>>, ui_tx: &ui_channel::UiSender) {
|
||||||
|
let active_tools = agent.lock().await.active_tools.clone();
|
||||||
|
let mut tools = active_tools.lock().unwrap();
|
||||||
|
if tools.is_empty() {
|
||||||
|
let _ = ui_tx.send(UiMessage::Info("(no running tool calls)".into()));
|
||||||
|
} else {
|
||||||
|
for entry in tools.drain(..) {
|
||||||
|
let elapsed = entry.started.elapsed();
|
||||||
|
let _ = ui_tx.send(UiMessage::Info(format!(
|
||||||
|
" killing {} ({:.0}s): {}", entry.name, elapsed.as_secs_f64(), entry.detail,
|
||||||
|
)));
|
||||||
|
entry.handle.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cmd_adjust_sampling(agent: &Arc<Mutex<Agent>>, param: usize, delta: f32) {
|
||||||
|
if let Ok(mut ag) = agent.try_lock() {
|
||||||
|
match param {
|
||||||
|
0 => ag.temperature = (ag.temperature + delta).clamp(0.0, 2.0),
|
||||||
|
1 => ag.top_p = (ag.top_p + delta).clamp(0.0, 1.0),
|
||||||
|
2 => ag.top_k = (ag.top_k as f32 + delta).max(0.0) as u32,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn cmd_switch_model(
|
pub async fn cmd_switch_model(
|
||||||
agent: &Arc<Mutex<Agent>>,
|
agent: &Arc<Mutex<Agent>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
|
@ -271,10 +320,16 @@ pub async fn run(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send hotkey actions to Mind
|
// Handle hotkey actions
|
||||||
let actions: Vec<HotkeyAction> = app.hotkey_actions.drain(..).collect();
|
let actions: Vec<HotkeyAction> = app.hotkey_actions.drain(..).collect();
|
||||||
for action in actions {
|
for action in actions {
|
||||||
let _ = mind_tx.send(MindMessage::Hotkey(action));
|
match action {
|
||||||
|
HotkeyAction::CycleReasoning => cmd_cycle_reasoning(&agent, &ui_tx),
|
||||||
|
HotkeyAction::KillProcess => cmd_kill_processes(&agent, &ui_tx).await,
|
||||||
|
HotkeyAction::Interrupt => { let _ = mind_tx.send(MindMessage::Hotkey(action)); }
|
||||||
|
HotkeyAction::CycleAutonomy => { let _ = mind_tx.send(MindMessage::Hotkey(action)); }
|
||||||
|
HotkeyAction::AdjustSampling(param, delta) => cmd_adjust_sampling(&agent, param, delta),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.drain_messages(&mut ui_rx) {
|
if app.drain_messages(&mut ui_rx) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue