"""Agent 协调整器 - Phase 10.5 统一协调所有 Agent 组件:TeamLeader, RemoteTransport, BackgroundTaskManager, SessionManager """ from typing import Any from app.agents.background.manager import BackgroundTaskManager, get_background_task_manager from app.agents.session.manager import AgentSession, create_agent_session, get_agent_session from app.agents.team.leader import TeamLeader from app.agents.transport.remote import RemoteTransport class AgentCoordinator: """Agent 协调整器 统一协调所有 Agent 组件,提供单一入口处理各类 Agent 操作。 """ def __init__( self, background_manager: BackgroundTaskManager | None = None, ): """ Args: background_manager: 后台任务管理器,None 则使用全局单例 """ self._team_leaders: dict[str, TeamLeader] = {} self._remote_transport = RemoteTransport() self._background_manager = background_manager or get_background_task_manager() self._sessions: dict[str, AgentSession] = {} # === Team 协作方法 === def create_team(self, team_id: str, members: list[str]) -> dict[str, Any]: """创建团队 Args: team_id: 团队 ID members: 成员 ID 列表 Returns: 团队创建结果 """ if team_id in self._team_leaders: return {"status": "error", "message": f"Team '{team_id}' already exists"} leader = TeamLeader(team_id=team_id, members=members) self._team_leaders[team_id] = leader return { "status": "created", "team_id": team_id, "members": members, } def get_team(self, team_id: str) -> TeamLeader | None: """获取团队 Args: team_id: 团队 ID Returns: TeamLeader 或 None """ return self._team_leaders.get(team_id) def assign_task(self, team_id: str, description: str, member: str) -> dict[str, Any]: """创建并分配任务 Args: team_id: 团队 ID description: 任务描述 member: 成员 ID Returns: 分配结果 """ leader = self._team_leaders.get(team_id) if not leader: return {"status": "error", "message": f"Team '{team_id}' not found"} task_id = leader.create_task(description) success = leader.assign_task(task_id, member) return { "status": "assigned" if success else "error", "task_id": task_id, "assignee": member, } def broadcast_task(self, team_id: str, description: str) -> dict[str, Any]: """广播任务给所有成员 Args: team_id: 团队 ID description: 任务描述 Returns: 广播结果 """ leader = self._team_leaders.get(team_id) if not leader: return {"status": "error", "message": f"Team '{team_id}' not found"} task_ids = leader.broadcast_task(description) return { "status": "broadcast", "team_id": team_id, "task_ids": task_ids, "member_count": len(leader.members), } def collect_team_results(self, team_id: str) -> dict[str, Any]: """收集团队任务结果 Args: team_id: 团队 ID Returns: 收集结果 """ leader = self._team_leaders.get(team_id) if not leader: return {"status": "error", "message": f"Team '{team_id}' not found"} results = leader.collect_results() status = leader.get_team_status() return { "status": "collected", "team_id": team_id, "results": results, "completed": status["completed"], "failed": status["failed"], } def get_team_status(self, team_id: str) -> dict[str, Any]: """获取团队状态 Args: team_id: 团队 ID Returns: 团队状态 """ leader = self._team_leaders.get(team_id) if not leader: return {"status": "error", "message": f"Team '{team_id}' not found"} return leader.get_team_status() # === 后台任务方法 === def submit_background_task( self, name: str, coro: Any, *args, **kwargs, ) -> dict[str, Any]: """提交后台任务 Args: name: 任务名称 coro: 协程函数 *args: 位置参数 **kwargs: 关键字参数 Returns: 提交结果 """ task_id = self._background_manager.submit_task(name, coro, *args, **kwargs) return { "status": "submitted", "task_id": task_id, "name": name, } def cancel_background_task(self, task_id: str) -> dict[str, Any]: """取消后台任务 Args: task_id: 任务 ID Returns: 取消结果 """ success = self._background_manager.cancel_task(task_id) return { "status": "cancelled" if success else "error", "task_id": task_id, } def get_background_task_status(self, task_id: str) -> dict[str, Any]: """获取后台任务状态 Args: task_id: 任务 ID Returns: 任务状态 """ task = self._background_manager.get_task_status(task_id) if not task: return {"status": "error", "message": f"Task '{task_id}' not found"} return { "status": "found", "task_id": task.id, "name": task.name, "task_status": task.status.value, "result": task.result, "error": task.error, } def list_background_tasks(self) -> dict[str, Any]: """列出所有后台任务 Returns: 任务列表 """ tasks = self._background_manager.list_tasks() return { "status": "list", "count": len(tasks), "tasks": [ { "id": t.id, "name": t.name, "status": t.status.value, } for t in tasks ], } # === 会话方法 === def create_session( self, user_id: str | None = None, parent_session_id: str | None = None, ) -> dict[str, Any]: """创建会话 Args: user_id: 用户 ID parent_session_id: 父会话 ID Returns: 创建结果 """ session = create_agent_session( user_id=user_id, parent_session_id=parent_session_id, ) self._sessions[session.session_id] = session return { "status": "created", "session_id": session.session_id, "user_id": user_id, "parent_session_id": parent_session_id, } def get_session(self, session_id: str) -> AgentSession | None: """获取会话 Args: session_id: 会话 ID Returns: AgentSession 或 None """ return self._sessions.get(session_id) or get_agent_session(session_id) async def process_session_message( self, session_id: str, message: str, response: str, ) -> dict[str, Any]: """处理会话消息 Args: session_id: 会话 ID message: 用户消息 response: 助手响应 Returns: 处理结果 """ session = self.get_session(session_id) if not session: return {"status": "error", "message": f"Session '{session_id}' not found"} await session.process_message(message, response) return { "status": "processed", "session_id": session_id, "message_count": session.context.message_count, } async def spawn_child_session( self, session_id: str, user_id: str | None = None, ) -> dict[str, Any]: """创建子会话 Args: session_id: 父会话 ID user_id: 用户 ID Returns: 创建结果 """ session = self.get_session(session_id) if not session: return {"status": "error", "message": f"Session '{session_id}' not found"} child = await session.spawn_child_session(user_id=user_id) self._sessions[child.session_id] = child return { "status": "spawned", "parent_session_id": session_id, "child_session_id": child.session_id, "depth": child.context.depth, } def get_session_summary(self, session_id: str) -> dict[str, Any]: """获取会话摘要 Args: session_id: 会话 ID Returns: 会话摘要 """ import asyncio session = self.get_session(session_id) if not session: return {"status": "error", "message": f"Session '{session_id}' not found"} # get_session_summary is async, so we need to run it try: loop = asyncio.get_event_loop() if loop.is_running(): # Create a future future = asyncio.ensure_future(session.get_session_summary()) return {"status": "found", "summary": future} else: return { "status": "found", "summary": loop.run_until_complete(session.get_session_summary()), } except RuntimeError: # No event loop, create one return {"status": "found", "summary": asyncio.run(session.get_session_summary())} # === 远程传输方法 === def register_remote_handler(self, event_type: str, handler: Any) -> None: """注册远程消息处理器 Args: event_type: 事件类型 handler: 处理函数 """ self._remote_transport.register_handler(event_type, handler) async def send_remote_response( self, session_id: str, response: dict[str, Any], ) -> bool: """发送远程响应 Args: session_id: 会话 ID response: 响应数据 Returns: 是否发送成功 """ return await self._remote_transport.send_response(session_id, response) async def send_remote_event( self, session_id: str, event: dict[str, Any], ) -> bool: """发送远程事件 Args: session_id: 会话 ID event: 事件数据 Returns: 是否发送成功 """ return await self._remote_transport.send_event(session_id, event) async def send_remote_tool_call( self, session_id: str, tool_call: dict[str, Any], ) -> bool: """发送远程工具调用 Args: session_id: 会话 ID tool_call: 工具调用数据 Returns: 是否发送成功 """ return await self._remote_transport.send_tool_call(session_id, tool_call) # === 统一协调入口 === async def coordinate(self, request: dict[str, Any]) -> dict[str, Any]: """统一协调入口 根据请求类型协调各类 Agent 操作。 Args: request: 请求数据,包含: - action: 操作类型 (team_create, team_assign, task_submit, session_create, etc.) - 其他参数根据 action 不同而不同 Returns: 协调结果 """ action = request.get("action") if action == "team_create": return self.create_team( team_id=request["team_id"], members=request["members"], ) elif action == "team_assign": return self.assign_task( team_id=request["team_id"], description=request["description"], member=request["member"], ) elif action == "team_broadcast": return self.broadcast_task( team_id=request["team_id"], description=request["description"], ) elif action == "team_collect": return self.collect_team_results(team_id=request["team_id"]) elif action == "team_status": return self.get_team_status(team_id=request["team_id"]) elif action == "task_submit": return self.submit_background_task( name=request["name"], coro=request["coro"], *request.get("args", []), **request.get("kwargs", {}), ) elif action == "task_cancel": return self.cancel_background_task(task_id=request["task_id"]) elif action == "task_status": return self.get_background_task_status(task_id=request["task_id"]) elif action == "session_create": return self.create_session( user_id=request.get("user_id"), parent_session_id=request.get("parent_session_id"), ) elif action == "session_message": return await self.process_session_message( session_id=request["session_id"], message=request["message"], response=request["response"], ) elif action == "session_spawn": return await self.spawn_child_session( session_id=request["session_id"], user_id=request.get("user_id"), ) elif action == "session_summary": return self.get_session_summary(session_id=request["session_id"]) else: return {"status": "error", "message": f"Unknown action: {action}"} # 全局单例 _coordinator: AgentCoordinator | None = None def get_agent_coordinator() -> AgentCoordinator: """获取全局 Agent 协调整器""" global _coordinator if _coordinator is None: _coordinator = AgentCoordinator() return _coordinator