fix: enrich sub-agent results
This commit is contained in:
parent
ed82fc966e
commit
cd3f07bcc8
@ -328,6 +328,10 @@ class SubAgentManager:
|
|||||||
|
|
||||||
task["status"] = status
|
task["status"] = status
|
||||||
task["updated_at"] = time.time()
|
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")
|
agent_id = task.get("agent_id")
|
||||||
@ -340,6 +344,7 @@ class SubAgentManager:
|
|||||||
stats_summary=stats_summary,
|
stats_summary=stats_summary,
|
||||||
summary=summary,
|
summary=summary,
|
||||||
deliverables_dir=deliverables_dir,
|
deliverables_dir=deliverables_dir,
|
||||||
|
duration_seconds=elapsed_seconds,
|
||||||
)
|
)
|
||||||
elif status == "timeout":
|
elif status == "timeout":
|
||||||
system_message = self._compose_sub_agent_message(
|
system_message = self._compose_sub_agent_message(
|
||||||
@ -365,6 +370,9 @@ class SubAgentManager:
|
|||||||
"stats_summary": stats_summary,
|
"stats_summary": stats_summary,
|
||||||
"system_message": system_message,
|
"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
|
task["final_result"] = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -827,6 +835,11 @@ class SubAgentManager:
|
|||||||
copied_path = self._copy_deliverables_to_project(task, deliverables_dir)
|
copied_path = self._copy_deliverables_to_project(task, deliverables_dir)
|
||||||
task["copied_path"] = str(copied_path)
|
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)
|
system_message = self._build_system_message(task, status, copied_path, message)
|
||||||
result = {
|
result = {
|
||||||
"success": True,
|
"success": True,
|
||||||
@ -840,6 +853,9 @@ class SubAgentManager:
|
|||||||
"system_message": system_message,
|
"system_message": system_message,
|
||||||
"details": service_payload,
|
"details": service_payload,
|
||||||
}
|
}
|
||||||
|
if elapsed_seconds is not None:
|
||||||
|
result["elapsed_seconds"] = elapsed_seconds
|
||||||
|
result["runtime_seconds"] = elapsed_seconds
|
||||||
task["final_result"] = result
|
task["final_result"] = result
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -896,7 +912,10 @@ class SubAgentManager:
|
|||||||
extra = (extra_message or "").strip()
|
extra = (extra_message or "").strip()
|
||||||
|
|
||||||
if status == "completed" and copied_path:
|
if status == "completed" and copied_path:
|
||||||
|
elapsed_seconds = self._compute_elapsed_seconds(task)
|
||||||
msg = f"{prefix} 已完成,成果已复制到 {copied_path}。"
|
msg = f"{prefix} 已完成,成果已复制到 {copied_path}。"
|
||||||
|
if elapsed_seconds is not None:
|
||||||
|
msg += f" 运行了{elapsed_seconds}秒。"
|
||||||
if extra:
|
if extra:
|
||||||
msg += f" ({extra})"
|
msg += f" ({extra})"
|
||||||
return msg
|
return msg
|
||||||
@ -916,6 +935,18 @@ class SubAgentManager:
|
|||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
return 0
|
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:
|
def _build_stats_summary(self, stats: Optional[Dict[str, Any]]) -> str:
|
||||||
if not isinstance(stats, dict):
|
if not isinstance(stats, dict):
|
||||||
stats = {}
|
stats = {}
|
||||||
@ -946,10 +977,13 @@ class SubAgentManager:
|
|||||||
stats_summary: str,
|
stats_summary: str,
|
||||||
summary: str,
|
summary: str,
|
||||||
deliverables_dir: Optional[str] = None,
|
deliverables_dir: Optional[str] = None,
|
||||||
|
duration_seconds: Optional[int] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
parts = [prefix]
|
parts = [prefix]
|
||||||
if stats_summary:
|
if stats_summary:
|
||||||
parts.append(stats_summary)
|
parts.append(stats_summary)
|
||||||
|
if duration_seconds is not None:
|
||||||
|
parts.append(f"运行了{duration_seconds}秒")
|
||||||
if summary:
|
if summary:
|
||||||
parts.append(summary)
|
parts.append(summary)
|
||||||
if deliverables_dir:
|
if deliverables_dir:
|
||||||
|
|||||||
@ -197,11 +197,18 @@ async def poll_sub_agent_completion(*, web_terminal, workspace, conversation_id,
|
|||||||
|
|
||||||
# 构建 user 消息(后台完成时才发送)
|
# 构建 user 消息(后台完成时才发送)
|
||||||
prefix = "这是一句系统自动发送的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}
|
user_message = f"""{prefix}
|
||||||
|
|
||||||
子智能体{agent_id} ({summary}) 已完成任务。
|
子智能体{agent_id} ({summary}) 已完成任务。
|
||||||
|
|
||||||
{result_summary}
|
{result_summary}
|
||||||
|
{runtime_line}
|
||||||
|
|
||||||
交付目录:{deliverables_dir}"""
|
交付目录:{deliverables_dir}"""
|
||||||
|
|
||||||
|
|||||||
@ -56,6 +56,9 @@ async def process_sub_agent_updates(*, messages: List[Dict], inline: bool = Fals
|
|||||||
updates = synthesized
|
updates = synthesized
|
||||||
debug_log(f"[SubAgent] synthesized updates count={len(updates)}")
|
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:
|
for update in updates:
|
||||||
task_id = update.get("task_id")
|
task_id = update.get("task_id")
|
||||||
task_info = manager.tasks.get(task_id) if task_id else None
|
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())}")
|
debug_log(f"[SubAgent] update missing system_message: task={task_id} keys={list(update.keys())}")
|
||||||
continue
|
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}")
|
debug_log(f"[SubAgent] update task={task_id} inline={inline} msg={message}")
|
||||||
|
|
||||||
# 记录到对话历史(用于后续 build_messages 转换为 user 消息)
|
# 记录到对话历史(用于后续 build_messages 转换为 user 消息)
|
||||||
@ -118,6 +127,8 @@ async def process_sub_agent_updates(*, messages: List[Dict], inline: bool = Fals
|
|||||||
"content": message,
|
"content": message,
|
||||||
"metadata": {"sub_agent_notice": True, "inline": inline, "task_id": task_id}
|
"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}")
|
debug_log(f"[SubAgent] 插入子智能体通知位置: {insert_index} role={insert_role} after_tool_call_id={after_tool_call_id}")
|
||||||
sender('system_message', {
|
sender('system_message', {
|
||||||
'content': message,
|
'content': message,
|
||||||
|
|||||||
@ -56,38 +56,38 @@ const normalizeStatus = (status?: string) => {
|
|||||||
return status || 'running';
|
return status || 'running';
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildText = (entry: ActivityEntry, stateLabel: string) => {
|
const buildText = (entry: ActivityEntry) => {
|
||||||
const tool = entry.tool || '';
|
const tool = entry.tool || '';
|
||||||
const args = entry.args || {};
|
const args = entry.args || {};
|
||||||
if (tool === 'read_file') {
|
if (tool === 'read_file') {
|
||||||
const path = args.path || args.file_path || '';
|
const path = args.path || args.file_path || '';
|
||||||
return `阅读 ${path} ${stateLabel}`;
|
return `阅读 ${path}`;
|
||||||
}
|
}
|
||||||
if (tool === 'search_workspace') {
|
if (tool === 'search_workspace') {
|
||||||
const query = args.query || args.keyword || '';
|
const query = args.query || args.keyword || '';
|
||||||
return `在工作区搜索 ${query} ${stateLabel}`;
|
return `在工作区搜索 ${query}`;
|
||||||
}
|
}
|
||||||
if (tool === 'web_search') {
|
if (tool === 'web_search') {
|
||||||
const query = args.query || args.q || '';
|
const query = args.query || args.q || '';
|
||||||
return `在互联网中搜索 ${query} ${stateLabel}`;
|
return `在互联网中搜索 ${query}`;
|
||||||
}
|
}
|
||||||
if (tool === 'extract_webpage') {
|
if (tool === 'extract_webpage') {
|
||||||
const url = args.url || '';
|
const url = args.url || '';
|
||||||
return `在互联网中提取 ${url} ${stateLabel}`;
|
return `在互联网中提取 ${url}`;
|
||||||
}
|
}
|
||||||
if (tool === 'run_command') {
|
if (tool === 'run_command') {
|
||||||
const command = args.command || '';
|
const command = args.command || '';
|
||||||
return `运行命令 ${command} ${stateLabel}`;
|
return `运行命令 ${command}`;
|
||||||
}
|
}
|
||||||
if (tool === 'edit_file') {
|
if (tool === 'edit_file') {
|
||||||
const path = args.path || args.file_path || '';
|
const path = args.path || args.file_path || '';
|
||||||
return `编辑 ${path} ${stateLabel}`;
|
return `编辑 ${path}`;
|
||||||
}
|
}
|
||||||
if (tool === 'read_mediafile') {
|
if (tool === 'read_mediafile') {
|
||||||
const path = args.path || args.file_path || '';
|
const path = args.path || args.file_path || '';
|
||||||
return `读取媒体文件 ${path} ${stateLabel}`;
|
return `读取媒体文件 ${path}`;
|
||||||
}
|
}
|
||||||
return `${tool || '工具'} ${stateLabel}`;
|
return `${tool || '工具'}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const displayItems = computed(() => {
|
const displayItems = computed(() => {
|
||||||
@ -112,7 +112,7 @@ const displayItems = computed(() => {
|
|||||||
key,
|
key,
|
||||||
state,
|
state,
|
||||||
stateLabel,
|
stateLabel,
|
||||||
text: buildText(item, stateLabel)
|
text: buildText(item)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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")
|
result_data.get("stats") or (result_data.get("final_result") or {}).get("stats")
|
||||||
)
|
)
|
||||||
summary = result_data.get("message") or result_data.get("summary")
|
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]
|
lines = [header]
|
||||||
if stats_text:
|
if stats_text:
|
||||||
lines.append(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"}:
|
if summary and status in {"completed", "failed", "timeout", "terminated"}:
|
||||||
lines.append(str(summary))
|
lines.append(str(summary))
|
||||||
return "\n".join(lines)
|
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")
|
task_id = result_data.get("task_id")
|
||||||
agent_id = result_data.get("agent_id")
|
agent_id = result_data.get("agent_id")
|
||||||
status = result_data.get("status")
|
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"):
|
if result_data.get("success"):
|
||||||
copied_path = result_data.get("copied_path") or result_data.get("deliverables_path")
|
copied_path = result_data.get("copied_path") or result_data.get("deliverables_path")
|
||||||
message = result_data.get("message") or "子智能体任务已完成。"
|
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} 完成"]
|
lines = [f"子智能体 #{agent_id}/{task_id} 完成"]
|
||||||
if stats_text:
|
if stats_text:
|
||||||
lines.append(stats_text)
|
lines.append(stats_text)
|
||||||
|
if isinstance(elapsed_seconds, (int, float)):
|
||||||
|
lines.append(f"运行了{int(round(elapsed_seconds))}秒")
|
||||||
lines.append(message)
|
lines.append(message)
|
||||||
lines.append(deliver_note)
|
lines.append(deliver_note)
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
@ -575,14 +588,20 @@ def _format_get_sub_agent_status(result_data: Dict[str, Any]) -> str:
|
|||||||
status = item.get("status")
|
status = item.get("status")
|
||||||
summary = None
|
summary = None
|
||||||
final_result = item.get("final_result") or {}
|
final_result = item.get("final_result") or {}
|
||||||
|
elapsed_seconds = None
|
||||||
if isinstance(final_result, dict):
|
if isinstance(final_result, dict):
|
||||||
summary = final_result.get("message") or final_result.get("summary")
|
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:
|
if not summary:
|
||||||
summary = item.get("summary") or ""
|
summary = item.get("summary") or ""
|
||||||
stats_text = _format_sub_agent_stats(item.get("stats"))
|
stats_text = _format_sub_agent_stats(item.get("stats"))
|
||||||
lines = [f"子智能体 #{agent_id} 状态: {status}"]
|
lines = [f"子智能体 #{agent_id} 状态: {status}"]
|
||||||
if stats_text:
|
if stats_text:
|
||||||
lines.append(stats_text)
|
lines.append(stats_text)
|
||||||
|
if status == "completed" and isinstance(elapsed_seconds, (int, float)):
|
||||||
|
lines.append(f"运行了{int(round(elapsed_seconds))}秒")
|
||||||
if summary:
|
if summary:
|
||||||
lines.append(str(summary))
|
lines.append(str(summary))
|
||||||
blocks.append("\n".join(lines))
|
blocks.append("\n".join(lines))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user