diff --git a/crates/goose-agent/src/subagent.rs b/crates/goose-agent/src/subagent.rs index 6f992dd33c..93b5bf3fb4 100644 --- a/crates/goose-agent/src/subagent.rs +++ b/crates/goose-agent/src/subagent.rs @@ -34,8 +34,6 @@ pub trait SubagentRunner: MaybeSend + MaybeSync { conversation: &Conversation, ) -> Vec; - fn ready(&self, parent_session: &S, conversation: &Conversation) -> Result; - async fn start( &self, parent_session: &S, @@ -220,10 +218,7 @@ where self.runner .started_subagent_session_ids(session, conversation), ); - if pending.is_empty() || !self.runner.ready(session, conversation)? { - return not_applicable(); - } - let remaining = pending.len() - 1; + let remaining = pending.len().saturating_sub(1); let mut running = self.running.lock().await; for subagent_session_id in &pending { diff --git a/crates/goose-agent/tests/subagent.rs b/crates/goose-agent/tests/subagent.rs index 48571c92c0..3f6c554081 100644 --- a/crates/goose-agent/tests/subagent.rs +++ b/crates/goose-agent/tests/subagent.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; -use anyhow::Result; use async_trait::async_trait; use futures::future; use futures::FutureExt; @@ -28,7 +27,6 @@ struct FakeRunner { started: Mutex>, events: Mutex>, started_subagent_session_ids: Vec, - blocked: bool, stall_next_hook: AtomicBool, } @@ -68,10 +66,6 @@ impl SubagentRunner for FakeRunner { self.started_subagent_session_ids.clone() } - fn ready(&self, _parent_session: &Parent, _conversation: &Conversation) -> Result { - Ok(!self.blocked) - } - async fn start( &self, _parent_session: &Parent, @@ -192,21 +186,6 @@ async fn stop( ) } -#[tokio::test] -async fn nothing_starts_until_the_runner_is_ready() { - let runner = Arc::new(FakeRunner { - blocked: true, - ..fake(&["a"]) - }); - runner.finished("a", SubagentOutcome::Completed("done".into())); - - let delivered = run_once(&operation(&runner), &[kickoff()]).await; - - assert!(delivered.is_empty()); - assert!(runner.started().is_empty()); - assert!(runner.events().is_empty()); -} - #[tokio::test] async fn a_finished_subagent_is_delivered_without_running() { let runner = Arc::new(fake(&["a"])); diff --git a/crates/goose/src/agents/state_machine/ops_foreground_subagent.rs b/crates/goose/src/agents/state_machine/ops_foreground_subagent.rs index db518eb0fe..223537ce7a 100644 --- a/crates/goose/src/agents/state_machine/ops_foreground_subagent.rs +++ b/crates/goose/src/agents/state_machine/ops_foreground_subagent.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use async_trait::async_trait; use futures::future::{self, BoxFuture}; use goose_agent::subagent::{SubagentOutcome, SubagentRunner}; @@ -86,7 +85,9 @@ impl SubagentRunner for ForegroundSubagentRunner { parent_session: &Session, conversation: &Conversation, ) -> Vec { - if parent_session.session_type == SessionType::SubAgent { + let all_tool_calls_answered = messages_since_kickoff(conversation) + .is_ok_and(|messages| !awaits_tool_responses(messages)); + if parent_session.session_type == SessionType::SubAgent || !all_tool_calls_answered { return Vec::new(); } conversation @@ -97,12 +98,6 @@ impl SubagentRunner for ForegroundSubagentRunner { .collect() } - fn ready(&self, _parent_session: &Session, conversation: &Conversation) -> Result { - Ok(!awaits_tool_responses(messages_since_kickoff( - conversation, - )?)) - } - async fn start( &self, parent_session: &Session, @@ -154,6 +149,7 @@ impl SubagentRunner for ForegroundSubagentRunner { mod tests { use std::sync::Arc; + use anyhow::Result; use goose_agent::events::AgentEvent; use goose_agent::subagent::ForegroundSubagentOperation; use rmcp::model::{CallToolRequestParams, CallToolResult, ContentBlock, MetaObject}; @@ -308,6 +304,7 @@ mod tests { let mut failed_delegate = delegate_result("failed", true); failed_delegate.is_error = Some(true); let conversation = Conversation::new_unvalidated(vec![ + Message::user().with_text("delegate"), Message::user() .with_tool_response("a", Ok(delegate_result("first", true))) .with_tool_response("b", Ok(delegate_result("background", false))) @@ -351,13 +348,18 @@ mod tests { requests, delegate_message("s1"), ]; - assert!(!runner.ready(&parent, &Conversation::new_unvalidated(messages.clone()))?); + assert!(runner + .started_subagent_session_ids(&parent, &Conversation::new_unvalidated(messages.clone())) + .is_empty()); messages.push(Message::user().with_tool_response( "other-call", Ok(CallToolResult::success(vec![ContentBlock::text("done")])), )); - assert!(runner.ready(&parent, &Conversation::new_unvalidated(messages))?); + assert_eq!( + runner.started_subagent_session_ids(&parent, &Conversation::new_unvalidated(messages)), + ["s1"] + ); Ok(()) }