feat: 更新后端agent和skill服务
- agent_handler.go: 新增ListAgents、CreateAgent接口 - skill_handler.go: 更新skill内容获取和保存功能 - agent_service.go: 新增agent服务逻辑 - main.go: 新增agent路由 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -500,6 +500,8 @@ func main() {
|
|||||||
// Agent管理模块 (调用 Python Agent Engine)
|
// Agent管理模块 (调用 Python Agent Engine)
|
||||||
agentGroup := r.Group("/api/agent")
|
agentGroup := r.Group("/api/agent")
|
||||||
{
|
{
|
||||||
|
agentGroup.GET("/list", agentHandler.ListAgents)
|
||||||
|
agentGroup.POST("/create", agentHandler.CreateAgent)
|
||||||
agentGroup.POST("/chat", agentHandler.Chat)
|
agentGroup.POST("/chat", agentHandler.Chat)
|
||||||
agentGroup.POST("/chat/stream", agentHandler.ChatStream)
|
agentGroup.POST("/chat/stream", agentHandler.ChatStream)
|
||||||
agentGroup.POST("/team/chat", agentHandler.TeamChat)
|
agentGroup.POST("/team/chat", agentHandler.TeamChat)
|
||||||
|
|||||||
@@ -40,7 +40,27 @@ type ChatResponse struct {
|
|||||||
Metadata interface{} `json:"metadata"`
|
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 单智能体对话
|
// 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) {
|
func (h *AgentHandler) Chat(c *gin.Context) {
|
||||||
var req ChatRequest
|
var req ChatRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -88,6 +108,12 @@ func (h *AgentHandler) Chat(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ChatStream 单智能体对话(流式输出)
|
// 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) {
|
func (h *AgentHandler) ChatStream(c *gin.Context) {
|
||||||
var req ChatRequest
|
var req ChatRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -132,6 +158,13 @@ type TeamChatResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TeamChat 多智能体群聊
|
// 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) {
|
func (h *AgentHandler) TeamChat(c *gin.Context) {
|
||||||
var req TeamChatRequest
|
var req TeamChatRequest
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
@@ -167,3 +200,46 @@ func (h *AgentHandler) TeamChat(c *gin.Context) {
|
|||||||
Metadata: nil,
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ package handler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"x-agents/server/internal/model"
|
"x-agents/server/internal/model"
|
||||||
"x-agents/server/internal/service"
|
"x-agents/server/internal/service"
|
||||||
@@ -115,18 +118,17 @@ func (h *SkillHandler) Create(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
userID, _ := c.Get("userID")
|
userID, _ := c.Get("userID")
|
||||||
|
|
||||||
|
// skillName 和 skillDesc 改为可选,如果没传则从文件内容解析
|
||||||
|
// 先从前端获取,但如果上传了文件则以文件内容解析的为准
|
||||||
skillName := c.PostForm("skill_name")
|
skillName := c.PostForm("skill_name")
|
||||||
skillDesc := c.PostForm("skill_desc")
|
skillDesc := c.PostForm("skill_desc")
|
||||||
skillType := c.PostForm("skill_type")
|
skillType := c.PostForm("skill_type")
|
||||||
|
|
||||||
if skillName == "" {
|
// 记录原始输入(用于调试)
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "skill_name is required"})
|
originalSkillName := skillName
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确定技能类型:优先使用传入的type,否则根据用户角色判断
|
// 确定技能类型:优先使用传入的type,否则根据用户角色判断
|
||||||
if skillType == "" {
|
if skillType == "" {
|
||||||
// 判断是否为管理员用户
|
|
||||||
if username == "admin" {
|
if username == "admin" {
|
||||||
skillType = "system"
|
skillType = "system"
|
||||||
} else {
|
} else {
|
||||||
@@ -147,24 +149,87 @@ func (h *SkillHandler) Create(c *gin.Context) {
|
|||||||
skillDir = "system"
|
skillDir = "system"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建技能目录
|
// 用于存储最终路径
|
||||||
skillPath := filepath.Join(projectRoot, "core", "agents", "skills", skillDir, skillName)
|
var skillPath string
|
||||||
if err := os.MkdirAll(skillPath, 0755); err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create skill directory: " + err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理文件上传
|
// 处理文件上传
|
||||||
file, err := c.FormFile("file")
|
file, err := c.FormFile("file")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// 保存上传的文件为 SKILL.md
|
// 读取文件内容,解析 YAML front matter 获取 name
|
||||||
|
fileContent, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to read file: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer fileContent.Close()
|
||||||
|
|
||||||
|
content := make([]byte, 1024*1024) // 最多读取 1MB
|
||||||
|
n, _ := fileContent.Read(content)
|
||||||
|
contentStr := string(content[:n])
|
||||||
|
|
||||||
|
// 解析 name
|
||||||
|
parsedName, parsedDesc := parseSkillMeta(contentStr)
|
||||||
|
log.Printf("[SkillHandler] Original skill_name from form: %s, parsed name from file: %s", originalSkillName, parsedName)
|
||||||
|
|
||||||
|
// 优先使用文件解析出的 name
|
||||||
|
if parsedName != "" {
|
||||||
|
skillName = parsedName
|
||||||
|
} else if skillName == "" {
|
||||||
|
// 如果解析不到且表单也没传,用文件名
|
||||||
|
skillName = filepath.Base(file.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsedDesc != "" {
|
||||||
|
skillDesc = parsedDesc
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理 skillName,只保留纯文件名,去除所有路径
|
||||||
|
skillName = filepath.Base(skillName)
|
||||||
|
// 去除 .md 后缀
|
||||||
|
skillName = strings.TrimSuffix(skillName, ".md")
|
||||||
|
// 去除空格
|
||||||
|
skillName = strings.TrimSpace(skillName)
|
||||||
|
// 如果包含路径分隔符,取最后一部分
|
||||||
|
if idx := strings.LastIndexAny(skillName, "/\\"); idx >= 0 {
|
||||||
|
skillName = skillName[idx+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[SkillHandler] Final skill name: %s", skillName)
|
||||||
|
|
||||||
|
// 创建技能目录
|
||||||
|
skillPath = filepath.Join(projectRoot, "core", "agents", "skills", skillDir, skillName)
|
||||||
|
if err := os.MkdirAll(skillPath, 0755); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create skill directory: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存文件(使用之前读取的内容)
|
||||||
skillFilePath := filepath.Join(skillPath, "SKILL.md")
|
skillFilePath := filepath.Join(skillPath, "SKILL.md")
|
||||||
if err := c.SaveUploadedFile(file, skillFilePath); err != nil {
|
if err := os.WriteFile(skillFilePath, []byte(contentStr), 0644); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save skill file: " + err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save skill file: " + err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 如果没有上传文件,创建一个默认的 SKILL.md
|
// 如果没有上传文件但提供了 name 和 desc,创建默认文件
|
||||||
|
if skillName == "" || skillDesc == "" {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "skill_name and skill_desc are required when no file uploaded"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理 skillName
|
||||||
|
skillName = filepath.Base(skillName)
|
||||||
|
skillName = strings.TrimSuffix(skillName, ".md")
|
||||||
|
skillName = strings.TrimSpace(skillName)
|
||||||
|
if idx := strings.LastIndexAny(skillName, "/\\"); idx >= 0 {
|
||||||
|
skillName = skillName[idx+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
skillPath = filepath.Join(projectRoot, "core", "agents", "skills", skillDir, skillName)
|
||||||
|
if err := os.MkdirAll(skillPath, 0755); err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create skill directory: " + err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
defaultContent := "---\nname: " + skillName + "\ndescription: " + skillDesc + "\n---\n\n# " + skillName + "\n\n" + skillDesc
|
defaultContent := "---\nname: " + skillName + "\ndescription: " + skillDesc + "\n---\n\n# " + skillName + "\n\n" + skillDesc
|
||||||
skillFilePath := filepath.Join(skillPath, "SKILL.md")
|
skillFilePath := filepath.Join(skillPath, "SKILL.md")
|
||||||
if err := os.WriteFile(skillFilePath, []byte(defaultContent), 0644); err != nil {
|
if err := os.WriteFile(skillFilePath, []byte(defaultContent), 0644); err != nil {
|
||||||
@@ -196,6 +261,45 @@ func (h *SkillHandler) Create(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, gin.H{"message": "skill created", "skill": skill})
|
c.JSON(http.StatusOK, gin.H{"message": "skill created", "skill": skill})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseSkillMeta 解析 SKILL.md 内容,提取 name 和 description
|
||||||
|
func parseSkillMeta(content string) (name string, description string) {
|
||||||
|
contentStr := strings.TrimSpace(content)
|
||||||
|
if !strings.HasPrefix(contentStr, "---") {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到第二个 ---
|
||||||
|
lines := strings.Split(contentStr, "\n")
|
||||||
|
var endIdx int
|
||||||
|
for i := 1; i < len(lines); i++ {
|
||||||
|
if strings.TrimSpace(lines[i]) == "---" {
|
||||||
|
endIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if endIdx == 0 {
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取 YAML 内容
|
||||||
|
yamlContent := strings.Join(lines[1:endIdx], "\n")
|
||||||
|
|
||||||
|
// 解析 name
|
||||||
|
nameMatch := regexp.MustCompile(`name:\s*(.+)`).FindStringSubmatch(yamlContent)
|
||||||
|
if len(nameMatch) > 1 {
|
||||||
|
name = strings.TrimSpace(nameMatch[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析 description
|
||||||
|
descMatch := regexp.MustCompile(`description:\s*(.+)`).FindStringSubmatch(yamlContent)
|
||||||
|
if len(descMatch) > 1 {
|
||||||
|
description = strings.TrimSpace(descMatch[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
return name, description
|
||||||
|
}
|
||||||
|
|
||||||
// getProjectRoot 获取项目根目录
|
// getProjectRoot 获取项目根目录
|
||||||
func (h *SkillHandler) getProjectRoot() string {
|
func (h *SkillHandler) getProjectRoot() string {
|
||||||
execPath, _ := os.Getwd()
|
execPath, _ := os.Getwd()
|
||||||
@@ -262,11 +366,28 @@ func (h *SkillHandler) Update(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
skillName := c.PostForm("skill_name")
|
// 支持 JSON 格式的请求
|
||||||
skillDesc := c.PostForm("skill_desc")
|
var req struct {
|
||||||
skillType := c.PostForm("skill_type")
|
SkillName string `json:"skill_name"`
|
||||||
|
SkillDesc string `json:"skill_desc"`
|
||||||
|
SkillType string `json:"skill_type"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试解析 JSON,如果失败则用 PostForm
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
req.SkillName = c.PostForm("skill_name")
|
||||||
|
req.SkillDesc = c.PostForm("skill_desc")
|
||||||
|
req.SkillType = c.PostForm("skill_type")
|
||||||
|
req.Status = c.PostForm("status")
|
||||||
|
}
|
||||||
|
|
||||||
// 如果没有传则使用现有值
|
// 如果没有传则使用现有值
|
||||||
|
skillName := req.SkillName
|
||||||
|
skillDesc := req.SkillDesc
|
||||||
|
skillType := req.SkillType
|
||||||
|
status := req.Status
|
||||||
|
|
||||||
if skillName == "" {
|
if skillName == "" {
|
||||||
skillName = existingSkill.SkillName
|
skillName = existingSkill.SkillName
|
||||||
}
|
}
|
||||||
@@ -276,6 +397,9 @@ func (h *SkillHandler) Update(c *gin.Context) {
|
|||||||
if skillType == "" {
|
if skillType == "" {
|
||||||
skillType = existingSkill.SkillType
|
skillType = existingSkill.SkillType
|
||||||
}
|
}
|
||||||
|
if status == "" {
|
||||||
|
status = existingSkill.Status
|
||||||
|
}
|
||||||
|
|
||||||
// 获取项目根目录
|
// 获取项目根目录
|
||||||
projectRoot := h.getProjectRoot()
|
projectRoot := h.getProjectRoot()
|
||||||
@@ -321,6 +445,7 @@ func (h *SkillHandler) Update(c *gin.Context) {
|
|||||||
existingSkill.SkillName = skillName
|
existingSkill.SkillName = skillName
|
||||||
existingSkill.SkillDesc = skillDesc
|
existingSkill.SkillDesc = skillDesc
|
||||||
existingSkill.SkillType = skillType
|
existingSkill.SkillType = skillType
|
||||||
|
existingSkill.Status = status
|
||||||
|
|
||||||
if err := h.skillService.UpdateSkill(existingSkill); err != nil {
|
if err := h.skillService.UpdateSkill(existingSkill); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
|||||||
@@ -279,3 +279,118 @@ func (s *AgentService) ChatStream(c interface{}, agentID int, message, sessionID
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateAgentRequest 创建智能体请求
|
||||||
|
type CreateAgentRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
SkillsMode string `json:"skills_mode"`
|
||||||
|
Skills []string `json:"skills"`
|
||||||
|
Knowledge string `json:"knowledge"`
|
||||||
|
Prompt string `json:"prompt"`
|
||||||
|
ModelProvider string `json:"model_provider"`
|
||||||
|
ModelName string `json:"model_name"`
|
||||||
|
UserID int `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAgentResponse 创建智能体响应
|
||||||
|
type CreateAgentResponse struct {
|
||||||
|
AgentID int `json:"agent_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateAgent 创建智能体
|
||||||
|
func (s *AgentService) CreateAgent(req CreateAgentRequest, userID int) (*CreateAgentResponse, error) {
|
||||||
|
url := fmt.Sprintf("%s/agent/create", s.pythonURL)
|
||||||
|
|
||||||
|
// 构建请求体
|
||||||
|
pythonReq := CreateAgentRequest{
|
||||||
|
Name: req.Name,
|
||||||
|
Description: req.Description,
|
||||||
|
Avatar: req.Avatar,
|
||||||
|
SkillsMode: req.SkillsMode,
|
||||||
|
Skills: req.Skills,
|
||||||
|
Knowledge: req.Knowledge,
|
||||||
|
Prompt: req.Prompt,
|
||||||
|
ModelProvider: req.ModelProvider,
|
||||||
|
ModelName: req.ModelName,
|
||||||
|
UserID: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(pythonReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := s.client.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to call python agent: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("python agent error: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var result CreateAgentResponse
|
||||||
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[AgentService] Agent created: %s (ID: %d)", result.Name, result.AgentID)
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAgentsResponse 获取智能体列表响应
|
||||||
|
type ListAgentsResponse struct {
|
||||||
|
Agents []interface{} `json:"agents"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAgents 获取智能体列表
|
||||||
|
func (s *AgentService) ListAgents() (*ListAgentsResponse, error) {
|
||||||
|
url := fmt.Sprintf("%s/agent/list", s.pythonURL)
|
||||||
|
|
||||||
|
httpReq, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := s.client.Do(httpReq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to call python agent: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return nil, fmt.Errorf("python agent error: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var result ListAgentsResponse
|
||||||
|
if err := json.Unmarshal(body, &result); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[AgentService] Listed agents: %d", len(result.Agents))
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user