786 lines
24 KiB
Python
786 lines
24 KiB
Python
"""
|
||
Agent 协作工具
|
||
|
||
提供动态Agent创建、通信和管理功能
|
||
"""
|
||
|
||
import logging
|
||
from typing import Optional, List, Dict, Any
|
||
from pydantic import BaseModel, Field
|
||
|
||
from .base import AgentTool, ToolResult
|
||
from ..core.registry import agent_registry
|
||
from ..core.message import message_bus, MessageType, MessagePriority
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class CreateAgentInput(BaseModel):
|
||
"""创建Agent输入参数"""
|
||
name: str = Field(..., description="Agent名称")
|
||
task: str = Field(..., description="任务描述")
|
||
agent_type: str = Field(
|
||
default="specialist",
|
||
description="Agent类型: analysis(分析), verification(验证), specialist(专家)"
|
||
)
|
||
knowledge_modules: Optional[str] = Field(
|
||
default=None,
|
||
description="知识模块,逗号分隔,最多5个。如: sql_injection,xss,authentication"
|
||
)
|
||
inherit_context: bool = Field(
|
||
default=True,
|
||
description="是否继承父Agent的上下文"
|
||
)
|
||
execute_immediately: bool = Field(
|
||
default=False,
|
||
description="是否立即执行子Agent(否则只创建不执行)"
|
||
)
|
||
context: Optional[Dict[str, Any]] = Field(
|
||
default=None,
|
||
description="传递给子Agent的上下文数据"
|
||
)
|
||
|
||
|
||
class CreateSubAgentTool(AgentTool):
|
||
"""
|
||
创建子Agent工具
|
||
|
||
允许Agent动态创建专业化的子Agent来处理特定任务。
|
||
子Agent可以加载特定的知识模块,专注于特定领域。
|
||
|
||
支持两种模式:
|
||
1. 仅创建:创建Agent但不执行,后续可以批量执行
|
||
2. 立即执行:创建并立即执行Agent,等待结果返回
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
parent_agent_id: str,
|
||
llm_service=None,
|
||
tools: Dict[str, Any] = None,
|
||
event_emitter=None,
|
||
):
|
||
super().__init__()
|
||
self.parent_agent_id = parent_agent_id
|
||
self.llm_service = llm_service
|
||
self.tools = tools or {}
|
||
self.event_emitter = event_emitter
|
||
|
||
# 子Agent执行器(延迟初始化)
|
||
self._sub_executor = None
|
||
|
||
def _get_executor(self):
|
||
"""获取子Agent执行器"""
|
||
if self._sub_executor is None and self.llm_service:
|
||
from ..core.executor import SubAgentExecutor
|
||
# 需要获取父Agent实例
|
||
parent_agent = agent_registry.get_agent(self.parent_agent_id)
|
||
if parent_agent:
|
||
self._sub_executor = SubAgentExecutor(
|
||
parent_agent=parent_agent,
|
||
llm_service=self.llm_service,
|
||
tools=self.tools,
|
||
event_emitter=self.event_emitter,
|
||
)
|
||
return self._sub_executor
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "create_sub_agent"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """创建专业化的子Agent来处理特定任务。
|
||
|
||
使用场景:
|
||
1. 发现需要深入分析的特定漏洞类型
|
||
2. 需要专业知识来验证某个发现
|
||
3. 任务过于复杂需要分解
|
||
|
||
参数:
|
||
- name: Agent名称(如 "SQL注入专家")
|
||
- task: 具体任务描述
|
||
- agent_type: Agent类型 (analysis/verification/specialist)
|
||
- knowledge_modules: 知识模块,逗号分隔(如 "sql_injection,database_security")
|
||
- inherit_context: 是否继承当前上下文
|
||
- execute_immediately: 是否立即执行(默认false,仅创建)
|
||
- context: 传递给子Agent的上下文数据
|
||
|
||
注意:每个Agent最多加载5个知识模块。"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return CreateAgentInput
|
||
|
||
async def _execute(
|
||
self,
|
||
name: str,
|
||
task: str,
|
||
agent_type: str = "specialist",
|
||
knowledge_modules: Optional[str] = None,
|
||
inherit_context: bool = True,
|
||
execute_immediately: bool = False,
|
||
context: Optional[Dict[str, Any]] = None,
|
||
**kwargs
|
||
) -> ToolResult:
|
||
"""创建子Agent"""
|
||
|
||
if not name or not name.strip():
|
||
return ToolResult(success=False, error="Agent名称不能为空")
|
||
|
||
if not task or not task.strip():
|
||
return ToolResult(success=False, error="任务描述不能为空")
|
||
|
||
# 解析知识模块
|
||
modules = []
|
||
if knowledge_modules:
|
||
modules = [m.strip() for m in knowledge_modules.split(",") if m.strip()]
|
||
if len(modules) > 5:
|
||
return ToolResult(
|
||
success=False,
|
||
error="知识模块数量不能超过5个"
|
||
)
|
||
|
||
# 验证知识模块(如果有)
|
||
if modules:
|
||
from ..knowledge import knowledge_loader
|
||
validation = knowledge_loader.validate_modules(modules)
|
||
if validation["invalid"]:
|
||
available = knowledge_loader.get_all_module_names()
|
||
return ToolResult(
|
||
success=False,
|
||
error=f"无效的知识模块: {validation['invalid']}。可用模块: {', '.join(available)}"
|
||
)
|
||
|
||
# 生成Agent ID
|
||
from ..core.state import _generate_agent_id
|
||
agent_id = _generate_agent_id()
|
||
|
||
# 注册到注册表
|
||
node = agent_registry.register_agent(
|
||
agent_id=agent_id,
|
||
agent_name=name.strip(),
|
||
agent_type=agent_type,
|
||
task=task.strip(),
|
||
parent_id=self.parent_agent_id,
|
||
knowledge_modules=modules,
|
||
)
|
||
|
||
# 创建消息队列
|
||
message_bus.create_queue(agent_id)
|
||
|
||
logger.info(f"Created sub-agent: {name} ({agent_id}), parent: {self.parent_agent_id}")
|
||
|
||
# 如果需要立即执行
|
||
if execute_immediately:
|
||
executor = self._get_executor()
|
||
if executor:
|
||
# 准备上下文
|
||
exec_context = context or {}
|
||
exec_context["knowledge_modules"] = modules
|
||
|
||
# 执行子Agent
|
||
exec_result = await executor.create_and_run_sub_agent(
|
||
agent_type=agent_type if agent_type in ["analysis", "verification"] else "analysis",
|
||
task=task.strip(),
|
||
context=exec_context,
|
||
knowledge_modules=modules,
|
||
)
|
||
|
||
# 更新注册表状态
|
||
if exec_result.get("success"):
|
||
agent_registry.update_agent_status(agent_id, "completed", exec_result)
|
||
else:
|
||
agent_registry.update_agent_status(agent_id, "failed", {"error": exec_result.get("error")})
|
||
|
||
return ToolResult(
|
||
success=exec_result.get("success", False),
|
||
data={
|
||
"message": f"子Agent '{name}' 已执行完成" if exec_result.get("success") else f"子Agent '{name}' 执行失败",
|
||
"agent_id": agent_id,
|
||
"execution_result": exec_result,
|
||
"findings": exec_result.get("data", {}).get("findings", []) if exec_result.get("success") else [],
|
||
},
|
||
error=exec_result.get("error"),
|
||
metadata=node,
|
||
)
|
||
else:
|
||
logger.warning("SubAgentExecutor not available, agent created but not executed")
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"message": f"子Agent '{name}' 已创建",
|
||
"agent_id": agent_id,
|
||
"agent_info": {
|
||
"id": agent_id,
|
||
"name": name,
|
||
"type": agent_type,
|
||
"task": task[:100],
|
||
"knowledge_modules": modules,
|
||
"parent_id": self.parent_agent_id,
|
||
"status": "created",
|
||
}
|
||
},
|
||
metadata=node,
|
||
)
|
||
|
||
|
||
class SendMessageInput(BaseModel):
|
||
"""发送消息输入参数"""
|
||
target_agent_id: str = Field(..., description="目标Agent ID")
|
||
message: str = Field(..., description="消息内容")
|
||
message_type: str = Field(
|
||
default="information",
|
||
description="消息类型: query(查询), instruction(指令), information(信息)"
|
||
)
|
||
priority: str = Field(
|
||
default="normal",
|
||
description="优先级: low, normal, high, urgent"
|
||
)
|
||
|
||
|
||
class SendMessageTool(AgentTool):
|
||
"""
|
||
发送消息工具
|
||
|
||
向其他Agent发送消息,实现Agent间通信
|
||
"""
|
||
|
||
def __init__(self, sender_agent_id: str):
|
||
super().__init__()
|
||
self.sender_agent_id = sender_agent_id
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "send_message"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """向其他Agent发送消息。
|
||
|
||
使用场景:
|
||
1. 向子Agent发送指令
|
||
2. 向父Agent报告进展
|
||
3. 请求其他Agent提供信息
|
||
|
||
参数:
|
||
- target_agent_id: 目标Agent的ID
|
||
- message: 消息内容
|
||
- message_type: 消息类型 (query/instruction/information)
|
||
- priority: 优先级 (low/normal/high/urgent)"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return SendMessageInput
|
||
|
||
async def _execute(
|
||
self,
|
||
target_agent_id: str,
|
||
message: str,
|
||
message_type: str = "information",
|
||
priority: str = "normal",
|
||
**kwargs
|
||
) -> ToolResult:
|
||
"""发送消息"""
|
||
|
||
if not target_agent_id:
|
||
return ToolResult(success=False, error="目标Agent ID不能为空")
|
||
|
||
if not message or not message.strip():
|
||
return ToolResult(success=False, error="消息内容不能为空")
|
||
|
||
# 检查目标Agent是否存在
|
||
target_node = agent_registry.get_agent_node(target_agent_id)
|
||
if not target_node:
|
||
return ToolResult(
|
||
success=False,
|
||
error=f"目标Agent '{target_agent_id}' 不存在"
|
||
)
|
||
|
||
# 转换消息类型
|
||
try:
|
||
msg_type = MessageType(message_type)
|
||
except ValueError:
|
||
msg_type = MessageType.INFORMATION
|
||
|
||
try:
|
||
msg_priority = MessagePriority(priority)
|
||
except ValueError:
|
||
msg_priority = MessagePriority.NORMAL
|
||
|
||
# 发送消息
|
||
sent_message = message_bus.send_message(
|
||
from_agent=self.sender_agent_id,
|
||
to_agent=target_agent_id,
|
||
content=message.strip(),
|
||
message_type=msg_type,
|
||
priority=msg_priority,
|
||
)
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"message": f"消息已发送到 '{target_node['name']}'",
|
||
"message_id": sent_message.id,
|
||
"target_agent": {
|
||
"id": target_agent_id,
|
||
"name": target_node["name"],
|
||
"status": target_node["status"],
|
||
}
|
||
},
|
||
metadata=sent_message.to_dict(),
|
||
)
|
||
|
||
|
||
class ViewAgentGraphTool(AgentTool):
|
||
"""
|
||
查看Agent图工具
|
||
|
||
查看当前的Agent树结构和状态
|
||
"""
|
||
|
||
def __init__(self, current_agent_id: str):
|
||
super().__init__()
|
||
self.current_agent_id = current_agent_id
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "view_agent_graph"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """查看当前的Agent树结构和状态。
|
||
|
||
显示:
|
||
- 所有Agent及其层级关系
|
||
- 每个Agent的状态和任务
|
||
- 加载的知识模块"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return None
|
||
|
||
async def _execute(self, **kwargs) -> ToolResult:
|
||
"""查看Agent图"""
|
||
|
||
tree_view = agent_registry.get_agent_tree_view()
|
||
stats = agent_registry.get_statistics()
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"graph_structure": tree_view,
|
||
"summary": stats,
|
||
"current_agent_id": self.current_agent_id,
|
||
},
|
||
)
|
||
|
||
|
||
class WaitForMessageTool(AgentTool):
|
||
"""
|
||
等待消息工具
|
||
|
||
让Agent进入等待状态,等待其他Agent的消息
|
||
"""
|
||
|
||
def __init__(self, agent_id: str, agent_state=None):
|
||
super().__init__()
|
||
self.agent_id = agent_id
|
||
self.agent_state = agent_state
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "wait_for_message"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """进入等待状态,等待其他Agent或用户的消息。
|
||
|
||
使用场景:
|
||
1. 等待子Agent完成任务并报告
|
||
2. 等待用户提供更多信息
|
||
3. 等待其他Agent的协作响应
|
||
|
||
参数:
|
||
- reason: 等待原因"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return None
|
||
|
||
async def _execute(
|
||
self,
|
||
reason: str = "等待消息",
|
||
**kwargs
|
||
) -> ToolResult:
|
||
"""进入等待状态"""
|
||
|
||
# 更新Agent状态
|
||
if self.agent_state:
|
||
self.agent_state.enter_waiting_state(reason)
|
||
|
||
# 更新注册表
|
||
agent_registry.update_agent_status(self.agent_id, "waiting")
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"status": "waiting",
|
||
"message": f"Agent正在等待: {reason}",
|
||
"agent_id": self.agent_id,
|
||
"resume_conditions": [
|
||
"收到其他Agent的消息",
|
||
"收到用户消息",
|
||
"等待超时",
|
||
],
|
||
},
|
||
)
|
||
|
||
|
||
class AgentFinishInput(BaseModel):
|
||
"""Agent完成输入参数"""
|
||
result_summary: str = Field(..., description="结果摘要")
|
||
findings: Optional[List[str]] = Field(default=None, description="发现列表")
|
||
success: bool = Field(default=True, description="是否成功")
|
||
recommendations: Optional[List[str]] = Field(default=None, description="建议列表")
|
||
|
||
|
||
class AgentFinishTool(AgentTool):
|
||
"""
|
||
Agent完成工具
|
||
|
||
子Agent完成任务后调用,向父Agent报告结果
|
||
"""
|
||
|
||
def __init__(self, agent_id: str, agent_state=None):
|
||
super().__init__()
|
||
self.agent_id = agent_id
|
||
self.agent_state = agent_state
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "agent_finish"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """完成当前Agent的任务并向父Agent报告。
|
||
|
||
只有子Agent才能使用此工具。根Agent应使用finish_scan。
|
||
|
||
参数:
|
||
- result_summary: 结果摘要
|
||
- findings: 发现列表
|
||
- success: 是否成功完成
|
||
- recommendations: 建议列表"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return AgentFinishInput
|
||
|
||
async def _execute(
|
||
self,
|
||
result_summary: str,
|
||
findings: Optional[List[str]] = None,
|
||
success: bool = True,
|
||
recommendations: Optional[List[str]] = None,
|
||
**kwargs
|
||
) -> ToolResult:
|
||
"""完成Agent任务"""
|
||
|
||
# 获取父Agent ID
|
||
parent_id = agent_registry.get_parent(self.agent_id)
|
||
|
||
if not parent_id:
|
||
return ToolResult(
|
||
success=False,
|
||
error="此工具只能由子Agent使用。根Agent请使用finish_scan。"
|
||
)
|
||
|
||
# 更新状态
|
||
result = {
|
||
"summary": result_summary,
|
||
"findings": findings or [],
|
||
"success": success,
|
||
"recommendations": recommendations or [],
|
||
}
|
||
|
||
agent_registry.update_agent_status(
|
||
self.agent_id,
|
||
"completed" if success else "failed",
|
||
result,
|
||
)
|
||
|
||
if self.agent_state:
|
||
self.agent_state.set_completed(result)
|
||
|
||
# 向父Agent发送完成报告
|
||
message_bus.send_completion_report(
|
||
from_agent=self.agent_id,
|
||
to_agent=parent_id,
|
||
summary=result_summary,
|
||
findings=[{"description": f} for f in (findings or [])],
|
||
success=success,
|
||
)
|
||
|
||
agent_node = agent_registry.get_agent_node(self.agent_id)
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"agent_completed": True,
|
||
"parent_notified": True,
|
||
"completion_summary": {
|
||
"agent_id": self.agent_id,
|
||
"agent_name": agent_node["name"] if agent_node else "Unknown",
|
||
"success": success,
|
||
"findings_count": len(findings or []),
|
||
}
|
||
},
|
||
)
|
||
|
||
|
||
class RunSubAgentsInput(BaseModel):
|
||
"""批量执行子Agent输入参数"""
|
||
agent_ids: List[str] = Field(..., description="要执行的Agent ID列表")
|
||
parallel: bool = Field(default=True, description="是否并行执行")
|
||
|
||
|
||
class RunSubAgentsTool(AgentTool):
|
||
"""
|
||
批量执行子Agent工具
|
||
|
||
执行已创建的子Agent,支持并行执行
|
||
"""
|
||
|
||
def __init__(
|
||
self,
|
||
parent_agent_id: str,
|
||
llm_service=None,
|
||
tools: Dict[str, Any] = None,
|
||
event_emitter=None,
|
||
):
|
||
super().__init__()
|
||
self.parent_agent_id = parent_agent_id
|
||
self.llm_service = llm_service
|
||
self.tools = tools or {}
|
||
self.event_emitter = event_emitter
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "run_sub_agents"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """批量执行已创建的子Agent。
|
||
|
||
使用场景:
|
||
1. 创建多个子Agent后批量执行
|
||
2. 并行执行多个分析任务
|
||
|
||
参数:
|
||
- agent_ids: 要执行的Agent ID列表
|
||
- parallel: 是否并行执行(默认true)"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return RunSubAgentsInput
|
||
|
||
async def _execute(
|
||
self,
|
||
agent_ids: List[str],
|
||
parallel: bool = True,
|
||
**kwargs
|
||
) -> ToolResult:
|
||
"""批量执行子Agent"""
|
||
|
||
if not agent_ids:
|
||
return ToolResult(success=False, error="Agent ID列表不能为空")
|
||
|
||
# 验证所有Agent存在且是当前Agent的子Agent
|
||
valid_agents = []
|
||
for aid in agent_ids:
|
||
node = agent_registry.get_agent_node(aid)
|
||
if not node:
|
||
continue
|
||
if node.get("parent_id") != self.parent_agent_id:
|
||
continue
|
||
if node.get("status") not in ["created", "pending"]:
|
||
continue
|
||
valid_agents.append(node)
|
||
|
||
if not valid_agents:
|
||
return ToolResult(
|
||
success=False,
|
||
error="没有找到可执行的子Agent"
|
||
)
|
||
|
||
# 构建执行任务
|
||
from ..core.executor import DynamicAgentExecutor, ExecutionTask
|
||
|
||
executor = DynamicAgentExecutor(
|
||
llm_service=self.llm_service,
|
||
tools=self.tools,
|
||
event_emitter=self.event_emitter,
|
||
)
|
||
|
||
tasks = []
|
||
for node in valid_agents:
|
||
task = ExecutionTask(
|
||
agent_id=node["id"],
|
||
agent_type=node["type"],
|
||
task=node["task"],
|
||
context={
|
||
"knowledge_modules": node.get("knowledge_modules", []),
|
||
},
|
||
)
|
||
tasks.append(task)
|
||
|
||
# 定义Agent工厂函数
|
||
async def agent_factory(task: ExecutionTask) -> Dict[str, Any]:
|
||
from ..agents import AnalysisAgent, VerificationAgent
|
||
|
||
agent_class_map = {
|
||
"analysis": AnalysisAgent,
|
||
"verification": VerificationAgent,
|
||
"specialist": AnalysisAgent, # 默认使用分析Agent
|
||
}
|
||
|
||
agent_class = agent_class_map.get(task.agent_type, AnalysisAgent)
|
||
|
||
return await executor.execute_agent(
|
||
agent_class=agent_class,
|
||
agent_config={},
|
||
input_data={
|
||
"task": task.task,
|
||
"task_context": task.context,
|
||
},
|
||
parent_id=self.parent_agent_id,
|
||
knowledge_modules=task.context.get("knowledge_modules"),
|
||
)
|
||
|
||
# 执行
|
||
if parallel:
|
||
result = await executor.execute_parallel(tasks, agent_factory)
|
||
else:
|
||
# 顺序执行
|
||
result = await executor.execute_parallel(tasks, agent_factory)
|
||
|
||
return ToolResult(
|
||
success=result.success,
|
||
data={
|
||
"message": f"执行完成: {result.completed_agents}/{result.total_agents} 成功",
|
||
"total_agents": result.total_agents,
|
||
"completed": result.completed_agents,
|
||
"failed": result.failed_agents,
|
||
"findings_count": len(result.all_findings),
|
||
"findings": result.all_findings[:20], # 限制返回数量
|
||
"duration_ms": result.total_duration_ms,
|
||
"tokens_used": result.total_tokens,
|
||
},
|
||
error="; ".join(result.errors) if result.errors else None,
|
||
metadata={
|
||
"agent_results": {
|
||
aid: {
|
||
"success": r.get("success"),
|
||
"findings_count": len(r.get("data", {}).get("findings", [])) if r.get("success") else 0,
|
||
}
|
||
for aid, r in result.agent_results.items()
|
||
}
|
||
},
|
||
)
|
||
|
||
|
||
class CollectSubAgentResultsTool(AgentTool):
|
||
"""
|
||
收集子Agent结果工具
|
||
|
||
收集所有子Agent的执行结果和发现
|
||
"""
|
||
|
||
def __init__(self, parent_agent_id: str):
|
||
super().__init__()
|
||
self.parent_agent_id = parent_agent_id
|
||
|
||
@property
|
||
def name(self) -> str:
|
||
return "collect_sub_agent_results"
|
||
|
||
@property
|
||
def description(self) -> str:
|
||
return """收集所有子Agent的执行结果。
|
||
|
||
返回:
|
||
- 所有子Agent的状态
|
||
- 汇总的发现列表
|
||
- 执行统计"""
|
||
|
||
@property
|
||
def args_schema(self):
|
||
return None
|
||
|
||
async def _execute(self, **kwargs) -> ToolResult:
|
||
"""收集子Agent结果"""
|
||
|
||
# 获取所有子Agent
|
||
children = agent_registry.get_children(self.parent_agent_id)
|
||
|
||
if not children:
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"message": "没有子Agent",
|
||
"children_count": 0,
|
||
"findings": [],
|
||
}
|
||
)
|
||
|
||
all_findings = []
|
||
completed = 0
|
||
failed = 0
|
||
running = 0
|
||
|
||
child_summaries = []
|
||
|
||
for child_id in children:
|
||
node = agent_registry.get_agent_node(child_id)
|
||
if not node:
|
||
continue
|
||
|
||
status = node.get("status", "unknown")
|
||
|
||
if status == "completed":
|
||
completed += 1
|
||
# 收集发现
|
||
result = node.get("result", {})
|
||
if isinstance(result, dict):
|
||
findings = result.get("findings", [])
|
||
if isinstance(findings, list):
|
||
all_findings.extend(findings)
|
||
elif status == "failed":
|
||
failed += 1
|
||
elif status == "running":
|
||
running += 1
|
||
|
||
child_summaries.append({
|
||
"id": child_id,
|
||
"name": node.get("name"),
|
||
"type": node.get("type"),
|
||
"status": status,
|
||
"findings_count": len(node.get("result", {}).get("findings", [])) if node.get("result") else 0,
|
||
})
|
||
|
||
return ToolResult(
|
||
success=True,
|
||
data={
|
||
"message": f"收集完成: {completed} 完成, {failed} 失败, {running} 运行中",
|
||
"children_count": len(children),
|
||
"completed": completed,
|
||
"failed": failed,
|
||
"running": running,
|
||
"total_findings": len(all_findings),
|
||
"findings": all_findings,
|
||
"children": child_summaries,
|
||
},
|
||
)
|