mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-27 13:23:10 +02:00
152 lines
5.1 KiB
Go
152 lines
5.1 KiB
Go
package handler
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"cyberstrike-ai/internal/agent"
|
||
"cyberstrike-ai/internal/audit"
|
||
"cyberstrike-ai/internal/database"
|
||
"cyberstrike-ai/internal/mcp/builtin"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// multiAgentPrepared 多代理请求在调用 Eino 前的会话与消息准备结果。
|
||
type multiAgentPrepared struct {
|
||
ConversationID string
|
||
CreatedNew bool
|
||
History []agent.ChatMessage
|
||
FinalMessage string
|
||
RoleTools []string
|
||
AssistantMessageID string
|
||
UserMessageID string
|
||
}
|
||
|
||
func (h *AgentHandler) prepareMultiAgentSession(req *ChatRequest, c *gin.Context, source string) (*multiAgentPrepared, error) {
|
||
if len(req.Attachments) > maxAttachments {
|
||
return nil, fmt.Errorf("附件最多 %d 个", maxAttachments)
|
||
}
|
||
|
||
conversationID := strings.TrimSpace(req.ConversationID)
|
||
createdNew := false
|
||
if conversationID == "" {
|
||
title := safeTruncateString(req.Message, 50)
|
||
var conv *database.Conversation
|
||
var err error
|
||
meta := audit.ConversationCreateMetaFromGin(c, source)
|
||
meta.ProjectID = effectiveProjectID(h.config, req.ProjectID)
|
||
if strings.TrimSpace(req.WebShellConnectionID) != "" {
|
||
meta.Source = source + "_webshell"
|
||
meta.WebShellConnectionID = strings.TrimSpace(req.WebShellConnectionID)
|
||
conv, err = h.db.CreateConversationWithWebshell(meta.WebShellConnectionID, title, meta)
|
||
} else {
|
||
conv, err = h.db.CreateConversation(title, meta)
|
||
}
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建对话失败: %w", err)
|
||
}
|
||
conversationID = conv.ID
|
||
createdNew = true
|
||
} else {
|
||
if _, err := h.db.GetConversation(conversationID); err != nil {
|
||
return nil, fmt.Errorf("对话不存在")
|
||
}
|
||
}
|
||
|
||
agentHistoryMessages, err := h.loadHistoryFromAgentTrace(conversationID)
|
||
if err != nil {
|
||
historyMessages, getErr := h.db.GetMessages(conversationID)
|
||
if getErr != nil {
|
||
agentHistoryMessages = []agent.ChatMessage{}
|
||
} else {
|
||
agentHistoryMessages = dbMessagesToAgentChatMessages(historyMessages)
|
||
}
|
||
}
|
||
|
||
finalMessage := req.Message
|
||
var roleTools []string
|
||
if req.WebShellConnectionID != "" {
|
||
conn, errConn := h.db.GetWebshellConnection(strings.TrimSpace(req.WebShellConnectionID))
|
||
if errConn != nil || conn == nil {
|
||
h.logger.Warn("WebShell AI 助手:未找到连接", zap.String("id", req.WebShellConnectionID), zap.Error(errConn))
|
||
return nil, fmt.Errorf("未找到该 WebShell 连接")
|
||
}
|
||
webshellContext := BuildWebshellAssistantContext(conn, WebshellSkillHintMultiAgent, req.Message)
|
||
// WebShell 模式下如果同时指定了角色,追加角色 user_prompt(工具集仍仅限 webshell 专用工具)
|
||
if req.Role != "" && req.Role != "默认" && h.config != nil && h.config.Roles != nil {
|
||
if role, exists := h.config.Roles[req.Role]; exists && role.Enabled && role.UserPrompt != "" {
|
||
finalMessage = role.UserPrompt + "\n\n" + webshellContext
|
||
h.logger.Info("WebShell + 角色: 应用角色提示词(多代理)", zap.String("role", req.Role))
|
||
} else {
|
||
finalMessage = webshellContext
|
||
}
|
||
} else {
|
||
finalMessage = webshellContext
|
||
}
|
||
roleTools = []string{
|
||
builtin.ToolWebshellExec,
|
||
builtin.ToolWebshellFileList,
|
||
builtin.ToolWebshellFileRead,
|
||
builtin.ToolWebshellFileWrite,
|
||
builtin.ToolRecordVulnerability,
|
||
builtin.ToolListVulnerabilities,
|
||
builtin.ToolGetVulnerability,
|
||
builtin.ToolUpsertProjectFact,
|
||
builtin.ToolGetProjectFact,
|
||
builtin.ToolListProjectFacts,
|
||
builtin.ToolSearchProjectFacts,
|
||
builtin.ToolDeprecateProjectFact,
|
||
builtin.ToolListKnowledgeRiskTypes,
|
||
builtin.ToolSearchKnowledgeBase,
|
||
}
|
||
} else if req.Role != "" && req.Role != "默认" && h.config != nil && h.config.Roles != nil {
|
||
if role, exists := h.config.Roles[req.Role]; exists && role.Enabled {
|
||
if role.UserPrompt != "" {
|
||
finalMessage = role.UserPrompt + "\n\n" + req.Message
|
||
}
|
||
roleTools = role.Tools
|
||
}
|
||
}
|
||
|
||
var savedPaths []string
|
||
if len(req.Attachments) > 0 {
|
||
var aerr error
|
||
savedPaths, aerr = saveAttachmentsToDateAndConversationDir(req.Attachments, conversationID, h.logger)
|
||
if aerr != nil {
|
||
return nil, fmt.Errorf("保存上传文件失败: %w", aerr)
|
||
}
|
||
}
|
||
finalMessage = appendAttachmentsToMessage(finalMessage, req.Attachments, savedPaths)
|
||
|
||
userContent := userMessageContentForStorage(req.Message, req.Attachments, savedPaths)
|
||
userMsgRow, uerr := h.db.AddMessage(conversationID, "user", userContent, nil)
|
||
if uerr != nil {
|
||
h.logger.Error("保存用户消息失败", zap.Error(uerr))
|
||
return nil, fmt.Errorf("保存用户消息失败: %w", uerr)
|
||
}
|
||
userMessageID := ""
|
||
if userMsgRow != nil {
|
||
userMessageID = userMsgRow.ID
|
||
}
|
||
|
||
assistantMsg, aerr := h.db.AddMessage(conversationID, "assistant", "处理中...", nil)
|
||
var assistantMessageID string
|
||
if aerr != nil {
|
||
h.logger.Warn("创建助手消息占位失败", zap.Error(aerr))
|
||
} else if assistantMsg != nil {
|
||
assistantMessageID = assistantMsg.ID
|
||
}
|
||
|
||
return &multiAgentPrepared{
|
||
ConversationID: conversationID,
|
||
CreatedNew: createdNew,
|
||
History: agentHistoryMessages,
|
||
FinalMessage: finalMessage,
|
||
RoleTools: roleTools,
|
||
AssistantMessageID: assistantMessageID,
|
||
UserMessageID: userMessageID,
|
||
}, nil
|
||
}
|