feat(subagents): inherit MCP tools in child runtimes (#2422)
Harvested from #2377 with thanks to @buko. Threads the parent MCP tool pool into child SubAgentRuntime construction and registers MCP-backed tools for child agents when MCP is enabled, while leaving the broader mention-browser/provider/config work for focused follow-ups. Validation: - cargo fmt --all -- --check - CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-pr2377-target cargo test -p codewhale-tui tools::subagent - CARGO_TARGET_DIR=/Volumes/VIXinSSD/codewhale-target/harvest-2377-recheck cargo test -p codewhale-tui tools::subagent --all-features
This commit is contained in:
@@ -697,6 +697,12 @@ impl Engine {
|
||||
continue;
|
||||
};
|
||||
|
||||
let mcp_pool = if self.config.features.enabled(Feature::Mcp) {
|
||||
self.ensure_mcp_pool().await.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut runtime = SubAgentRuntime::new(
|
||||
client,
|
||||
self.session.model.clone(),
|
||||
@@ -714,6 +720,7 @@ impl Engine {
|
||||
)
|
||||
.with_max_spawn_depth(self.config.max_spawn_depth)
|
||||
.with_step_api_timeout(self.config.subagent_api_timeout)
|
||||
.with_mcp_pool(mcp_pool)
|
||||
.background_runtime();
|
||||
let route = resolve_subagent_assignment_route(
|
||||
&runtime,
|
||||
@@ -1179,6 +1186,12 @@ impl Engine {
|
||||
None
|
||||
};
|
||||
|
||||
let mcp_pool = if self.config.features.enabled(Feature::Mcp) {
|
||||
self.ensure_mcp_pool().await.ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let tool_registry = match mode {
|
||||
AppMode::Agent | AppMode::Yolo => {
|
||||
if self.config.features.enabled(Feature::Subagents) {
|
||||
@@ -1199,6 +1212,7 @@ impl Engine {
|
||||
)
|
||||
.with_max_spawn_depth(self.config.max_spawn_depth)
|
||||
.with_step_api_timeout(self.config.subagent_api_timeout)
|
||||
.with_mcp_pool(mcp_pool.clone())
|
||||
.with_parent_completion_tx(self.tx_subagent_completion.clone());
|
||||
if let Some(context) = fork_context_for_runtime.clone() {
|
||||
rt = rt.with_fork_context(context);
|
||||
|
||||
@@ -777,7 +777,6 @@ impl ToolRegistryBuilder {
|
||||
/// MCP tools are marked `defer_loading` by default (except discovery
|
||||
/// helpers) to keep the model-visible catalog compact.
|
||||
#[must_use]
|
||||
#[allow(dead_code)]
|
||||
pub fn with_mcp_tools(
|
||||
mut self,
|
||||
mcp_pool: std::sync::Arc<tokio::sync::Mutex<crate::mcp::McpPool>>,
|
||||
|
||||
@@ -786,6 +786,8 @@ pub struct SubAgentRuntime {
|
||||
pub parent_completion_tx: Option<mpsc::UnboundedSender<SubAgentCompletion>>,
|
||||
/// Snapshot of the request prefix visible to an opt-in forked child.
|
||||
pub fork_context: Option<SubAgentForkContext>,
|
||||
/// The parent's MCP pool if available.
|
||||
pub mcp_pool: Option<std::sync::Arc<tokio::sync::Mutex<crate::mcp::McpPool>>>,
|
||||
/// Per-step DeepSeek API timeout for the child's `create_message` call.
|
||||
/// Resolved from `[subagents] api_timeout_secs` (clamped to 1..=1800) at
|
||||
/// engine construction so a slow but legitimate model turn does not
|
||||
@@ -825,10 +827,21 @@ impl SubAgentRuntime {
|
||||
mailbox: None,
|
||||
parent_completion_tx: None,
|
||||
fork_context: None,
|
||||
mcp_pool: None,
|
||||
step_api_timeout: DEFAULT_STEP_API_TIMEOUT,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attach an MCP pool so the subagent can execute MCP tools.
|
||||
#[must_use]
|
||||
pub fn with_mcp_pool(
|
||||
mut self,
|
||||
pool: Option<std::sync::Arc<tokio::sync::Mutex<crate::mcp::McpPool>>>,
|
||||
) -> Self {
|
||||
self.mcp_pool = pool;
|
||||
self
|
||||
}
|
||||
|
||||
/// Override the per-step DeepSeek API timeout (default
|
||||
/// `DEFAULT_STEP_API_TIMEOUT`). Called by the engine after reading
|
||||
/// `[subagents] api_timeout_secs`. Tests may use this to fail fast
|
||||
@@ -959,6 +972,7 @@ impl SubAgentRuntime {
|
||||
mailbox: self.mailbox.clone(),
|
||||
parent_completion_tx: self.parent_completion_tx.clone(),
|
||||
fork_context: self.fork_context.clone(),
|
||||
mcp_pool: self.mcp_pool.clone(),
|
||||
step_api_timeout: self.step_api_timeout,
|
||||
}
|
||||
}
|
||||
@@ -4762,17 +4776,21 @@ impl SubAgentToolRegistry {
|
||||
// review, RLM, sub-agent management (so grandchildren can spawn),
|
||||
// plus per-child fresh todo/plan state.
|
||||
let context = runtime.context.clone();
|
||||
let registry = ToolRegistryBuilder::new()
|
||||
.with_full_agent_surface(
|
||||
Some(runtime.client.clone()),
|
||||
runtime.model.clone(),
|
||||
runtime.manager.clone(),
|
||||
runtime.clone(),
|
||||
runtime.allow_shell,
|
||||
todo_list,
|
||||
plan_state,
|
||||
)
|
||||
.build(context);
|
||||
let mut registry = ToolRegistryBuilder::new().with_full_agent_surface(
|
||||
Some(runtime.client.clone()),
|
||||
runtime.model.clone(),
|
||||
runtime.manager.clone(),
|
||||
runtime.clone(),
|
||||
runtime.allow_shell,
|
||||
todo_list,
|
||||
plan_state,
|
||||
);
|
||||
|
||||
if let Some(pool) = runtime.mcp_pool.as_ref() {
|
||||
registry = registry.with_mcp_tools(std::sync::Arc::clone(pool));
|
||||
}
|
||||
|
||||
let registry = registry.build(context);
|
||||
|
||||
Self {
|
||||
allowed_tools: explicit_allowed_tools,
|
||||
|
||||
@@ -1736,6 +1736,7 @@ fn stub_runtime() -> SubAgentRuntime {
|
||||
mailbox: None,
|
||||
parent_completion_tx: None,
|
||||
fork_context: None,
|
||||
mcp_pool: None,
|
||||
step_api_timeout: DEFAULT_STEP_API_TIMEOUT,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user