mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-05-07 01:56:40 +02:00
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package multiagent
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"cyberstrike-ai/internal/agent"
|
|
)
|
|
|
|
const defaultSubAgentUserContextMaxRunes = 2000
|
|
|
|
// buildUserContextForSubAgent collects all user messages from conversation
|
|
// history plus the current user message, and returns a formatted string to
|
|
// append to sub-agent instructions. This ensures sub-agents always have
|
|
// access to the full user intent (target URLs, scope, etc.) even when the
|
|
// orchestrator forgets to include them in the task description.
|
|
//
|
|
// maxRunes controls the character budget for the user-context body:
|
|
// - 0 uses defaultSubAgentUserContextMaxRunes
|
|
// - negative disables injection (returns "")
|
|
//
|
|
// When truncation is needed, the first and last user messages are each
|
|
// allocated half the budget so neither is lost entirely.
|
|
func buildUserContextForSubAgent(userMessage string, history []agent.ChatMessage, maxRunes int) string {
|
|
if maxRunes < 0 {
|
|
return ""
|
|
}
|
|
if maxRunes == 0 {
|
|
maxRunes = defaultSubAgentUserContextMaxRunes
|
|
}
|
|
|
|
var userMsgs []string
|
|
for _, h := range history {
|
|
if h.Role == "user" {
|
|
if m := strings.TrimSpace(h.Content); m != "" {
|
|
userMsgs = append(userMsgs, m)
|
|
}
|
|
}
|
|
}
|
|
if um := strings.TrimSpace(userMessage); um != "" {
|
|
if len(userMsgs) == 0 || userMsgs[len(userMsgs)-1] != um {
|
|
userMsgs = append(userMsgs, um)
|
|
}
|
|
}
|
|
if len(userMsgs) == 0 {
|
|
return ""
|
|
}
|
|
|
|
joined := strings.Join(userMsgs, "\n---\n")
|
|
|
|
if len([]rune(joined)) > maxRunes {
|
|
joined = truncateKeepFirstLast(userMsgs, maxRunes)
|
|
}
|
|
|
|
return "\n\n## 本次会话用户原始请求(自动注入,确保你了解完整上下文)\n" + joined
|
|
}
|
|
|
|
// truncateKeepFirstLast keeps the first and last user messages, giving each
|
|
// half the rune budget. The first message typically contains target info;
|
|
// the last is the current instruction.
|
|
func truncateKeepFirstLast(msgs []string, maxRunes int) string {
|
|
if len(msgs) == 1 {
|
|
return truncateRunes(msgs[0], maxRunes)
|
|
}
|
|
|
|
first := msgs[0]
|
|
last := msgs[len(msgs)-1]
|
|
sep := "\n---\n...(中间对话省略)...\n---\n"
|
|
sepLen := len([]rune(sep))
|
|
|
|
budget := maxRunes - sepLen
|
|
if budget <= 0 {
|
|
return truncateRunes(first+"\n---\n"+last, maxRunes)
|
|
}
|
|
|
|
halfBudget := budget / 2
|
|
firstTrunc := truncateRunes(first, halfBudget)
|
|
lastTrunc := truncateRunes(last, budget-len([]rune(firstTrunc)))
|
|
|
|
return firstTrunc + sep + lastTrunc
|
|
}
|
|
|
|
func truncateRunes(s string, max int) string {
|
|
rs := []rune(s)
|
|
if len(rs) <= max {
|
|
return s
|
|
}
|
|
if max <= 0 {
|
|
return ""
|
|
}
|
|
return string(rs[:max])
|
|
}
|