diff --git a/core/agents/api/__init__.py b/core/agents/api/__init__.py index f95fbff..76e3571 100644 --- a/core/agents/api/__init__.py +++ b/core/agents/api/__init__.py @@ -1,5 +1,5 @@ """X-Agents API Module.""" -from agents.api.routes import router +from .routes import router __all__ = ["router"] diff --git a/core/agents/api/server.py b/core/agents/api/server.py new file mode 100644 index 0000000..e6e6de9 --- /dev/null +++ b/core/agents/api/server.py @@ -0,0 +1,26 @@ +"""X-Agents API Server.""" + +import sys +sys.path.insert(0, 'D:/Code/Project/X-Agents/core') + +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from .routes import router + +app = FastAPI(title="X-Agents API") + +# Add CORS middleware +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# Include the router +app.include_router(router) + +if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=8001) diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index d26a80e..fb9e194 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -387,7 +387,14 @@ func main() { log.Println("Default tools initialized") } - // 4.3 初始化 skills(已禁用自动加载,如需启用请调用 /skill/sync 接口) + // 4.3 初始化团队成员智能体 + if err := agentService.InitTeamMembers(); err != nil { + log.Printf("Warning: Failed to init team members: %v", err) + } else { + log.Println("Team members initialized") + } + + // 4.4 初始化 skills(已禁用自动加载,如需启用请调用 /skill/sync 接口) // if err := skillService.InitSkills(); err != nil { // log.Printf("Warning: Failed to init skills: %v", err) // } else { @@ -405,7 +412,7 @@ func main() { toolHandler := handler.NewToolHandler(toolService) mcpHandler := handler.NewMCPHandler(mcpService) skillHandler := handler.NewSkillHandler(skillService) - agentHandler := handler.NewAgentHandler(agentService) + agentHandler := handler.NewAgentHandler(agentService, agentRepo) memoryHandler := handler.NewMemoryHandler(memoryService) sessionHandler := handler.NewSessionHandler(chatRepo, agentService) @@ -590,6 +597,7 @@ func main() { { agentGroup.GET("/list", agentHandler.ListAgents) agentGroup.POST("/create", agentHandler.CreateAgent) + agentGroup.POST("/init-team", agentHandler.InitTeamMembers) agentGroup.PUT("/:id/status", agentHandler.UpdateAgentStatus) agentGroup.PUT("/:id", agentHandler.UpdateAgent) agentGroup.DELETE("/:id", agentHandler.DeleteAgent) diff --git a/server/config/config.yaml b/server/config/config.yaml index 05908d5..ede9d66 100644 --- a/server/config/config.yaml +++ b/server/config/config.yaml @@ -1,5 +1,5 @@ # 本地开发配置 -port: "8082" +port: "8080" jwt_secret: "dev-secret-key" # 数据库配置 (类型: mysql 或 sqlite) diff --git a/server/internal/handler/agent_handler.go b/server/internal/handler/agent_handler.go index 16cd869..5d04def 100644 --- a/server/internal/handler/agent_handler.go +++ b/server/internal/handler/agent_handler.go @@ -1,10 +1,15 @@ 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" ) @@ -12,22 +17,25 @@ import ( // AgentHandler Agent 处理器 type AgentHandler struct { agentService *service.AgentService + agentRepo *repository.AgentRepository } // NewAgentHandler 创建 Agent 处理器 -func NewAgentHandler(agentService *service.AgentService) *AgentHandler { +func NewAgentHandler(agentService *service.AgentService, agentRepo *repository.AgentRepository) *AgentHandler { return &AgentHandler{ agentService: agentService, + agentRepo: agentRepo, } } // ChatRequest 对话请求 type ChatRequest struct { - AgentID string `json:"agent_id" binding:"required"` // 字符串类型 - Message string `json:"message" binding:"required"` - SessionID string `json:"session_id"` - ModelID string `json:"model_id"` - UseXBot bool `json:"use_xbot"` + 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 对话响应 @@ -131,6 +139,29 @@ func (h *AgentHandler) ChatStream(c *gin.Context) { // 直接使用字符串类型的 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") @@ -144,6 +175,37 @@ func (h *AgentHandler) ChatStream(c *gin.Context) { } } +// 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"` @@ -236,6 +298,30 @@ func (h *AgentHandler) CreateAgent(c *gin.Context) { 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 智能体管理 diff --git a/server/internal/service/agent_service.go b/server/internal/service/agent_service.go index 72d9e83..814e4aa 100644 --- a/server/internal/service/agent_service.go +++ b/server/internal/service/agent_service.go @@ -117,7 +117,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) { log.Printf("[AgentService] Sending to Python: model_id=%s, api_key=%s, base_url=%s, provider=%s, model=%s", req.ModelID, apiKeyPreview, req.BaseURL, req.ModelProvider, req.ModelName) - url := fmt.Sprintf("%s/api/v1/agent/chat", s.pythonURL) + url := fmt.Sprintf("%s/agent/chat", s.pythonURL) jsonData, err := json.Marshal(req) if err != nil { @@ -155,7 +155,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) { // TeamChat 多智能体群聊 func (s *AgentService) TeamChat(req TeamChatRequest) (*TeamChatResponse, error) { - url := fmt.Sprintf("%s/api/v1/agent/team/chat", s.pythonURL) + url := fmt.Sprintf("%s/agent/team/chat", s.pythonURL) // 设置默认策略 if req.Strategy == "" { @@ -233,7 +233,7 @@ func (s *AgentService) ChatStream(c interface{}, agentID string, message, sessio log.Printf("[ChatStream] modelID is empty or modelRepo is nil: modelID=%s, modelRepo=%v", modelID, s.modelRepo != nil) } - streamURL := fmt.Sprintf("%s/api/v1/agent/chat/stream", s.pythonURL) + streamURL := fmt.Sprintf("%s/agent/chat/stream", s.pythonURL) jsonData, err := json.Marshal(reqBody) if err != nil { @@ -365,6 +365,89 @@ func (s *AgentService) CreateAgent(req CreateAgentRequest, userID int) (*CreateA }, nil } +// TeamMemberInitRequest 团队成员初始化请求 +type TeamMemberInitRequest struct { + Name string + Description string + Avatar string + Skills []string + RoleDescription string +} + +// InitTeamMembers 初始化团队成员智能体 +func (s *AgentService) InitTeamMembers() error { + if s.agentRepo == nil { + log.Printf("[AgentService] InitTeamMembers: agentRepo is nil!") + return fmt.Errorf("agent repository not initialized") + } + + // 骚人开发组团队成员配置 + teamMembers := []TeamMemberInitRequest{ + { + Name: "小荣", + Description: "前端开发工程师 - 骚人开发组成员", + Avatar: "👨‍💻", + Skills: []string{"Vue 3", "TypeScript", "Element Plus", "Tailwind CSS"}, + RoleDescription: `你叫小荣,是骚人开发组的前端开发工程师。你细心认真,善于沟通。 + +技能专长: +- Vue 3 框架开发 +- TypeScript 类型系统 +- Element Plus 组件库 +- Tailwind CSS 样式框架 + +性格特点: +- 细心认真,注重代码质量 +- 善于与团队成员沟通协作 +- 积极解决前端技术难题`, + }, + } + + // 检查是否已存在同名智能体 + for _, member := range teamMembers { + existingAgents, err := s.agentRepo.FindAll() + if err != nil { + log.Printf("[AgentService] InitTeamMembers: failed to list agents: %v", err) + continue + } + + exists := false + for _, a := range existingAgents { + if a.Name == member.Name { + exists = true + log.Printf("[AgentService] InitTeamMembers: agent %s already exists, skipping", member.Name) + break + } + } + + if !exists { + // 创建智能体 + agent := &model.Agent{ + ID: uuid.New().String(), + Name: member.Name, + Description: member.Description, + OwnerID: "1", // 系统管理员 + Avatar: member.Avatar, + Skills: member.Skills, + RoleDescription: member.RoleDescription, + ModelProvider: "anthropic", + ModelName: "claude-sonnet-4-20250514", + IsActive: true, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + if err := s.agentRepo.Create(agent); err != nil { + log.Printf("[AgentService] InitTeamMembers: failed to create agent %s: %v", member.Name, err) + continue + } + log.Printf("[AgentService] InitTeamMembers: created agent %s (ID: %s)", member.Name, agent.ID) + } + } + + return nil +} + // ListAgentsResponse 获取智能体列表响应 type ListAgentsResponse struct { Agents []interface{} `json:"agents"` diff --git a/web/src/components/chat/ChatInput.vue b/web/src/components/chat/ChatInput.vue index e994195..189b962 100644 --- a/web/src/components/chat/ChatInput.vue +++ b/web/src/components/chat/ChatInput.vue @@ -1,15 +1,137 @@