Converted all external tool calling to async

This commit is contained in:
Timmy
2026-06-29 16:59:54 +01:00
parent 75f41088b1
commit feb35ddd10
49 changed files with 482 additions and 496 deletions
+18 -27
View File
@@ -1,7 +1,6 @@
//! Agent stop — terminates a running agent while preserving its worktree.
use crate::process_kill::{pids_matching, sigkill_pids_and_verify};
use crate::slog;
use crate::slog_error;
use crate::slog_warn;
use std::path::Path;
@@ -40,7 +39,7 @@ impl AgentPool {
// Step 1: snapshot the worktree path (no status mutation yet).
let worktree_info = {
let agents = self.agents.lock().map_err(|e| e.to_string())?;
let agents = self.agents.lock().await;
let agent = agents
.get(&key)
.ok_or_else(|| format!("No agent '{agent_name}' for story '{story_id}'"))?;
@@ -71,12 +70,12 @@ impl AgentPool {
"[stop_agent] No worktree path recorded for '{key}'; cannot tree-kill, \
falling back to portable_pty SIGHUP (likely no-op for claude-code)."
);
self.kill_child_for_key(&key);
self.kill_child_for_key(&key).await;
}
// Step 3: now safe to mutate. Status flip and handle abort.
let (task_handle, tx) = {
let mut agents = self.agents.lock().map_err(|e| e.to_string())?;
let mut agents = self.agents.lock().await;
let agent = agents
.get_mut(&key)
.ok_or_else(|| format!("No agent '{agent_name}' for story '{story_id}'"))?;
@@ -107,7 +106,7 @@ impl AgentPool {
// Remove from map.
{
let mut agents = self.agents.lock().map_err(|e| e.to_string())?;
let mut agents = self.agents.lock().await;
agents.remove(&key);
}
@@ -138,9 +137,7 @@ impl AgentPool {
// Snapshot active LLM agents without holding the lock during async stops.
let snapshot: Vec<(String, String, PipelineStage)> = {
let Ok(agents) = self.agents.lock() else {
return;
};
let agents = self.agents.lock().await;
agents
.iter()
.filter_map(|(key, a)| {
@@ -197,14 +194,8 @@ impl AgentPool {
///
/// Called when a story is archived so that stale entries don't accumulate.
/// Returns the number of entries removed.
pub fn remove_agents_for_story(&self, story_id: &str) -> usize {
let mut agents = match self.agents.lock() {
Ok(a) => a,
Err(e) => {
slog_error!("[agents] Failed to lock pool for cleanup of '{story_id}': {e}");
return 0;
}
};
pub async fn remove_agents_for_story(&self, story_id: &str) -> usize {
let mut agents = self.agents.lock().await;
let prefix = format!("{story_id}:");
let keys_to_remove: Vec<String> = agents
.keys()
@@ -229,30 +220,30 @@ mod tests {
// ── remove_agents_for_story tests ────────────────────────────────────────
#[test]
fn remove_agents_for_story_removes_all_entries() {
#[tokio::test]
async fn remove_agents_for_story_removes_all_entries() {
let pool = AgentPool::new_test(3001);
pool.inject_test_agent("story_a", "coder-1", AgentStatus::Completed);
pool.inject_test_agent("story_a", "qa", AgentStatus::Failed);
pool.inject_test_agent("story_b", "coder-1", AgentStatus::Running);
let removed = pool.remove_agents_for_story("story_a");
let removed = pool.remove_agents_for_story("story_a").await;
assert_eq!(removed, 2, "should remove both agents for story_a");
let agents = pool.list_agents().unwrap();
let agents = pool.list_agents().await.unwrap();
assert_eq!(agents.len(), 1, "only story_b agent should remain");
assert_eq!(agents[0].story_id, "story_b");
}
#[test]
fn remove_agents_for_story_returns_zero_when_no_match() {
#[tokio::test]
async fn remove_agents_for_story_returns_zero_when_no_match() {
let pool = AgentPool::new_test(3001);
pool.inject_test_agent("story_a", "coder-1", AgentStatus::Running);
let removed = pool.remove_agents_for_story("nonexistent");
let removed = pool.remove_agents_for_story("nonexistent").await;
assert_eq!(removed, 0);
let agents = pool.list_agents().unwrap();
let agents = pool.list_agents().await.unwrap();
assert_eq!(agents.len(), 1, "existing agents should not be affected");
}
@@ -283,12 +274,12 @@ mod tests {
pool.inject_test_agent("60_story_cleanup", "qa", AgentStatus::Completed);
pool.inject_test_agent("61_story_other", "coder-1", AgentStatus::Running);
assert_eq!(pool.list_agents().unwrap().len(), 3);
assert_eq!(pool.list_agents().await.unwrap().len(), 3);
move_story_to_done("60_story_cleanup").unwrap();
pool.remove_agents_for_story("60_story_cleanup");
pool.remove_agents_for_story("60_story_cleanup").await;
let remaining = pool.list_agents().unwrap();
let remaining = pool.list_agents().await.unwrap();
assert_eq!(
remaining.len(),
1,