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:
@@ -1,7 +1,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"x-agents/server/internal/model"
|
||||
"x-agents/server/internal/repository"
|
||||
|
||||
@@ -10,21 +20,27 @@ import (
|
||||
|
||||
// 错误定义
|
||||
var (
|
||||
ErrNoAgents = errors.New("no agents provided")
|
||||
ErrNoAgents = errors.New("no agents provided")
|
||||
ErrAgentNotFound = errors.New("agent not found")
|
||||
)
|
||||
|
||||
// ChatGroupService 群聊服务
|
||||
type ChatGroupService struct {
|
||||
groupRepo *repository.ChatGroupRepository
|
||||
agentRepo *repository.AgentRepository
|
||||
groupRepo *repository.ChatGroupRepository
|
||||
agentRepo *repository.AgentRepository
|
||||
pythonURL string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
// NewChatGroupService 创建群聊服务
|
||||
func NewChatGroupService(groupRepo *repository.ChatGroupRepository, agentRepo *repository.AgentRepository) *ChatGroupService {
|
||||
func NewChatGroupService(groupRepo *repository.ChatGroupRepository, agentRepo *repository.AgentRepository, pythonURL string) *ChatGroupService {
|
||||
return &ChatGroupService{
|
||||
groupRepo: groupRepo,
|
||||
agentRepo: agentRepo,
|
||||
pythonURL: pythonURL,
|
||||
client: &http.Client{
|
||||
Timeout: 120 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,37 +124,122 @@ func (s *ChatGroupService) GroupChat(userID, message, agentIDs, sessionID string
|
||||
return nil, ErrAgentNotFound
|
||||
}
|
||||
|
||||
// 并行调用所有 Agent
|
||||
results := make(chan model.SubtaskResult, len(agents))
|
||||
for _, agent := range agents {
|
||||
go func(agentID, agentName string) {
|
||||
// TODO: 调用实际的 Agent 对话逻辑
|
||||
// 这里暂时返回模拟结果
|
||||
result := model.SubtaskResult{
|
||||
AgentID: agentID,
|
||||
AgentName: agentName,
|
||||
Reply: "Agent response placeholder",
|
||||
TokensUsed: 100,
|
||||
DurationMs: 500,
|
||||
}
|
||||
results <- result
|
||||
}(agent.ID, agent.Name)
|
||||
// 解析 userID 为整数
|
||||
userIDInt, err := strconv.Atoi(userID)
|
||||
if err != nil {
|
||||
userIDInt = 1 // 默认值
|
||||
}
|
||||
|
||||
// 收集结果
|
||||
subtaskResults := make([]model.SubtaskResult, 0, len(agents))
|
||||
for i := 0; i < len(agents); i++ {
|
||||
subtaskResults = append(subtaskResults, <-results)
|
||||
// 将 agent UUIDs 转换为整数 IDs
|
||||
memberAgentIDs := make([]int, len(agents))
|
||||
for i := range agents {
|
||||
// 使用索引+1 作为 agent ID(因为 Python 端使用整数 ID)
|
||||
memberAgentIDs[i] = i + 1
|
||||
log.Printf("[ChatGroupService] Agent: %s (ID: %s)", agents[i].Name, agents[i].ID)
|
||||
}
|
||||
|
||||
// 调用 Python TeamAgent 进行群聊
|
||||
teamReq := TeamChatRequest{
|
||||
SupervisorAgentID: 0, // 没有 supervisor,使用并行策略
|
||||
MemberAgentIDs: memberAgentIDs,
|
||||
Message: message,
|
||||
UserID: userIDInt,
|
||||
SessionID: sessionID,
|
||||
Strategy: "parallel",
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s/api/v1/agent/team/chat", s.pythonURL)
|
||||
jsonData, err := json.Marshal(teamReq)
|
||||
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 team 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 team agent error: %s", string(body))
|
||||
}
|
||||
|
||||
var teamResp TeamChatResponse
|
||||
if err := json.Unmarshal(body, &teamResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[ChatGroupService] Raw teamResp: %+v", teamResp)
|
||||
log.Printf("[ChatGroupService] SubtaskResults count: %d", len(teamResp.SubtaskResults))
|
||||
|
||||
// 转换 SubtaskResults - Python 返回格式: agent_id, status, result
|
||||
// 使用 agents 列表获取 agent 名称
|
||||
subtaskResults := make([]model.SubtaskResult, 0)
|
||||
for i, sr := range teamResp.SubtaskResults {
|
||||
srMap, ok := sr.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取 agent 名称(从已查询的 agents 列表)
|
||||
agentName := ""
|
||||
if i < len(agents) {
|
||||
agentName = agents[i].Name
|
||||
}
|
||||
|
||||
// 处理 agent_id (Python 返回 int,Go 需要 string)
|
||||
agentIDVal := srMap["agent_id"]
|
||||
var agentIDStr string
|
||||
switch v := agentIDVal.(type) {
|
||||
case float64:
|
||||
agentIDStr = fmt.Sprintf("%d", int(v))
|
||||
case string:
|
||||
agentIDStr = v
|
||||
default:
|
||||
agentIDStr = "0"
|
||||
}
|
||||
|
||||
// 如果没有从 agents 列表获取到名称,使用 agent_id
|
||||
if agentName == "" {
|
||||
agentName = agentIDStr
|
||||
}
|
||||
|
||||
// 获取 result 作为 reply
|
||||
resultVal, _ := srMap["result"]
|
||||
var reply string
|
||||
switch v := resultVal.(type) {
|
||||
case string:
|
||||
reply = v
|
||||
default:
|
||||
reply = fmt.Sprintf("%v", resultVal)
|
||||
}
|
||||
|
||||
subtaskResults = append(subtaskResults, model.SubtaskResult{
|
||||
AgentID: agentIDStr,
|
||||
AgentName: agentName,
|
||||
Reply: reply,
|
||||
TokensUsed: 0, // Python 暂时未返回
|
||||
DurationMs: 0, // Python 暂时未返回
|
||||
})
|
||||
}
|
||||
close(results)
|
||||
|
||||
// 汇总结果
|
||||
response := &model.GroupChatResponse{
|
||||
SessionID: sessionID,
|
||||
Reply: "Group chat completed",
|
||||
DurationMs: 1000,
|
||||
TokensUsed: 500,
|
||||
Strategy: "parallel",
|
||||
Reply: teamResp.Response,
|
||||
DurationMs: teamResp.DurationMs,
|
||||
Strategy: teamResp.Strategy,
|
||||
SubtaskResults: subtaskResults,
|
||||
}
|
||||
|
||||
@@ -150,8 +251,15 @@ func parseAgentIDs(agentIDs string) []string {
|
||||
if agentIDs == "" {
|
||||
return []string{}
|
||||
}
|
||||
// 简单解析,假设是 JSON 数组格式
|
||||
// 实际应该使用 json.Unmarshal
|
||||
// 这里简化处理,直接返回
|
||||
// 尝试解析 JSON 数组格式
|
||||
var ids []string
|
||||
if err := json.Unmarshal([]byte(agentIDs), &ids); err == nil {
|
||||
return ids
|
||||
}
|
||||
// 如果解析失败,可能是逗号分隔的字符串
|
||||
if strings.Contains(agentIDs, ",") {
|
||||
return strings.Split(agentIDs, ",")
|
||||
}
|
||||
// 简单处理,直接返回
|
||||
return []string{agentIDs}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user