package service import ( "fmt" "sort" "ai-agent-scaffold-go/internal/model" "ai-agent-scaffold-go/pkg/types" ) // ChatService 聊天服务 type ChatService struct { registry model.AgentRegistry sessions model.SessionStore } // NewChatService 创建聊天服务 func NewChatService(registry model.AgentRegistry, sessions model.SessionStore) *ChatService { return &ChatService{registry: registry, sessions: sessions} } // QueryAgentConfigList 查询已注册的 Agent 列表 func (s *ChatService) QueryAgentConfigList() []model.AgentSummary { registered := s.registry.List() sort.Slice(registered, func(i, j int) bool { return registered[i].AgentID < registered[j].AgentID }) agents := make([]model.AgentSummary, 0, len(registered)) for _, agent := range registered { agents = append(agents, model.AgentSummary{ AgentID: agent.AgentID, AgentName: agent.AgentName, AgentDesc: agent.AgentDesc, }) } return agents } // CreateSession 为指定 Agent 和用户创建会话 func (s *ChatService) CreateSession(agentID, userID string) (string, error) { if sessionID, ok := s.sessions.Get(userID, agentID); ok { return sessionID, nil } registered, ok := s.registry.Get(agentID) if !ok || registered.Runner == nil { return "", types.NewAppError(types.CodeAgentNotFound, types.InfoAgentNotFound) } sessionID, err := registered.Runner.CreateSession(userID) if err != nil { return "", err } if err := s.sessions.Set(userID, agentID, sessionID); err != nil { return "", err } return sessionID, nil } // HandleMessage 处理同步聊天消息 func (s *ChatService) HandleMessage(agentID, userID, sessionID, message string) ([]string, error) { content := model.ChatContent{Texts: []model.TextPart{{Message: message}}} return s.handleCommand(agentID, userID, sessionID, message, content) } // HandleMessageStream 处理流式聊天消息 func (s *ChatService) HandleMessageStream(agentID, userID, sessionID, message string) (<-chan string, <-chan error) { content := model.ChatContent{Texts: []model.TextPart{{Message: message}}} return s.handleCommandStream(agentID, userID, sessionID, message, content) } func (s *ChatService) handleCommand(agentID, userID, sessionID, message string, content model.ChatContent) ([]string, error) { registered, sessionID, err := s.resolveRunnerSession(agentID, userID, sessionID, message, content) if err != nil { return nil, err } return registered.Runner.Run(userID, sessionID, content) } func (s *ChatService) handleCommandStream(agentID, userID, sessionID, message string, content model.ChatContent) (<-chan string, <-chan error) { registered, sessionID, err := s.resolveRunnerSession(agentID, userID, sessionID, message, content) if err != nil { outputs := make(chan string) errs := make(chan error, 1) errs <- err close(outputs) close(errs) return outputs, errs } return registered.Runner.Stream(userID, sessionID, content) } func (s *ChatService) resolveRunnerSession(agentID, userID, sessionID, message string, content model.ChatContent) (model.RegisteredAgent, string, error) { registered, ok := s.registry.Get(agentID) if !ok || registered.Runner == nil { return model.RegisteredAgent{}, "", types.NewAppError(types.CodeAgentNotFound, types.InfoAgentNotFound) } if sessionID == "" { var err error sessionID, err = s.CreateSession(agentID, userID) if err != nil { return model.RegisteredAgent{}, "", err } } if len(content.Texts) == 0 && message != "" { content.Texts = []model.TextPart{{Message: message}} } if len(content.Texts) == 0 { return model.RegisteredAgent{}, "", fmt.Errorf("chat content is required") } return registered, sessionID, nil }