fix: enrich sub-agent results

This commit is contained in:
JOJO 2026-03-11 18:05:01 +08:00
parent ed82fc966e
commit cd3f07bcc8
5 changed files with 82 additions and 11 deletions

View File

@ -328,6 +328,10 @@ class SubAgentManager:
task["status"] = status
task["updated_at"] = time.time()
elapsed_seconds = self._compute_elapsed_seconds(task)
if status == "completed" and elapsed_seconds is not None:
task["elapsed_seconds"] = elapsed_seconds
task["runtime_seconds"] = elapsed_seconds
# 构建系统消息
agent_id = task.get("agent_id")
@ -340,6 +344,7 @@ class SubAgentManager:
stats_summary=stats_summary,
summary=summary,
deliverables_dir=deliverables_dir,
duration_seconds=elapsed_seconds,
)
elif status == "timeout":
system_message = self._compose_sub_agent_message(
@ -365,6 +370,9 @@ class SubAgentManager:
"stats_summary": stats_summary,
"system_message": system_message,
}
if status == "completed" and elapsed_seconds is not None:
result["elapsed_seconds"] = elapsed_seconds
result["runtime_seconds"] = elapsed_seconds
task["final_result"] = result
return result
@ -827,6 +835,11 @@ class SubAgentManager:
copied_path = self._copy_deliverables_to_project(task, deliverables_dir)
task["copied_path"] = str(copied_path)
elapsed_seconds = self._compute_elapsed_seconds(task)
if elapsed_seconds is not None:
task["elapsed_seconds"] = elapsed_seconds
task["runtime_seconds"] = elapsed_seconds
system_message = self._build_system_message(task, status, copied_path, message)
result = {
"success": True,
@ -840,6 +853,9 @@ class SubAgentManager:
"system_message": system_message,
"details": service_payload,
}
if elapsed_seconds is not None:
result["elapsed_seconds"] = elapsed_seconds
result["runtime_seconds"] = elapsed_seconds
task["final_result"] = result
return result
@ -896,7 +912,10 @@ class SubAgentManager:
extra = (extra_message or "").strip()
if status == "completed" and copied_path:
elapsed_seconds = self._compute_elapsed_seconds(task)
msg = f"{prefix} 已完成,成果已复制到 {copied_path}"
if elapsed_seconds is not None:
msg += f" 运行了{elapsed_seconds}秒。"
if extra:
msg += f" ({extra})"
return msg
@ -916,6 +935,18 @@ class SubAgentManager:
except (TypeError, ValueError):
return 0
@staticmethod
def _compute_elapsed_seconds(task: Dict) -> Optional[int]:
try:
created_at = float(task.get("created_at") or 0)
updated_at = float(task.get("updated_at") or time.time())
except (TypeError, ValueError):
return None
if created_at <= 0:
return None
elapsed = max(0.0, updated_at - created_at)
return int(round(elapsed))
def _build_stats_summary(self, stats: Optional[Dict[str, Any]]) -> str:
if not isinstance(stats, dict):
stats = {}
@ -946,10 +977,13 @@ class SubAgentManager:
stats_summary: str,
summary: str,
deliverables_dir: Optional[str] = None,
duration_seconds: Optional[int] = None,
) -> str:
parts = [prefix]
if stats_summary:
parts.append(stats_summary)
if duration_seconds is not None:
parts.append(f"运行了{duration_seconds}")
if summary:
parts.append(summary)
if deliverables_dir:

View File

