Compare commits
2 Commits
761f8577be
...
2607ca4aa4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2607ca4aa4 | ||
|
|
e506ffd539 |
@ -80,6 +80,8 @@ impl AgentFactory {
|
||||
message_seq: None,
|
||||
subagent_description: None,
|
||||
nesting_depth: 0,
|
||||
task_id: None,
|
||||
parent_task_id: None,
|
||||
});
|
||||
// 如果有取消信号接收端,注入 Agent
|
||||
if let Some(token) = request.cancel_token {
|
||||
|
||||
@ -209,9 +209,9 @@ pub(crate) fn build_session_manager_with_sender(
|
||||
|
||||
// 注册 task 工具到子代理工具集(需在 runtime 创建之后,打破循环依赖)
|
||||
if factory.is_enabled("task") {
|
||||
subagent_tools.register(TaskTool::new_with_depth(
|
||||
subagent_tools.register(TaskTool::new(
|
||||
subagent_runtime.clone(),
|
||||
task_config.max_nesting_depth,
|
||||
Some(task_config.max_nesting_depth),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@ -164,7 +164,7 @@ impl ToolRegistryFactory {
|
||||
// 注册 Task 工具(如果启用且有 subagent_runtime)
|
||||
if self.is_enabled("task") && self.task_config.enabled {
|
||||
if let Some(runtime) = &self.subagent_runtime {
|
||||
registry.register(TaskTool::new(runtime.clone()));
|
||||
registry.register(TaskTool::new(runtime.clone(), None));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -212,6 +212,8 @@ pub enum WsOutbound {
|
||||
subagent_type: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
topic_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
parent_task_id: Option<String>,
|
||||
},
|
||||
#[serde(rename = "session_established")]
|
||||
SessionEstablished { session_id: String },
|
||||
|
||||
@ -173,6 +173,7 @@ pub(crate) fn ws_outbound_from_outbound_message(message: &OutboundMessage) -> Ve
|
||||
description: message.metadata.get("task_description").cloned().unwrap_or_default(),
|
||||
subagent_type: message.metadata.get("task_subagent_type").cloned().unwrap_or_default(),
|
||||
topic_id: message.metadata.get("topic_id").cloned(),
|
||||
parent_task_id: message.metadata.get("parent_task_id").cloned(),
|
||||
}],
|
||||
OutboundEventKind::StreamDelta => vec![WsOutbound::StreamDelta {
|
||||
id: message.tool_call_id.clone().unwrap_or_default(),
|
||||
|
||||
@ -327,6 +327,7 @@ impl DefaultSubAgentRuntime {
|
||||
session: &TaskSession,
|
||||
system_prompt: String,
|
||||
parent_nesting_depth: u32,
|
||||
parent_task_id: Option<String>,
|
||||
) -> Result<AgentLoop, TaskError> {
|
||||
let prompt_provider = Arc::new(StaticSystemPromptProvider::new(system_prompt));
|
||||
|
||||
@ -347,6 +348,8 @@ impl DefaultSubAgentRuntime {
|
||||
message_seq: None,
|
||||
subagent_description: Some(session.description.clone()),
|
||||
nesting_depth: parent_nesting_depth + 1,
|
||||
task_id: Some(session.id.clone()),
|
||||
parent_task_id,
|
||||
});
|
||||
|
||||
// 如果有 MessageBus,附加实时广播 emitter
|
||||
@ -534,6 +537,11 @@ impl SubAgentRuntime for DefaultSubAgentRuntime {
|
||||
metadata.insert("task_subagent_type".to_string(), session.subagent_type.clone());
|
||||
metadata.insert("topic_id".to_string(), session.parent_topic_id.clone().unwrap_or_default());
|
||||
|
||||
// 如果是子智能体创建的孙智能体,传递父 task_id
|
||||
if let Some(ref ptid) = parent_context.task_id {
|
||||
metadata.insert("parent_task_id".to_string(), ptid.clone());
|
||||
}
|
||||
|
||||
let event = OutboundMessage {
|
||||
channel: session.parent_channel_name.clone(),
|
||||
chat_id: session.parent_chat_id.clone(),
|
||||
@ -566,7 +574,7 @@ impl SubAgentRuntime for DefaultSubAgentRuntime {
|
||||
);
|
||||
|
||||
// 7. 创建子代理
|
||||
let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth)?;
|
||||
let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth, parent_context.task_id.clone())?;
|
||||
|
||||
// 8. 执行任务
|
||||
let result = self
|
||||
@ -647,7 +655,7 @@ impl SubAgentRuntime for DefaultSubAgentRuntime {
|
||||
);
|
||||
|
||||
// 5. 创建子代理
|
||||
let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth)?;
|
||||
let agent = self.create_subagent(&session, system_prompt, parent_context.nesting_depth, parent_context.task_id.clone())?;
|
||||
|
||||
// 6. 使用历史继续执行
|
||||
let result = self
|
||||
|
||||
@ -10,20 +10,15 @@ use super::types::{TaskDefinition, TaskToolArgs};
|
||||
/// Task 工具 - 创建和管理子代理
|
||||
pub struct TaskTool {
|
||||
runtime: Arc<dyn SubAgentRuntime>,
|
||||
/// 最大嵌套深度(0 = 无限制用于主 agent,>0 = 限制子代理最大嵌套层级)
|
||||
max_nesting_depth: u32,
|
||||
/// 最大嵌套深度(None = 无限制用于主 agent,Some(N) = 允许最多 N 层嵌套)
|
||||
max_nesting_depth: Option<u32>,
|
||||
}
|
||||
|
||||
impl TaskTool {
|
||||
pub fn new(runtime: Arc<dyn SubAgentRuntime>) -> Self {
|
||||
Self {
|
||||
runtime,
|
||||
max_nesting_depth: 0, // 主 agent 无深度限制
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建带嵌套深度限制的 TaskTool(用于子代理)
|
||||
pub fn new_with_depth(runtime: Arc<dyn SubAgentRuntime>, max_nesting_depth: u32) -> Self {
|
||||
/// 创建 TaskTool
|
||||
/// - `max_nesting_depth = None`:无深度限制(主 agent)
|
||||
/// - `max_nesting_depth = Some(N)`:允许最多 N 层嵌套(子 agent)
|
||||
pub fn new(runtime: Arc<dyn SubAgentRuntime>, max_nesting_depth: Option<u32>) -> Self {
|
||||
Self {
|
||||
runtime,
|
||||
max_nesting_depth,
|
||||
@ -139,17 +134,20 @@ impl Tool for TaskTool {
|
||||
});
|
||||
}
|
||||
|
||||
// 4. 深度校验(仅对嵌套场景生效,主 agent 的 max_nesting_depth = 0 不限制)
|
||||
if self.max_nesting_depth > 0 && context.nesting_depth >= self.max_nesting_depth {
|
||||
// 4. 深度校验(仅对嵌套场景生效,None = 不限制)
|
||||
// Some(N) 表示允许最多 N 层嵌套:depth=1 的 agent 可创建 depth=2,但 depth=2 不能再创建
|
||||
if let Some(max_depth) = self.max_nesting_depth {
|
||||
if context.nesting_depth > max_depth {
|
||||
return Ok(ToolResult {
|
||||
success: false,
|
||||
output: String::new(),
|
||||
error: Some(format!(
|
||||
"Cannot create nested subagent: max nesting depth ({}) reached",
|
||||
self.max_nesting_depth
|
||||
max_depth
|
||||
)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 执行任务
|
||||
let result = if let Some(task_id) = task_args.task_id {
|
||||
|
||||
@ -183,6 +183,8 @@ mod tests {
|
||||
message_seq: Some(1),
|
||||
subagent_description: None,
|
||||
nesting_depth: 0,
|
||||
task_id: None,
|
||||
parent_task_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -409,6 +409,8 @@ mod tests {
|
||||
message_seq: Some(1),
|
||||
subagent_description: None,
|
||||
nesting_depth: 0,
|
||||
task_id: None,
|
||||
parent_task_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,10 @@ pub struct ToolContext {
|
||||
pub subagent_description: Option<String>,
|
||||
/// 当前嵌套深度(0 = 主 agent,1 = 子 agent,2 = 孙 agent...)
|
||||
pub nesting_depth: u32,
|
||||
/// 当前智能体自身的任务 ID(主 agent 为 None,子/孙 agent 为 Some(uuid))
|
||||
pub task_id: Option<String>,
|
||||
/// 父任务 ID(仅子/孙智能体有值,用于构建任务层级)
|
||||
pub parent_task_id: Option<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
||||
@ -431,6 +431,8 @@ export function useChat(): UseChatReturn {
|
||||
const msg = message as TaskStarted
|
||||
// 只 backfill 当前话题的 task tool_call,避免跨话题串扰
|
||||
if (msg.topic_id && msg.topic_id !== selectedTopicRef.current) break
|
||||
// 孙智能体的 TaskStarted 不应 backfill 到主视图
|
||||
if (msg.parent_task_id) break
|
||||
|
||||
// 立即更新对应的 task tool_call,让用户可以点击查看实时进度
|
||||
setMessages((prev) => {
|
||||
|
||||
@ -101,6 +101,7 @@ export interface TaskStarted {
|
||||
description: string
|
||||
subagent_type: string
|
||||
topic_id?: string
|
||||
parent_task_id?: string
|
||||
}
|
||||
|
||||
export interface SessionEstablished {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user