ActiveTools wrapper: replace SharedActiveTools Arc<Mutex<Vec>>

New ActiveTools struct with proper methods: push, remove, abort_all,
take_finished, take_foreground, iter, len. Lives directly on AgentState,
no separate Arc<Mutex> needed.

TUI reads active tools through agent.state.try_lock(). Turn loop uses
helpers instead of manual index iteration.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-08 16:45:56 -04:00
parent 9c9618d034
commit 31a41fa042
5 changed files with 23 additions and 26 deletions

View file

@ -126,7 +126,7 @@ impl App {
temperature: 0.6,
top_p: 0.95,
top_k: 20,
agent: mind.agent.clone(),
agent,
should_quit: false,
context_info: None,
agent_state: Vec::new(),
@ -181,8 +181,6 @@ async fn start(cli: crate::user::CliArgs) -> Result<()> {
let mind = crate::mind::Mind::new(config, turn_tx).await;
let shared_active_tools = mind.agent.state.lock().await.active_tools.clone();
let mut result = Ok(());
tokio_scoped::scope(|s| {
// Mind event loop — init + run
@ -194,7 +192,7 @@ async fn start(cli: crate::user::CliArgs) -> Result<()> {
// UI event loop
s.spawn(async {
result = run(
tui::App::new(String::new(), shared_active_tools),
tui::App::new(String::new(), mind.agent.clone()),
&mind, mind_tx,
).await;
});
@ -222,15 +220,11 @@ fn hotkey_cycle_reasoning(mind: &crate::mind::Mind) {
async fn hotkey_kill_processes(mind: &crate::mind::Mind) {
let mut st = mind.agent.state.lock().await;
let active_tools = st.active_tools.clone();
let mut tools = active_tools.lock().unwrap();
if tools.is_empty() {
if st.active_tools.is_empty() {
st.notify("no running tools");
} else {
let count = tools.len();
for entry in tools.drain(..) {
entry.handle.abort();
}
let count = st.active_tools.len();
st.active_tools.abort_all();
st.notify(format!("killed {} tools", count));
}
}