feat: subagent turn count, simple agent loop (#3597)

This commit is contained in:
Wendy Tang
2025-07-23 14:13:05 -07:00
committed by GitHub
parent a358e264a5
commit 64d311c751
2 changed files with 21 additions and 30 deletions
+8 -29
View File
@@ -1,3 +1,4 @@
use crate::agents::subagent_task_config::DEFAULT_SUBAGENT_MAX_TURNS;
use crate::{
agents::extension::ExtensionConfig,
agents::{extension_manager::ExtensionManager, Agent, TaskConfig},
@@ -203,20 +204,6 @@ impl SubAgent {
.as_ref()
.ok_or_else(|| anyhow!("No provider configured for subagent"))?;
// Check if we've exceeded max turns
{
let turn_count = *self.turn_count.lock().await;
if let Some(max_turns) = self.config.max_turns {
if turn_count >= max_turns {
self.set_status(SubAgentStatus::Completed(
"Maximum turns exceeded".to_string(),
))
.await;
return Err(anyhow!("Maximum turns ({}) exceeded", max_turns));
}
}
}
// Set status to processing
self.set_status(SubAgentStatus::Processing).await;
@@ -227,17 +214,6 @@ impl SubAgent {
conversation.push(user_message.clone());
}
// Increment turn count
{
let mut turn_count = self.turn_count.lock().await;
*turn_count += 1;
self.send_mcp_notification(
"turn_progress",
&format!("Turn {}/{}", turn_count, self.config.max_turns.unwrap_or(0)),
)
.await;
}
// Get the current conversation for context
let mut messages = self.get_conversation().await;
@@ -255,8 +231,14 @@ impl SubAgent {
// Build system prompt using the template
let system_prompt = self.build_system_prompt(&tools).await?;
// Generate response from provider with loop for tool processing (max_turns iterations)
let mut loop_count = 0;
let max_turns = self.config.max_turns.unwrap_or(DEFAULT_SUBAGENT_MAX_TURNS);
// Generate response from provider
loop {
loop_count += 1;
match Agent::generate_response_from_provider(
Arc::clone(provider),
&system_prompt,
@@ -281,7 +263,7 @@ impl SubAgent {
.collect();
// If there are no tool requests, we're done
if tool_requests.is_empty() {
if tool_requests.is_empty() || loop_count >= max_turns {
self.add_message(response.clone()).await;
// Send notification about response
@@ -291,9 +273,6 @@ impl SubAgent {
)
.await;
// Add delay before completion to ensure all processing finishes
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
// Set status back to ready and return the final response
self.set_status(SubAgentStatus::Completed("Completed!".to_string()))
.await;
@@ -1,10 +1,17 @@
use crate::providers::base::Provider;
use rmcp::model::JsonRpcMessage;
use std::env;
use std::fmt;
use std::sync::Arc;
use tokio::sync::mpsc;
use uuid::Uuid;
/// Default maximum number of turns for task execution
pub const DEFAULT_SUBAGENT_MAX_TURNS: usize = 5;
/// Environment variable name for configuring max turns
pub const GOOSE_SUBAGENT_MAX_TURNS_ENV_VAR: &str = "GOOSE_SUBAGENT_MAX_TURNS";
/// Configuration for task execution with all necessary dependencies
#[derive(Clone)]
pub struct TaskConfig {
@@ -31,7 +38,12 @@ impl TaskConfig {
id: Uuid::new_v4().to_string(),
provider,
mcp_tx,
max_turns: Some(10),
max_turns: Some(
env::var(GOOSE_SUBAGENT_MAX_TURNS_ENV_VAR)
.ok()
.and_then(|val| val.parse::<usize>().ok())
.unwrap_or(DEFAULT_SUBAGENT_MAX_TURNS),
),
}
}