package handler import ( "log" "net/http" "strconv" "strings" "x-agents/server/internal/model" "x-agents/server/internal/repository" "x-agents/server/internal/service" "x-agents/server/internal/utils" "github.com/gin-gonic/gin" ) // AgentHandler Agent 处理器 type AgentHandler struct { agentService *service.AgentService agentRepo *repository.AgentRepository } // NewAgentHandler 创建 Agent 处理器 func NewAgentHandler(agentService *service.AgentService, agentRepo *repository.AgentRepository) *AgentHandler { return &AgentHandler{ agentService: agentService, agentRepo: agentRepo, } } // ChatRequest 对话请求 type ChatRequest struct { AgentID string `json:"agent_id"` // 字符串类型,支持 UUID,可为空(当使用 mentioned_agent_ids 时) Message string `json:"message" binding:"required"` SessionID string `json:"session_id"` ModelID string `json:"model_id"` UseXBot bool `json:"use_xbot"` MentionedAgentIDs []string `json:"mentioned_agent_ids"` // @ 提及的智能体 ID 列表 } // ChatResponse 对话响应 type ChatResponse struct { AgentID string `json:"agent_id"` // 支持 UUID 字符串 Reply string `json:"reply"` ToolsUsed []string `json:"tools_used"` SessionID string `json:"session_id"` TokensUsed int `json:"tokens_used"` DurationMs int `json:"duration_ms"` Metadata interface{} `json:"metadata"` } // CreateAgentResponse 创建智能体响应 type CreateAgentResponse struct { AgentID int `json:"agent_id"` Name string `json:"name"` Message string `json:"message"` } // ListAgentsResponse 获取智能体列表响应 type ListAgentsResponse struct { Agents []interface{} `json:"agents"` } // Chat 单智能体对话 // @Summary 单智能体对话 // @Tags 智能体管理 // @Accept json // @Produce json // @Param request body ChatRequest true "对话请求" // @Success 200 {object} ChatResponse // @Router /api/agent/chat [post] func (h *AgentHandler) Chat(c *gin.Context) { var req ChatRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 获取用户 ID(从认证中间件获取) userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 userID, _ := strconv.Atoi(userIDStr) // 直接使用字符串类型的 agent_id,支持 UUID pythonReq := service.AgentChatRequest{ AgentID: req.AgentID, Message: req.Message, UserID: userID, SessionID: req.SessionID, ModelID: req.ModelID, UseXBot: req.UseXBot, } result, err := h.agentService.Chat(pythonReq) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } // 转换工具调用 toolsUsed := make([]string, 0) for _, tool := range result.ToolCalls { if toolMap, ok := tool.(map[string]interface{}); ok { if skillID, ok := toolMap["skill_id"].(string); ok { toolsUsed = append(toolsUsed, skillID) } } } c.JSON(http.StatusOK, ChatResponse{ AgentID: result.AgentID, Reply: result.Response, ToolsUsed: toolsUsed, SessionID: result.SessionID, TokensUsed: result.TokensUsed, DurationMs: result.DurationMs, Metadata: nil, }) } // ChatStream 单智能体对话(流式输出) // @Summary 单智能体对话(流式输出) // @Tags 智能体管理 // @Accept json // @Produce text/event-stream // @Param request body ChatRequest true "对话请求" // @Router /api/agent/chat/stream [post] func (h *AgentHandler) ChatStream(c *gin.Context) { var req ChatRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 获取用户 ID userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 userID, _ := strconv.Atoi(userIDStr) // 直接使用字符串类型的 agent_id,支持 UUID agentID := req.AgentID // 优先使用前端传递的 mentioned_agent_ids if len(req.MentionedAgentIDs) > 0 { // 如果有多个 @ 提及,使用第一个 mentionedAgentID := req.MentionedAgentIDs[0] log.Printf("[ChatStream] Using mentioned_agent_ids: %v", req.MentionedAgentIDs) agentID = mentionedAgentID // 清理消息,移除 @ 提及 mentionParser := utils.NewMentionParser() req.Message = mentionParser.RemoveMentions(req.Message) } else if agentID == "" { // 兼容:解析消息中的 @ 提及(备用方案) mentionParser := utils.NewMentionParser() mentions := mentionParser.ParseMentions(req.Message) if len(mentions) > 0 { mentionedAgent := h.findAgentByName(mentions[0]) if mentionedAgent != nil { log.Printf("[ChatStream] Detected @mention: %s, routing to agent: %s", mentions[0], mentionedAgent.ID) agentID = mentionedAgent.ID } req.Message = mentionParser.RemoveMentions(req.Message) } } // 构建 SSE 流 c.Header("Content-Type", "text/event-stream") c.Header("Cache-Control", "no-cache") c.Header("Connection", "keep-alive") c.Header("Access-Control-Allow-Origin", "*") // 调用 Python 服务的流式端点 err := h.agentService.ChatStream(c, agentID, req.Message, req.SessionID, req.ModelID, userID) if err != nil && !c.IsAborted() { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } } // findAgentByName 根据用户名查找智能体 func (h *AgentHandler) findAgentByName(name string) *model.Agent { log.Printf("[findAgentByName] Searching for agent: %s, agentRepo: %v", name, h.agentRepo) if h.agentRepo == nil { log.Printf("[findAgentByName] ERROR: agentRepo is nil!") return nil } // 先尝试精确匹配 agents, err := h.agentRepo.FindAll() if err != nil { return nil } for _, agent := range agents { if agent.Name == name { return &agent } } // 再尝试模糊匹配(忽略大小写) for _, agent := range agents { if strings.Contains(strings.ToLower(agent.Name), strings.ToLower(name)) { return &agent } } return nil } // TeamChatRequest 多智能体群聊请求 type TeamChatRequest struct { SupervisorAgentID int `json:"supervisor_agent_id" binding:"required"` MemberAgentIDs []int `json:"member_agent_ids" binding:"required"` Message string `json:"message" binding:"required"` SessionID string `json:"session_id"` Strategy string `json:"strategy"` } // TeamChatResponse 多智能体群聊响应 type TeamChatResponse struct { SupervisorAgentID int `json:"supervisor_agent_id"` Reply string `json:"reply"` SubtaskResults interface{} `json:"subtask_results"` Strategy string `json:"strategy"` SessionID string `json:"session_id"` DurationMs int `json:"duration_ms"` Metadata interface{} `json:"metadata"` } // TeamChat 多智能体群聊 // @Summary 多智能体群聊 // @Tags 智能体管理 // @Accept json // @Produce json // @Param request body TeamChatRequest true "群聊请求" // @Success 200 {object} TeamChatResponse // @Router /api/agent/team/chat [post] func (h *AgentHandler) TeamChat(c *gin.Context) { var req TeamChatRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 获取用户 ID userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 userID, _ := strconv.Atoi(userIDStr) pythonReq := service.TeamChatRequest{ SupervisorAgentID: req.SupervisorAgentID, MemberAgentIDs: req.MemberAgentIDs, Message: req.Message, UserID: userID, SessionID: req.SessionID, Strategy: req.Strategy, } result, err := h.agentService.TeamChat(pythonReq) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, TeamChatResponse{ SupervisorAgentID: result.SupervisorAgentID, Reply: result.Response, SubtaskResults: result.SubtaskResults, Strategy: result.Strategy, SessionID: result.SessionID, DurationMs: result.DurationMs, Metadata: nil, }) } // CreateAgent 创建智能体 // @Summary 创建智能体 // @Tags 智能体管理 // @Accept json // @Produce json // @Param request body CreateAgentRequest true "创建智能体请求" // @Success 200 {object} CreateAgentResponse // @Router /api/agent/create [post] func (h *AgentHandler) CreateAgent(c *gin.Context) { var req service.CreateAgentRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 获取用户 ID userID := 1 // TODO: 从 c.Get("user_id") 获取 result, err := h.agentService.CreateAgent(req, userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, result) } // InitTeamMembersResponse 初始化团队成员响应 type InitTeamMembersResponse struct { Message string `json:"message"` Count int `json:"count"` } // InitTeamMembers 初始化团队成员智能体 // @Summary 初始化团队成员智能体 // @Tags 智能体管理 // @Produce json // @Success 200 {object} InitTeamMembersResponse // @Router /api/agent/init-team [post] func (h *AgentHandler) InitTeamMembers(c *gin.Context) { if err := h.agentService.InitTeamMembers(); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, InitTeamMembersResponse{ Message: "Team members initialized successfully", Count: 1, // 小荣 }) } // ListAgents 获取智能体列表 // @Summary 获取智能体列表 // @Tags 智能体管理 // @Produce json // @Success 200 {object} ListAgentsResponse // @Router /api/agent/list [get] func (h *AgentHandler) ListAgents(c *gin.Context) { result, err := h.agentService.ListAgents() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, result) } // UpdateAgentStatusRequest 更新状态请求 type UpdateAgentStatusRequest struct { IsActive bool `json:"is_active"` } // UpdateAgentStatus 更新智能体状态 // @Summary 更新智能体状态 // @Tags 智能体管理 // @Accept json // @Produce json // @Param id path string true "Agent ID" // @Param request body UpdateAgentStatusRequest true "状态请求" // @Success 200 {object} gin.H // @Router /api/agent/{id}/status [put] func (h *AgentHandler) UpdateAgentStatus(c *gin.Context) { agentID := c.Param("id") if agentID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "agent id is required"}) return } var req UpdateAgentStatusRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } err := h.agentService.UpdateAgentStatus(agentID, req.IsActive) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "status updated successfully"}) } // DeleteAgent 删除智能体 // @Summary 删除智能体 // @Tags 智能体管理 // @Produce json // @Param id path string true "Agent ID" // @Success 200 {object} gin.H // @Router /api/agent/{id} [delete] func (h *AgentHandler) DeleteAgent(c *gin.Context) { agentID := c.Param("id") if agentID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "agent id is required"}) return } err := h.agentService.DeleteAgent(agentID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "agent deleted successfully"}) } // UpdateAgentRequest 更新智能体请求 type UpdateAgentRequest struct { Name string `json:"name"` Description string `json:"description"` Avatar string `json:"avatar"` Skills []string `json:"skills"` RoleDescription string `json:"role_description"` ModelProvider string `json:"model_provider"` ModelName string `json:"model_name"` } // UpdateAgent 更新智能体 // @Summary 更新智能体 // @Tags 智能体管理 // @Accept json // @Produce json // @Param id path string true "Agent ID" // @Param request body UpdateAgentRequest true "更新请求" // @Success 200 {object} gin.H // @Router /api/agent/{id} [put] func (h *AgentHandler) UpdateAgent(c *gin.Context) { agentID := c.Param("id") if agentID == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "agent id is required"}) return } var req UpdateAgentRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } err := h.agentService.UpdateAgent(agentID, req.Name, req.Description, req.Avatar, req.Skills, req.RoleDescription, req.ModelProvider, req.ModelName) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "agent updated successfully"}) }