""" 原生 LLM Agent 适配器 直接调用 LLM API 实现 Agent,不需要外部进程。 这是主要使用的适配器类型。 """ import asyncio import logging from typing import Dict, Optional, Any from datetime import datetime from ..core.agent_adapter import ( CLIPluginAdapter, Task, Result, AgentCapabilities ) from ..services.llm_service import ModelRouter, get_llm_service from ..services.agent_executor import AgentExecutor, get_agent_executor from ..services.meeting_scheduler import get_meeting_scheduler from ..services.agent_registry import get_agent_registry from ..services.heartbeat import get_heartbeat_service logger = logging.getLogger(__name__) class NativeLLMAgent(CLIPluginAdapter): """ 原生 LLM Agent 直接通过 LLM API 实现的 Agent,特点: 1. 无需外部进程,完全异步 2. 支持所有主流 LLM 提供商 3. 自动管理资源(文件锁、心跳) 4. 支持会议协作 """ def __init__( self, agent_id: str, name: str, role: str, model: str, config: Dict[str, Any] = None, llm_service: ModelRouter = None, executor: AgentExecutor = None ): self._id = agent_id self._name = name self._role = role self._model = model self.config = config or {} self._version = "1.0.0" # 获取服务 self.llm_service = llm_service or get_llm_service() self.executor = executor or get_agent_executor(self.llm_service) self.scheduler = get_meeting_scheduler() self.registry = get_agent_registry() self.heartbeat_service = get_heartbeat_service() # 状态 self._is_running = False self._current_task: Optional[Task] = None logger.info(f"NativeLLMAgent 初始化: {self._id} ({self._name})") # ========== 属性 ========== @property def id(self) -> str: return self._id @property def name(self) -> str: return self._name @property def version(self) -> str: return self._version @property def role(self) -> str: return self._role @property def model(self) -> str: return self._model @property def capabilities(self) -> AgentCapabilities: """返回 Agent 能力声明""" return AgentCapabilities( can_execute_code=True, can_read_files=True, can_write_files=True, can_analyze_code=True, can_generate_tests=self._role in ["developer", "qa"], can_review_code=self._role == "reviewer", supported_languages=["Python", "JavaScript", "TypeScript", "Java", "Go"], max_context_length=200000 ) @property def is_running(self) -> bool: return self._is_running # ========== 核心能力 ========== async def execute(self, task: Task) -> Result: """ 执行任务 通过 AgentExecutor 协调 LLM 调用和资源管理 """ self._current_task = task try: # 获取或注册 Agent 信息 agent_info = await self._ensure_registered() # 使用执行引擎执行任务 result = await self.executor.execute_task( agent_info, task, context=self.config.get("context", {}) ) logger.info(f"任务执行完成: {task.task_id} -> {result.success}") return result except Exception as e: logger.error(f"任务执行失败: {task.task_id}: {e}", exc_info=True) return Result( success=False, output="", error=str(e) ) finally: self._current_task = None async def join_meeting(self, meeting_id: str, timeout: int = 300) -> str: """ 加入会议等待队列(栅栏同步) 当最后一个参与者到达时,会议自动开始 """ logger.info(f"Agent {self._id} 等待会议: {meeting_id}") # 更新心跳为等待状态 await self.update_heartbeat("waiting", f"等待会议: {meeting_id}", 0) # 调用会议调度器 result = await self.scheduler.wait_for_meeting( self._id, meeting_id, timeout=timeout ) logger.info(f"会议 {meeting_id} 结果: {result}") return result async def write_state(self, state: Dict) -> None: """ 写入状态到注册表 状态包含:当前任务、进度、临时数据等 """ task = state.get("task", "") progress = state.get("progress", 0) await self.registry.update_state(self._id, task, progress) logger.debug(f"状态已更新: {self._id} -> {progress}%") async def read_others(self, agent_id: str) -> Dict: """ 读取其他 Agent 的状态 用于 Agent 之间互相了解工作状态 """ agent = await self.registry.get_agent(agent_id) if not agent: return {"error": f"Agent {agent_id} 不存在"} state = await self.registry.get_state(agent_id) heartbeat = await self.heartbeat_service.get_heartbeat(agent_id) return { "agent": { "agent_id": agent.agent_id, "name": agent.name, "role": agent.role, "model": agent.model, "status": agent.status }, "state": { "current_task": state.current_task if state else None, "progress": state.progress if state else 0 } if state else None, "heartbeat": { "status": heartbeat.status if heartbeat else None, "last_seen": heartbeat.last_seen.isoformat() if heartbeat else None, "is_alive": heartbeat.is_alive() if heartbeat else False } if heartbeat else None } async def update_heartbeat(self, status: str, task: str = "", progress: int = 0) -> None: """ 更新心跳 参数: status: working, waiting, idle, error task: 当前任务描述 progress: 进度 0-100 """ await self.heartbeat_service.update_heartbeat( self._id, status, task, progress ) # ========== 生命周期 ========== async def initialize(self) -> None: """Agent 初始化""" logger.info(f"Agent 初始化: {self._id}") # 确保已注册 await self._ensure_registered() # 发送初始心跳 await self.update_heartbeat("idle", "", 0) self._is_running = True async def shutdown(self) -> None: """Agent 关闭""" logger.info(f"Agent 关闭: {self._id}") # 更新状态为离线 await self.update_heartbeat("offline", "", 0) self._is_running = False async def health_check(self) -> bool: """健康检查""" try: heartbeat = await self.heartbeat_service.get_heartbeat(self._id) return heartbeat is not None and heartbeat.is_alive() except Exception: return False # ========== 会议相关 ========== async def propose(self, meeting_id: str, content: str, step: str = "") -> None: """在会议中提出提案""" from ..services.meeting_recorder import get_meeting_recorder recorder = get_meeting_recorder() await recorder.add_discussion( meeting_id, self._id, self._role.upper(), content, step ) logger.debug(f"提案已添加: {self._id} -> {meeting_id}") async def discuss(self, meeting_id: str, content: str, step: str = "") -> None: """在会议中参与讨论""" await self.propose(meeting_id, content, step) async def vote(self, meeting_id: str, proposal_id: str, agree: bool) -> None: """对提案进行投票""" # TODO: 实现投票机制 logger.debug(f"投票: {self._id} -> {proposal_id}: {agree}") # ========== 私有方法 ========== async def _ensure_registered(self): """确保 Agent 已注册""" agent = await self.registry.get_agent(self._id) if agent is None: # 注册 Agent agent = await self.registry.register_agent( self._id, self._name, self._role, self._model, self.config.get("description", f"{self._name} - {self._role}") ) logger.info(f"Agent 已注册: {self._id}") return agent # ========== 高级功能 ========== async def collaborate_with( self, other_agent_ids: list, task: str, meeting_id: str = None ) -> Dict: """ 与其他 Agent 协作完成任务 流程: 1. 创建或加入会议 2. 等待所有 Agent 到达 3. 讨论和分工 4. 执行分配的任务 5. 汇总结果 """ if not meeting_id: # 生成会议 ID import uuid meeting_id = f"meeting_{uuid.uuid4().hex[:12]}" # 创建会议 await self.scheduler.create_meeting( meeting_id, f"协作任务: {task[:50]}", [self._id] + other_agent_ids ) # 更新心跳 await self.update_heartbeat("waiting", f"等待协作会议: {meeting_id}", 0) # 提出初始提案 await self.propose(meeting_id, f"任务: {task}") return { "meeting_id": meeting_id, "status": "waiting", "participants": [self._id] + other_agent_ids } async def start_collaboration_loop( self, meeting_id: str, max_iterations: int = 5 ) -> Dict: """ 启动协作循环 持续参与会议讨论,直到达成共识或达到最大迭代次数 """ from ..services.meeting_recorder import get_meeting_recorder recorder = get_meeting_recorder() for iteration in range(max_iterations): # 等待会议开始 result = await self.join_meeting(meeting_id) if result == "started": # 获取会议信息 meeting = await recorder.get_meeting(meeting_id) if meeting and meeting.status == "completed": return { "status": "consensus_reached", "consensus": meeting.consensus, "iterations": iteration + 1 } # 分析当前讨论,提出自己的观点 await self._analyze_and_respond(meeting_id) elif result == "timeout": return { "status": "timeout", "iterations": iteration + 1 } return { "status": "max_iterations_reached", "iterations": max_iterations } async def _analyze_and_respond(self, meeting_id: str) -> None: """分析会议讨论并响应""" from ..services.meeting_recorder import get_meeting_recorder recorder = get_meeting_recorder() meeting = await recorder.get_meeting(meeting_id) if not meeting: return # 获取最近的讨论 recent_discussions = meeting.discussions[-5:] if meeting.discussions else [] # 构建分析提示 discussion_summary = "\n".join([ f"{d.agent} ({d.timestamp}): {d.content}" for d in recent_discussions ]) response_prompt = f""" 你是 {self._name} ({self._role})。 以下是会议讨论的摘要: {discussion_summary} 请基于你的角色 ({self._role}),给出你的回应: - 如果你不同意之前的提案,说明理由 - 如果你有更好的建议,提出新方案 - 如果你同意,可以表示支持或补充细节 保持简洁,直接回应。 """ # 调用 LLM 生成响应 if self.llm_service: try: llm_response = await self.llm_service.route_task( task=response_prompt, messages=[ {"role": "system", "content": f"你是 {self._name},一个 {self._role}。"}, {"role": "user", "content": response_prompt} ] ) # 发送响应到会议 await self.discuss(meeting_id, llm_response.content) except Exception as e: logger.error(f"生成会议响应失败: {e}") class NativeLLMAgentFactory: """原生 LLM Agent 工厂类""" @staticmethod async def create( agent_id: str, name: str = None, role: str = "developer", model: str = "claude-sonnet-4.6", config: Dict = None ) -> NativeLLMAgent: """ 创建并初始化一个 Agent 参数: agent_id: Agent 唯一标识 name: 显示名称(默认从 agent_id 生成) role: 角色 (architect, pm, developer, qa, reviewer) model: 使用的模型 config: 额外配置 """ if name is None: name = agent_id.replace("-", " ").title() agent = NativeLLMAgent( agent_id=agent_id, name=name, role=role, model=model, config=config ) # 初始化 Agent await agent.initialize() return agent @staticmethod async def create_team(team_config: Dict) -> Dict[str, NativeLLMAgent]: """ 创建一个 Agent 团队 配置格式: { "team_id": "dev-team-1", "agents": [ {"id": "arch-001", "role": "architect", "model": "claude-opus-4.6"}, {"id": "dev-001", "role": "developer", "model": "claude-sonnet-4.6"}, {"id": "qa-001", "role": "qa", "model": "claude-haiku-4.6"} ] } """ agents = {} for agent_config in team_config.get("agents", []): agent = await NativeLLMAgentFactory.create( agent_id=agent_config["id"], role=agent_config.get("role", "developer"), model=agent_config.get("model", "claude-sonnet-4.6"), config=agent_config.get("config", {}) ) agents[agent.id] = agent return agents