diff --git a/internal/project/user_verbatim_anchor.go b/internal/project/user_verbatim_anchor.go deleted file mode 100644 index bed7676f..00000000 --- a/internal/project/user_verbatim_anchor.go +++ /dev/null @@ -1,170 +0,0 @@ -package project - -import ( - "fmt" - "strings" - - "cyberstrike-ai/internal/database" - - "github.com/cloudwego/eino/adk" - "github.com/cloudwego/eino/schema" -) - -const ( - // UserVerbatimSectionHeading 用户原文锚点可读标题(块内保留,供 Agent 阅读)。 - UserVerbatimSectionHeading = "## 用户历史输入(原文保留,勿省略或改写)" - - // UserVerbatimSectionStartMarker / EndMarker:HTML 注释边界,供程序化替换;对模型无指令语义。 - UserVerbatimSectionStartMarker = "" - UserVerbatimSectionEndMarker = "" -) - -// ExtractUserContentsFromMessages 按时间顺序提取 user 角色消息的原文(跳过空白)。 -func ExtractUserContentsFromMessages(msgs []database.Message) []string { - out := make([]string, 0, len(msgs)) - for i := range msgs { - if !strings.EqualFold(strings.TrimSpace(msgs[i].Role), "user") { - continue - } - content := strings.TrimSpace(msgs[i].Content) - if content == "" { - continue - } - out = append(out, content) - } - return out -} - -// BuildUserVerbatimAnchorBlockFromMessages 从 messages 表行构建用户原文锚点块。 -// maxRunes: 0 = 不截断;>0 = 总 rune 上限(仍保留每一轮,仅对超长单条做尾部截断提示)。 -func BuildUserVerbatimAnchorBlockFromMessages(msgs []database.Message, maxRunes int) string { - return BuildUserVerbatimAnchorBlock(ExtractUserContentsFromMessages(msgs), maxRunes) -} - -// BuildUserVerbatimAnchorBlock 将各轮用户原文格式化为 system prompt 锚点块。 -func BuildUserVerbatimAnchorBlock(userContents []string, maxRunes int) string { - if len(userContents) == 0 { - return "" - } - lines := make([]string, 0, len(userContents)) - for _, content := range userContents { - content = strings.TrimSpace(content) - if content == "" { - continue - } - lines = append(lines, fmt.Sprintf("[第%d轮] %s", len(lines)+1, content)) - } - if len(lines) == 0 { - return "" - } - body := strings.Join(lines, "\n") - if maxRunes > 0 { - body = capUserVerbatimBody(body, maxRunes) - } - return wrapUserVerbatimBlock(UserVerbatimSectionHeading + "\n\n" + body) -} - -func capUserVerbatimBody(body string, maxRunes int) string { - rs := []rune(body) - if len(rs) <= maxRunes { - return body - } - suffix := "\n\n...(用户原文锚点已达配置上限,更早轮次可能被截断;完整原文见 messages 表)..." - suffixRunes := []rune(suffix) - keep := maxRunes - len(suffixRunes) - if keep <= 0 { - return string(rs[:maxRunes]) - } - return string(rs[:keep]) + suffix -} - -func wrapUserVerbatimBlock(content string) string { - content = strings.TrimSpace(content) - if content == "" { - return "" - } - return UserVerbatimSectionStartMarker + "\n" + content + "\n" + UserVerbatimSectionEndMarker + "\n" -} - -// ReplaceUserVerbatimAnchorSection 用 freshBlock 替换 content 中已有的用户原文锚点段。 -func ReplaceUserVerbatimAnchorSection(content, freshBlock string) (string, bool) { - content = strings.TrimSpace(content) - freshBlock = strings.TrimSpace(freshBlock) - if freshBlock == "" { - return content, false - } - start, ok := userVerbatimSectionStart(content) - if !ok { - return content, false - } - end, ok := userVerbatimSectionEnd(content, start) - if !ok { - return content, false - } - return strings.TrimSpace(content[:start] + freshBlock + content[end:]), true -} - -func userVerbatimSectionStart(content string) (int, bool) { - idx := strings.Index(content, UserVerbatimSectionStartMarker) - if idx < 0 { - return 0, false - } - return idx, true -} - -func userVerbatimSectionEnd(content string, start int) (int, bool) { - if start < 0 || start >= len(content) { - return 0, false - } - tail := content[start:] - idx := strings.LastIndex(tail, UserVerbatimSectionEndMarker) - if idx < 0 { - return 0, false - } - return start + idx + len(UserVerbatimSectionEndMarker), true -} - -// RefreshUserVerbatimAnchorInMessages 在 summarization 等压缩后,用 freshBlock 刷新 system 中的用户原文锚点。 -// 若尚无锚点段,则追加到首条 system 消息;若无 system 消息则在开头插入一条。 -func RefreshUserVerbatimAnchorInMessages(msgs []adk.Message, freshBlock string) []adk.Message { - freshBlock = strings.TrimSpace(freshBlock) - if freshBlock == "" || len(msgs) == 0 { - return msgs - } - - out := make([]adk.Message, len(msgs)) - changed := false - for i, msg := range msgs { - if msg == nil || msg.Role != schema.System { - out[i] = msg - continue - } - newContent, ok := ReplaceUserVerbatimAnchorSection(msg.Content, freshBlock) - if !ok { - out[i] = msg - continue - } - cloned := *msg - cloned.Content = newContent - out[i] = &cloned - changed = true - } - - if changed { - return out - } - - for i, msg := range msgs { - if msg == nil || msg.Role != schema.System { - continue - } - cloned := *msg - cloned.Content = AppendSystemPromptBlock(cloned.Content, freshBlock) - out[i] = &cloned - return out - } - - prefix := make([]adk.Message, 0, len(msgs)+1) - prefix = append(prefix, schema.SystemMessage(freshBlock)) - return append(prefix, msgs...) -}