@ -197,11 +197,18 @@ async def poll_sub_agent_completion(*, web_terminal, workspace, conversation_id,
# 构建 user 消息(后台完成时才发送)
prefix = "这是一句系统自动发送的user消息用于通知你子智能体已经运行完成"
runtime_line = ""
elapsed_seconds = update.get("runtime_seconds")
if elapsed_seconds is None:
elapsed_seconds = update.get("elapsed_seconds")
if status == "completed" and isinstance(elapsed_seconds, (int, float)):
runtime_line = f"\n\n运行了{int(round(elapsed_seconds))}"
user_message = f"""{prefix}
子智能体{agent_id} ({summary}) 已完成任务
{result_summary}
{runtime_line}
交付目录{deliverables_dir}"""

View File

@ -56,6 +56,9 @@ async def process_sub_agent_updates(*, messages: List[Dict], inline: bool = Fals
updates = synthesized
debug_log(f"[SubAgent] synthesized updates count={len(updates)}")
if inline and not hasattr(web_terminal, "_inline_sub_agent_notified"):
web_terminal._inline_sub_agent_notified = set()
for update in updates:
task_id = update.get("task_id")
task_info = manager.tasks.get(task_id) if task_id else None
@ -78,6 +81,12 @@ async def process_sub_agent_updates(*, messages: List[Dict], inline: bool = Fals
debug_log(f"[SubAgent] update missing system_message: task={task_id} keys={list(update.keys())}")
continue
if inline:
inline_key = ("task", task_id) if task_id else ("msg", message)
if inline_key in web_terminal._inline_sub_agent_notified:
debug_log(f"[SubAgent] inline 通知已发送,跳过: key={inline_key}")
continue
debug_log(f"[SubAgent] update task={task_id} inline={inline} msg={message}")
# 记录到对话历史(用于后续 build_messages 转换为 user 消息)
@ -118,6 +127,8 @@ async def process_sub_agent_updates(*, messages: List[Dict], inline: bool = Fals
"content": message,
"metadata": {"sub_agent_notice": True, "inline": inline, "task_id": task_id}
})
if inline:
web_terminal._inline_sub_agent_notified.add(inline_key)
debug_log(f"[SubAgent] 插入子智能体通知位置: {insert_index} role={insert_role} after_tool_call_id={after_tool_call_id}")
sender('system_message', {
'content': message,

View File

@ -56,38 +56,38 @@ const normalizeStatus = (status?: string) => {
return status || 'running';
};
const buildText = (entry: ActivityEntry, stateLabel: string) => {
const buildText = (entry: ActivityEntry) => {
const tool = entry.tool || '';
const args = entry.args || {};
if (tool === 'read_file') {
const path = args.path || args.file_path || '';
return `阅读 ${path} ${stateLabel}`;
return `阅读 ${path}`;
}
if (tool === 'search_workspace') {
const query = args.query || args.keyword || '';
return `在工作区搜索 ${query} ${stateLabel}`;
return `在工作区搜索 ${query}`;
}
if (tool === 'web_search') {
const query = args.query || args.q || '';
return `在互联网中搜索 ${query} ${stateLabel}`;
return `在互联网中搜索 ${query}`;
}
if (tool === 'extract_webpage') {
const url = args.url || '';
return `在互联网中提取 ${url} ${stateLabel}`;
return `在互联网中提取 ${url}`;
}
if (tool === 'run_command') {
const command = args.command || '';
return `运行命令 ${command} ${stateLabel}`;
return `运行命令 ${command}`;
}
if (tool === 'edit_file') {
const path = args.path || args.file_path || '';
return `编辑 ${path} ${stateLabel}`;
return `编辑 ${path}`;
}
if (tool === 'read_mediafile') {
const path = args.path || args.file_path || '';
return `读取媒体文件 ${path} ${stateLabel}`;
return `读取媒体文件 ${path}`;
}
return `${tool || '工具'} ${stateLabel}`;
return `${tool || '工具'}`;
};
const displayItems = computed(() => {
@ -112,7 +112,7 @@ const displayItems = computed(() => {
key,
state,
stateLabel,
text: buildText(item, stateLabel)
text: buildText(item)
};
});
});

View File

@ -529,9 +529,14 @@ def _format_create_sub_agent(result_data: Dict[str, Any]) -> str:
result_data.get("stats") or (result_data.get("final_result") or {}).get("stats")
)
summary = result_data.get("message") or result_data.get("summary")
elapsed_seconds = result_data.get("runtime_seconds")
if elapsed_seconds is None:
elapsed_seconds = result_data.get("elapsed_seconds")
lines = [header]
if stats_text:
lines.append(stats_text)
if status == "completed" and isinstance(elapsed_seconds, (int, float)):
lines.append(f"运行了{int(round(elapsed_seconds))}")
if summary and status in {"completed", "failed", "timeout", "terminated"}:
lines.append(str(summary))
return "\n".join(lines)
@ -541,7 +546,13 @@ def _format_wait_sub_agent(result_data: Dict[str, Any]) -> str:
task_id = result_data.get("task_id")
agent_id = result_data.get("agent_id")
status = result_data.get("status")
stats_text = _format_sub_agent_stats(result_data.get("stats"))
stats_value = result_data.get("stats")
if not isinstance(stats_value, dict) and status == "timeout":
stats_value = {}
stats_text = _format_sub_agent_stats(stats_value)
elapsed_seconds = result_data.get("runtime_seconds")
if elapsed_seconds is None:
elapsed_seconds = result_data.get("elapsed_seconds")
if result_data.get("success"):
copied_path = result_data.get("copied_path") or result_data.get("deliverables_path")
message = result_data.get("message") or "子智能体任务已完成。"
@ -549,6 +560,8 @@ def _format_wait_sub_agent(result_data: Dict[str, Any]) -> str:
lines = [f"子智能体 #{agent_id}/{task_id} 完成"]
if stats_text:
lines.append(stats_text)
if isinstance(elapsed_seconds, (int, float)):
lines.append(f"运行了{int(round(elapsed_seconds))}")
lines.append(message)
lines.append(deliver_note)
return "\n".join(lines)
@ -575,14 +588,20 @@ def _format_get_sub_agent_status(result_data: Dict[str, Any]) -> str:
status = item.get("status")
summary = None
final_result = item.get("final_result") or {}
elapsed_seconds = None
if isinstance(final_result, dict):
summary = final_result.get("message") or final_result.get("summary")
elapsed_seconds = final_result.get("runtime_seconds")
if elapsed_seconds is None:
elapsed_seconds = final_result.get("elapsed_seconds")
if not summary:
summary = item.get("summary") or ""
stats_text = _format_sub_agent_stats(item.get("stats"))
lines = [f"子智能体 #{agent_id} 状态: {status}"]
if stats_text:
lines.append(stats_text)
if status == "completed" and isinstance(elapsed_seconds, (int, float)):
lines.append(f"运行了{int(round(elapsed_seconds))}")
if summary:
lines.append(str(summary))
blocks.append("\n".join(lines))