feat: 更新 Server 后端服务

- 更新 agent handler 和 service 层
- 新增 chat_group handler 和 service
- 删除废弃的 chat_handler
- 更新 tool 相关处理
- 更新 API 文档和依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 21:26:27 +08:00
parent 237ab9f6d7
commit 71e8cc59d5
24 changed files with 5007 additions and 347 deletions

View File

@@ -2,6 +2,7 @@ package handler
import (
"net/http"
"strconv"
"x-agents/server/internal/service"
@@ -22,7 +23,7 @@ func NewAgentHandler(agentService *service.AgentService) *AgentHandler {
// ChatRequest 对话请求
type ChatRequest struct {
AgentID int `json:"agent_id" binding:"required"`
AgentID string `json:"agent_id" binding:"required"` // 字符串类型
Message string `json:"message" binding:"required"`
SessionID string `json:"session_id"`
ModelID string `json:"model_id"`
@@ -69,10 +70,14 @@ func (h *AgentHandler) Chat(c *gin.Context) {
}
// 获取用户 ID从认证中间件获取
userID := 1 // TODO: 从 c.Get("user_id") 获取
userIDStr := "1" // TODO: 从 c.Get("user_id") 获取
userID, _ := strconv.Atoi(userIDStr)
// 将前端传来的字符串 agent_id 转换为 int
agentID, _ := strconv.Atoi(req.AgentID)
pythonReq := service.AgentChatRequest{
AgentID: req.AgentID,
AgentID: agentID,
Message: req.Message,
UserID: userID,
SessionID: req.SessionID,
@@ -122,7 +127,11 @@ func (h *AgentHandler) ChatStream(c *gin.Context) {
}
// 获取用户 ID
userID := 1 // TODO: 从 c.Get("user_id") 获取
userIDStr := "1" // TODO: 从 c.Get("user_id") 获取
userID, _ := strconv.Atoi(userIDStr)
// 将前端传来的字符串 agent_id 转换为 int
agentID, _ := strconv.Atoi(req.AgentID)
// 构建 SSE 流
c.Header("Content-Type", "text/event-stream")
@@ -131,7 +140,7 @@ func (h *AgentHandler) ChatStream(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
// 调用 Python 服务的流式端点
err := h.agentService.ChatStream(c, req.AgentID, req.Message, req.SessionID, req.ModelID, userID)
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()})
}
@@ -173,7 +182,8 @@ func (h *AgentHandler) TeamChat(c *gin.Context) {
}
// 获取用户 ID
userID := 1 // TODO: 从 c.Get("user_id") 获取
userIDStr := "1" // TODO: 从 c.Get("user_id") 获取
userID, _ := strconv.Atoi(userIDStr)
pythonReq := service.TeamChatRequest{
SupervisorAgentID: req.SupervisorAgentID,

View File

@@ -1,6 +1,7 @@
package handler
import (
"log"
"net/http"
"strconv"
@@ -140,10 +141,13 @@ func (h *ChatGroupHandler) GroupChat(c *gin.Context) {
}
response, err := h.groupService.GroupChat(userID, req.Message, agentIDs, req.SessionID)
log.Printf("[ChatGroupHandler] Got response, err: %v", err)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
log.Printf("[ChatGroupHandler] Response subtask_results: %+v", response.SubtaskResults)
c.JSON(http.StatusOK, response)
}

View File

@@ -1,89 +0,0 @@
package handler
import (
"net/http"
"x-agents/server/internal/model"
"x-agents/server/internal/service"
"github.com/gin-gonic/gin"
)
type ChatHandler struct {
chatService *service.ChatService
}
func NewChatHandler(chatService *service.ChatService) *ChatHandler {
return &ChatHandler{chatService: chatService}
}
// Chat 处理聊天请求
func (h *ChatHandler) Chat(c *gin.Context) {
var req model.AgentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 从上下文获取用户ID由中间件设置
userID, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
resp, err := h.chatService.Chat(c.Request.Context(), userID.(string), req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, resp)
}
// ListAgents 获取 Agent 列表
func (h *ChatHandler) ListAgents(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
agents, err := h.chatService.ListAgents(userID.(string))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
if agents == nil {
agents = []model.Agent{}
}
c.JSON(http.StatusOK, gin.H{"agents": agents})
}
// CreateAgent 创建 Agent
func (h *ChatHandler) CreateAgent(c *gin.Context) {
userID, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}
var req struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
agent, err := h.chatService.CreateAgent(userID.(string), req.Name, req.Description)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, agent)
}

View File

@@ -164,3 +164,46 @@ func (h *ToolHandler) Delete(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "tool deleted"})
}
// SyncFromPythonRequest 从Python同步工具请求
type SyncFromPythonRequest struct {
Tools []PythonTool `json:"tools" binding:"required"`
}
// PythonTool Python端工具结构
type PythonTool struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters string `json:"parameters"`
Category string `json:"category"`
}
// SyncFromPython 从Python端同步工具
// @Summary 从Python端同步工具
// @Description 接收Python Agent同步过来的工具列表并存储到数据库
// @Tags 工具管理
// @Accept json
// @Produce json
// @Param tools body SyncFromPythonRequest true "工具列表"
// @Success 200 {object} map[string]interface{}
// @Router /tool/sync-from-python [post]
func (h *ToolHandler) SyncFromPython(c *gin.Context) {
var req struct {
Tools []map[string]interface{} `json:"tools" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
count, err := h.toolService.SyncToolsFromPython(req.Tools)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "tools synced from python",
"synced_count": count,
})
}