feat: subagent independent extension manager (#3596)

This commit is contained in:
Wendy Tang
2025-07-23 13:08:17 -07:00
committed by GitHub
parent 74140ad0f8
commit a358e264a5
3 changed files with 37 additions and 24 deletions

View File

@@ -344,9 +344,7 @@ impl Agent {
let provider = self.provider().await.ok();
let mcp_tx = self.mcp_tx.lock().await.clone();
let task_config =
TaskConfig::new(provider, Some(Arc::clone(&self.extension_manager)), mcp_tx);
let task_config = TaskConfig::new(provider, mcp_tx);
subagent_execute_task_tool::run_tasks(
tool_call.arguments.clone(),
task_config,

View File

@@ -1,5 +1,7 @@
use crate::{
agents::{Agent, TaskConfig},
agents::extension::ExtensionConfig,
agents::{extension_manager::ExtensionManager, Agent, TaskConfig},
config::ExtensionConfigManager,
message::{Message, MessageContent, ToolRequest},
prompt_template::render_global_file,
providers::errors::ProviderError,
@@ -43,6 +45,7 @@ pub struct SubAgent {
pub config: TaskConfig,
pub turn_count: Arc<Mutex<usize>>,
pub created_at: DateTime<Utc>,
pub extension_manager: Arc<RwLock<ExtensionManager>>,
}
impl SubAgent {
@@ -53,6 +56,29 @@ impl SubAgent {
) -> Result<(Arc<Self>, tokio::task::JoinHandle<()>), anyhow::Error> {
debug!("Creating new subagent with id: {}", task_config.id);
// Create a new extension manager for this subagent
let mut extension_manager = ExtensionManager::new();
// Add extensions based on task_type:
// 1. If executing dynamic task (task_type = 'text_instruction'), default to using all enabled extensions
// 2. (TODO) If executing a sub-recipe task, only use recipe extensions
// Get all enabled extensions from config
let enabled_extensions = ExtensionConfigManager::get_all()
.unwrap_or_default()
.into_iter()
.filter(|ext| ext.enabled)
.map(|ext| ext.config)
.collect::<Vec<ExtensionConfig>>();
// Add enabled extensions to the subagent's extension manager
for extension in enabled_extensions {
if let Err(e) = extension_manager.add_extension(extension).await {
debug!("Failed to add extension to subagent: {}", e);
// Continue with other extensions even if one fails
}
}
let subagent = Arc::new(SubAgent {
id: task_config.id.clone(),
conversation: Arc::new(Mutex::new(Vec::new())),
@@ -60,6 +86,7 @@ impl SubAgent {
config: task_config,
turn_count: Arc::new(Mutex::new(0)),
created_at: Utc::now(),
extension_manager: Arc::new(RwLock::new(extension_manager)),
});
// Send initial MCP notification
@@ -169,19 +196,13 @@ impl SubAgent {
self.send_mcp_notification("message_processing", &format!("Processing: {}", message))
.await;
// Get provider and extension manager from task config
// Get provider from task config
let provider = self
.config
.provider
.as_ref()
.ok_or_else(|| anyhow!("No provider configured for subagent"))?;
let extension_manager = self
.config
.extension_manager
.as_ref()
.ok_or_else(|| anyhow!("No extension manager configured for subagent"))?;
// Check if we've exceeded max turns
{
let turn_count = *self.turn_count.lock().await;
@@ -220,8 +241,9 @@ impl SubAgent {
// Get the current conversation for context
let mut messages = self.get_conversation().await;
// Get tools based on whether we're using a recipe or inheriting from parent
let tools: Vec<Tool> = extension_manager
// Get tools from the subagent's own extension manager
let tools: Vec<Tool> = self
.extension_manager
.read()
.await
.get_prefixed_tools(None)
@@ -292,7 +314,8 @@ impl SubAgent {
.await;
// Handle platform tools or dispatch to extension manager
let tool_result = match extension_manager
let tool_result = match self
.extension_manager
.read()
.await
.dispatch_tool_call(tool_call.clone())

View File

@@ -1,9 +1,8 @@
use crate::agents::extension_manager::ExtensionManager;
use crate::providers::base::Provider;
use rmcp::model::JsonRpcMessage;
use std::fmt;
use std::sync::Arc;
use tokio::sync::{mpsc, RwLock};
use tokio::sync::mpsc;
use uuid::Uuid;
/// Configuration for task execution with all necessary dependencies
@@ -11,7 +10,6 @@ use uuid::Uuid;
pub struct TaskConfig {
pub id: String,
pub provider: Option<Arc<dyn Provider>>,
pub extension_manager: Option<Arc<RwLock<ExtensionManager>>>,
pub mcp_tx: mpsc::Sender<JsonRpcMessage>,
pub max_turns: Option<usize>,
}
@@ -21,7 +19,6 @@ impl fmt::Debug for TaskConfig {
f.debug_struct("TaskConfig")
.field("id", &self.id)
.field("provider", &"<dyn Provider>")
.field("extension_manager", &"<ExtensionManager>")
.field("max_turns", &self.max_turns)
.finish()
}
@@ -29,15 +26,10 @@ impl fmt::Debug for TaskConfig {
impl TaskConfig {
/// Create a new TaskConfig with all required dependencies
pub fn new(
provider: Option<Arc<dyn Provider>>,
extension_manager: Option<Arc<RwLock<ExtensionManager>>>,
mcp_tx: mpsc::Sender<JsonRpcMessage>,
) -> Self {
pub fn new(provider: Option<Arc<dyn Provider>>, mcp_tx: mpsc::Sender<JsonRpcMessage>) -> Self {
Self {
id: Uuid::new_v4().to_string(),
provider,
extension_manager,
mcp_tx,
max_turns: Some(10),
}