From a9a22b91c7707de455132da739c55370d405ef96 Mon Sep 17 00:00:00 2001 From: lintsinghua Date: Sat, 13 Dec 2025 21:06:22 +0800 Subject: [PATCH] fix: Display aggregated findings for the orchestrator and task, and show sub-agent duration/status in UI. --- backend/app/api/v1/endpoints/agent_tasks.py | 35 +++++++++++++----- .../components/AgentDetailPanel.tsx | 37 ++++++++++++++----- .../AgentAudit/components/AgentTreeNode.tsx | 4 +- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/backend/app/api/v1/endpoints/agent_tasks.py b/backend/app/api/v1/endpoints/agent_tasks.py index dd6d113..e5aafdb 100644 --- a/backend/app/api/v1/endpoints/agent_tasks.py +++ b/backend/app/api/v1/endpoints/agent_tasks.py @@ -1919,6 +1919,9 @@ async def get_agent_tree( logger.debug(f"[AgentTree API] tree nodes={len(tree.get('nodes', {}))}, root={tree.get('root_agent_id')}") logger.debug(f"[AgentTree API] 节点详情: {list(tree.get('nodes', {}).keys())}") + # 🔥 获取 root agent ID,用于判断是否是 Orchestrator + root_agent_id = tree.get("root_agent_id") + # 构建节点列表 nodes = [] for agent_id, node_data in tree.get("nodes", {}).items(): @@ -1935,10 +1938,15 @@ async def get_agent_tree( tool_calls = agent_stats.get("tool_calls", 0) tokens_used = agent_stats.get("tokens_used", 0) - # 从结果中获取发现数量 - if node_data.get("result"): - result = node_data.get("result", {}) - findings_count = len(result.get("findings", [])) + # 🔥 FIX: 对于 Orchestrator (root agent),使用 task 的 findings_count + # 这确保了正确显示聚合的 findings 总数 + if agent_id == root_agent_id: + findings_count = task.findings_count or 0 + else: + # 从结果中获取发现数量(对于子 agent) + if node_data.get("result"): + result = node_data.get("result", {}) + findings_count = len(result.get("findings", [])) nodes.append(AgentTreeNodeResponse( id=node_data.get("id", agent_id), @@ -1956,14 +1964,15 @@ async def get_agent_tree( children=[], )) + # 🔥 使用 task.findings_count 作为 total_findings,确保一致性 return AgentTreeResponse( task_id=task_id, - root_agent_id=tree.get("root_agent_id"), + root_agent_id=root_agent_id, total_agents=stats.get("total", 0), running_agents=stats.get("running", 0), completed_agents=stats.get("completed", 0), failed_agents=stats.get("failed", 0), - total_findings=sum(n.findings_count for n in nodes), + total_findings=task.findings_count or 0, nodes=nodes, ) @@ -1989,7 +1998,6 @@ async def get_agent_tree( running = 0 completed = 0 failed = 0 - total_findings = 0 for node in db_nodes: if node.parent_agent_id is None: @@ -2002,7 +2010,13 @@ async def get_agent_tree( elif node.status == "failed": failed += 1 - total_findings += node.findings_count or 0 + # 🔥 FIX: 对于 Orchestrator (root agent),使用 task 的 findings_count + # 这确保了正确显示聚合的 findings 总数 + if node.parent_agent_id is None: + # Root agent uses task's total findings + node_findings_count = task.findings_count or 0 + else: + node_findings_count = node.findings_count or 0 nodes.append(AgentTreeNodeResponse( id=node.id, @@ -2015,7 +2029,7 @@ async def get_agent_tree( knowledge_modules=node.knowledge_modules, status=node.status, result_summary=node.result_summary, - findings_count=node.findings_count or 0, + findings_count=node_findings_count, iterations=node.iterations or 0, tokens_used=node.tokens_used or 0, tool_calls=node.tool_calls or 0, @@ -2023,6 +2037,7 @@ async def get_agent_tree( children=[], )) + # 🔥 使用 task.findings_count 作为 total_findings,确保一致性 return AgentTreeResponse( task_id=task_id, root_agent_id=root_id, @@ -2030,7 +2045,7 @@ async def get_agent_tree( running_agents=running, completed_agents=completed, failed_agents=failed, - total_findings=total_findings, + total_findings=task.findings_count or 0, nodes=nodes, ) diff --git a/frontend/src/pages/AgentAudit/components/AgentDetailPanel.tsx b/frontend/src/pages/AgentAudit/components/AgentDetailPanel.tsx index c7b5859..b377407 100644 --- a/frontend/src/pages/AgentAudit/components/AgentDetailPanel.tsx +++ b/frontend/src/pages/AgentAudit/components/AgentDetailPanel.tsx @@ -6,7 +6,6 @@ import { memo } from "react"; import { X, Cpu, Scan, FileSearch, ShieldCheck, Bot, Repeat, Zap, Bug, FileCode, Clock, Network } from "lucide-react"; -import { Badge } from "@/components/ui/badge"; import { AGENT_STATUS_CONFIG } from "../constants"; import { findAgentInTree } from "../utils"; import type { AgentDetailPanelProps } from "../types"; @@ -119,16 +118,36 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo - {/* Findings */} -
- 0 ? 'text-red-400/70' : 'text-gray-500/70'}`} /> -
-
Findings
-
0 ? 'text-red-400' : 'text-white'}`}> - {agent.findings_count} + {/* Findings - Only show for Orchestrator (root agent with no parent) */} + {!agent.parent_agent_id && ( +
+ 0 ? 'text-red-400/70' : 'text-gray-500/70'}`} /> +
+
Findings
+
0 ? 'text-red-400' : 'text-white'}`}> + {agent.findings_count} +
-
+ )} + + {/* Duration/Status - Show for sub-agents instead of Findings */} + {agent.parent_agent_id && ( +
+ +
+
+ {agent.duration_ms ? "Duration" : "Status"} +
+
+ {agent.duration_ms + ? `${(agent.duration_ms / 1000).toFixed(1)}s` + : (AGENT_STATUS_CONFIG[agent.status]?.text || agent.status) + } +
+
+
+ )} {/* Tokens */}
diff --git a/frontend/src/pages/AgentAudit/components/AgentTreeNode.tsx b/frontend/src/pages/AgentAudit/components/AgentTreeNode.tsx index 814e6c3..7bb41e0 100644 --- a/frontend/src/pages/AgentAudit/components/AgentTreeNode.tsx +++ b/frontend/src/pages/AgentAudit/components/AgentTreeNode.tsx @@ -133,8 +133,8 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({ )} - {/* Findings count */} - {node.findings_count > 0 && ( + {/* Findings count - Only show for Orchestrator (root agent) */} + {!node.parent_agent_id && node.findings_count > 0 && ( {node.findings_count}