""" Agent管理路由 """ from typing import List, Optional, Dict, Any from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel, Field from loguru import logger from services.agent_service import AgentService, AGENT_TEMPLATES router = APIRouter() # ============ 请求/响应模型 ============ class CapabilitiesModel(BaseModel): """能力配置模型""" memory_enabled: bool = False mcp_tools: List[str] = [] skills: List[str] = [] multimodal: bool = False class BehaviorModel(BaseModel): """行为配置模型""" speak_threshold: float = 0.5 max_speak_per_round: int = 2 speak_style: str = "balanced" class AgentCreateRequest(BaseModel): """创建Agent请求""" name: str = Field(..., description="Agent名称") role: str = Field(..., description="角色定义") system_prompt: str = Field(..., description="系统提示词") provider_id: str = Field(..., description="使用的AI接口ID") temperature: float = Field(default=0.7, ge=0, le=2, description="温度参数") max_tokens: int = Field(default=2000, gt=0, description="最大token数") capabilities: Optional[CapabilitiesModel] = None behavior: Optional[BehaviorModel] = None avatar: Optional[str] = None color: str = "#1890ff" class Config: json_schema_extra = { "example": { "name": "产品经理", "role": "产品规划和需求分析专家", "system_prompt": "你是一位经验丰富的产品经理...", "provider_id": "openrouter-abc123", "temperature": 0.7, "max_tokens": 2000 } } class AgentUpdateRequest(BaseModel): """更新Agent请求""" name: Optional[str] = None role: Optional[str] = None system_prompt: Optional[str] = None provider_id: Optional[str] = None temperature: Optional[float] = Field(default=None, ge=0, le=2) max_tokens: Optional[int] = Field(default=None, gt=0) capabilities: Optional[CapabilitiesModel] = None behavior: Optional[BehaviorModel] = None avatar: Optional[str] = None color: Optional[str] = None enabled: Optional[bool] = None class AgentResponse(BaseModel): """Agent响应""" agent_id: str name: str role: str system_prompt: str provider_id: str temperature: float max_tokens: int capabilities: Dict[str, Any] behavior: Dict[str, Any] avatar: Optional[str] color: str enabled: bool created_at: str updated_at: str class AgentTestRequest(BaseModel): """Agent测试请求""" message: str = "你好,请简单介绍一下你自己。" class AgentTestResponse(BaseModel): """Agent测试响应""" success: bool message: str response: Optional[str] = None model: Optional[str] = None tokens: Optional[int] = None latency_ms: Optional[float] = None class TemplateResponse(BaseModel): """模板响应""" template_id: str name: str role: str system_prompt: str color: str class GeneratePromptRequest(BaseModel): """生成提示词请求""" provider_id: str = Field(..., description="使用的AI接口ID") name: str = Field(..., description="Agent名称") role: str = Field(..., description="角色定位") description: Optional[str] = Field(None, description="额外描述(可选)") class GeneratePromptResponse(BaseModel): """生成提示词响应""" success: bool message: Optional[str] = None prompt: Optional[str] = None model: Optional[str] = None tokens: Optional[int] = None # ============ 路由处理 ============ @router.post("", response_model=AgentResponse, status_code=status.HTTP_201_CREATED) async def create_agent(request: AgentCreateRequest): """ 创建新的Agent """ try: agent = await AgentService.create_agent( name=request.name, role=request.role, system_prompt=request.system_prompt, provider_id=request.provider_id, temperature=request.temperature, max_tokens=request.max_tokens, capabilities=request.capabilities.dict() if request.capabilities else None, behavior=request.behavior.dict() if request.behavior else None, avatar=request.avatar, color=request.color ) return _to_response(agent) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"创建Agent失败: {e}") raise HTTPException(status_code=500, detail="创建失败") @router.get("", response_model=List[AgentResponse]) async def list_agents(enabled_only: bool = False): """ 获取所有Agent """ agents = await AgentService.get_all_agents(enabled_only) return [_to_response(a) for a in agents] @router.get("/templates", response_model=List[TemplateResponse]) async def list_templates(): """ 获取Agent预设模板 """ return [ TemplateResponse( template_id=tid, name=t["name"], role=t["role"], system_prompt=t["system_prompt"], color=t["color"] ) for tid, t in AGENT_TEMPLATES.items() ] @router.post("/generate-prompt", response_model=GeneratePromptResponse) async def generate_prompt(request: GeneratePromptRequest): """ 使用AI生成Agent系统提示词 """ result = await AgentService.generate_system_prompt( provider_id=request.provider_id, name=request.name, role=request.role, description=request.description ) return GeneratePromptResponse(**result) @router.get("/{agent_id}", response_model=AgentResponse) async def get_agent(agent_id: str): """ 获取指定Agent """ agent = await AgentService.get_agent(agent_id) if not agent: raise HTTPException(status_code=404, detail="Agent不存在") return _to_response(agent) @router.put("/{agent_id}", response_model=AgentResponse) async def update_agent(agent_id: str, request: AgentUpdateRequest): """ 更新Agent配置 """ update_data = request.dict(exclude_unset=True) # 转换嵌套模型 if "capabilities" in update_data and update_data["capabilities"]: if hasattr(update_data["capabilities"], "dict"): update_data["capabilities"] = update_data["capabilities"].dict() if "behavior" in update_data and update_data["behavior"]: if hasattr(update_data["behavior"], "dict"): update_data["behavior"] = update_data["behavior"].dict() try: agent = await AgentService.update_agent(agent_id, **update_data) if not agent: raise HTTPException(status_code=404, detail="Agent不存在") return _to_response(agent) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @router.delete("/{agent_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_agent(agent_id: str): """ 删除Agent """ success = await AgentService.delete_agent(agent_id) if not success: raise HTTPException(status_code=404, detail="Agent不存在") @router.post("/{agent_id}/test", response_model=AgentTestResponse) async def test_agent(agent_id: str, request: AgentTestRequest = None): """ 测试Agent对话 """ message = request.message if request else "你好,请简单介绍一下你自己。" result = await AgentService.test_agent(agent_id, message) return AgentTestResponse(**result) @router.post("/{agent_id}/duplicate", response_model=AgentResponse) async def duplicate_agent(agent_id: str, new_name: Optional[str] = None): """ 复制Agent """ agent = await AgentService.duplicate_agent(agent_id, new_name) if not agent: raise HTTPException(status_code=404, detail="源Agent不存在") return _to_response(agent) @router.post("/from-template/{template_id}", response_model=AgentResponse) async def create_from_template(template_id: str, provider_id: str): """ 从模板创建Agent """ if template_id not in AGENT_TEMPLATES: raise HTTPException(status_code=404, detail="模板不存在") template = AGENT_TEMPLATES[template_id] try: agent = await AgentService.create_agent( name=template["name"], role=template["role"], system_prompt=template["system_prompt"], provider_id=provider_id, color=template["color"] ) return _to_response(agent) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) # ============ 辅助函数 ============ def _to_response(agent) -> AgentResponse: """ 转换为响应模型 """ return AgentResponse( agent_id=agent.agent_id, name=agent.name, role=agent.role, system_prompt=agent.system_prompt, provider_id=agent.provider_id, temperature=agent.temperature, max_tokens=agent.max_tokens, capabilities=agent.capabilities, behavior=agent.behavior, avatar=agent.avatar, color=agent.color, enabled=agent.enabled, created_at=agent.created_at.isoformat(), updated_at=agent.updated_at.isoformat() )