From 631c61fea2e241e1eeedbe948c7417d1af63829a Mon Sep 17 00:00:00 2001 From: oudecheng <13802883547@139.com> Date: Wed, 17 Jun 2026 14:43:55 +0800 Subject: [PATCH] =?UTF-8?q?feat(agent):=20=E6=94=AF=E6=8C=81=E5=AD=90?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E6=9C=80=E5=A4=A7=E5=B5=8C=E5=A5=97=E6=B7=B1?= =?UTF-8?q?=E5=BA=A6=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在配置结构体中新增 max_nesting_depth 字段,设置子代理最大嵌套深度 - 在 AgentFactory、todo_read、todo_write 等处初始化 nesting_depth 字段为 0 - 允许 Task 工具注册,使用 max_nesting_depth 控制子代理嵌套层数 - SubAgentRuntimeConfig 新增 max_nesting_depth 配置项,默认值为 1 - TaskTool 新增 max_nesting_depth 字段和带深度限制的构造函数 - 任务执行时增加嵌套深度校验,超过最大深度返回错误提示,防止无限递归创建子代理 --- src/config/mod.rs | 7 +++++++ src/gateway/agent_factory.rs | 1 + src/gateway/runtime.rs | 1 + src/gateway/tool_registry_factory.rs | 10 +++++++++- src/tools/task/runtime.rs | 9 +++++++-- src/tools/task/tool.rs | 29 ++++++++++++++++++++++++++-- src/tools/todo_read.rs | 1 + src/tools/todo_write.rs | 1 + src/tools/traits.rs | 2 ++ 9 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index cf5eead..d4af3ff 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -221,6 +221,8 @@ pub struct TaskConfig { pub ttl_hours: u64, #[serde(default = "default_task_allowed_tools")] pub allowed_tools: Vec, + #[serde(default = "default_task_max_nesting_depth")] + pub max_nesting_depth: u32, } fn default_task_enabled() -> bool { @@ -239,6 +241,10 @@ fn default_task_ttl_hours() -> u64 { 24 } +fn default_task_max_nesting_depth() -> u32 { + 1 +} + fn default_task_allowed_tools() -> Vec { vec![ "read".to_string(), @@ -264,6 +270,7 @@ impl Default for TaskConfig { explore_max_execution_secs: default_task_explore_max_execution_secs(), ttl_hours: default_task_ttl_hours(), allowed_tools: default_task_allowed_tools(), + max_nesting_depth: default_task_max_nesting_depth(), } } } diff --git a/src/gateway/agent_factory.rs b/src/gateway/agent_factory.rs index efddc66..d7abd4b 100644 --- a/src/gateway/agent_factory.rs +++ b/src/gateway/agent_factory.rs @@ -79,6 +79,7 @@ impl AgentFactory { message_id: request.message_id.map(str::to_string), message_seq: None, subagent_description: None, + nesting_depth: 0, }); // 如果有取消信号接收端,注入 Agent if let Some(token) = request.cancel_token { diff --git a/src/gateway/runtime.rs b/src/gateway/runtime.rs index 38498cc..64c895c 100644 --- a/src/gateway/runtime.rs +++ b/src/gateway/runtime.rs @@ -193,6 +193,7 @@ pub(crate) fn build_session_manager_with_sender( explore_max_execution_secs: task_config.explore_max_execution_secs, ttl_hours: task_config.ttl_hours, skills_index: skills.system_index_prompt(), + max_nesting_depth: task_config.max_nesting_depth, }; let subagent_runtime = Arc::new(DefaultSubAgentRuntime::new( diff --git a/src/gateway/tool_registry_factory.rs b/src/gateway/tool_registry_factory.rs index 0d307db..2cf3508 100644 --- a/src/gateway/tool_registry_factory.rs +++ b/src/gateway/tool_registry_factory.rs @@ -243,7 +243,15 @@ impl ToolRegistryFactory { } } - // 注意:不注册 task 工具,防止递归创建子代理 + // 注册 task 工具,允许子代理创建孙代理(深度由 TaskTool 运行时控制) + if self.is_enabled("task") && self.task_config.enabled { + if let Some(runtime) = &self.subagent_runtime { + registry.register(TaskTool::new_with_depth( + runtime.clone(), + self.task_config.max_nesting_depth, + )); + } + } registry } diff --git a/src/tools/task/runtime.rs b/src/tools/task/runtime.rs index c01746c..e111dac 100644 --- a/src/tools/task/runtime.rs +++ b/src/tools/task/runtime.rs @@ -34,6 +34,8 @@ pub struct SubAgentRuntimeConfig { pub ttl_hours: u64, /// 技能索引(可选,预生成的技能列表字符串) pub skills_index: Option, + /// 子代理最大嵌套深度(0 = 禁止嵌套,1 = 允许 1 层孙代理) + pub max_nesting_depth: u32, } impl Default for SubAgentRuntimeConfig { @@ -57,6 +59,7 @@ impl Default for SubAgentRuntimeConfig { explore_max_execution_secs: 3600, // 60分钟 ttl_hours: 24, skills_index: None, + max_nesting_depth: 1, } } } @@ -323,6 +326,7 @@ impl DefaultSubAgentRuntime { &self, session: &TaskSession, system_prompt: String, + parent_nesting_depth: u32, ) -> Result { let prompt_provider = Arc::new(StaticSystemPromptProvider::new(system_prompt)); @@ -342,6 +346,7 @@ impl DefaultSubAgentRuntime { message_id: None, message_seq: None, subagent_description: Some(session.description.clone()), + nesting_depth: parent_nesting_depth + 1, }); // 如果有 MessageBus,附加实时广播 emitter @@ -561,7 +566,7 @@ impl SubAgentRuntime for DefaultSubAgentRuntime { ); // 7. 创建子代理 - let agent = self.create_subagent(&session, system_prompt)?; + let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth)?; // 8. 执行任务 let result = self @@ -642,7 +647,7 @@ impl SubAgentRuntime for DefaultSubAgentRuntime { ); // 5. 创建子代理 - let agent = self.create_subagent(&session, system_prompt)?; + let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth)?; // 6. 使用历史继续执行 let result = self diff --git a/src/tools/task/tool.rs b/src/tools/task/tool.rs index 2ab16dd..1faa6ed 100644 --- a/src/tools/task/tool.rs +++ b/src/tools/task/tool.rs @@ -10,11 +10,24 @@ use super::types::{TaskDefinition, TaskToolArgs}; /// Task 工具 - 创建和管理子代理 pub struct TaskTool { runtime: Arc, + /// 最大嵌套深度(0 = 主 agent 不允许创建子代理,1 = 子 agent 可创建 1 层孙 agent) + max_nesting_depth: u32, } impl TaskTool { pub fn new(runtime: Arc) -> Self { - Self { runtime } + Self { + runtime, + max_nesting_depth: 0, // 主 agent 无深度限制 + } + } + + /// 创建带嵌套深度限制的 TaskTool(用于子代理) + pub fn new_with_depth(runtime: Arc, max_nesting_depth: u32) -> Self { + Self { + runtime, + max_nesting_depth, + } } } @@ -126,7 +139,19 @@ impl Tool for TaskTool { }); } - // 4. 执行任务 + // 4. 深度校验(仅对嵌套场景生效,主 agent 的 max_nesting_depth = 0 不限制) + if self.max_nesting_depth > 0 && context.nesting_depth >= self.max_nesting_depth { + return Ok(ToolResult { + success: false, + output: String::new(), + error: Some(format!( + "Cannot create nested subagent: max nesting depth ({}) reached", + self.max_nesting_depth + )), + }); + } + + // 5. 执行任务 let result = if let Some(task_id) = task_args.task_id { // 恢复现有任务 self.runtime diff --git a/src/tools/todo_read.rs b/src/tools/todo_read.rs index ecbf4ba..d9cca0f 100644 --- a/src/tools/todo_read.rs +++ b/src/tools/todo_read.rs @@ -182,6 +182,7 @@ mod tests { message_id: Some("msg-1".to_string()), message_seq: Some(1), subagent_description: None, + nesting_depth: 0, } } diff --git a/src/tools/todo_write.rs b/src/tools/todo_write.rs index 2c776cd..1656be6 100644 --- a/src/tools/todo_write.rs +++ b/src/tools/todo_write.rs @@ -402,6 +402,7 @@ mod tests { message_id: Some("msg-1".to_string()), message_seq: Some(1), subagent_description: None, + nesting_depth: 0, } } diff --git a/src/tools/traits.rs b/src/tools/traits.rs index 5b7f589..02960aa 100644 --- a/src/tools/traits.rs +++ b/src/tools/traits.rs @@ -18,6 +18,8 @@ pub struct ToolContext { pub message_seq: Option, /// 子代理标识,用于标注消息来源 pub subagent_description: Option, + /// 当前嵌套深度(0 = 主 agent,1 = 子 agent,2 = 孙 agent...) + pub nesting_depth: u32, } #[async_trait]