mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-22 09:58:06 +00:00
feat: webui 消息重放双重防护(client_msg_id 去重 + agent 内容级去重)
回应群聊 08-19 消息轰炸诊断(GUI SSE 重连导致消息重放):
1. webui 层 client_msg_id 单飞去重(与 GUI c29abe9 配套):
- /api/v1/chat 解析 client_msg_id, 同 ID 重放等待首次结果直接复用
- 响应带 deduplicated=true 标记; 无 ID 旧客户端完全兼容
- FIFO 缓存上限 256 条防泄漏
2. agent 核心层内容级短窗口去重(兜底无 ID 客户端):
- isDuplicateInput: source+content 为 key, 10s 窗口内重复丢弃
- 持续轰炸时刷新时间戳保持拦截; 过期项自动清理
测试: webui 去重三场景 + agent 核心去重行为验证, 全项目 go test 通过
This commit is contained in:
@ -111,6 +111,11 @@ type Agent struct {
|
||||
noMergeMarkers map[string]int
|
||||
noMergeMu sync.Mutex
|
||||
|
||||
// 输入去重:防 webui/GUI 断线重连导致的消息重放
|
||||
// key=source+"|"+content, value=上次接收时间;短窗口内同内容丢弃
|
||||
lastInput map[string]time.Time
|
||||
lastInputMu sync.Mutex
|
||||
|
||||
// 词嵌入模型,用于实体语义相似度计算
|
||||
embedder *memory.StaticEmbedder
|
||||
}
|
||||
@ -221,6 +226,7 @@ func New(cfg AgentConfig) *Agent {
|
||||
inputCfg: cfg.InputProcessing,
|
||||
embedder: embedder,
|
||||
noMergeMarkers: make(map[string]int),
|
||||
lastInput: make(map[string]time.Time),
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +246,34 @@ func (a *Agent) Stop() {
|
||||
|
||||
func (a *Agent) ID() types.AgentID { return a.id }
|
||||
|
||||
// isDuplicateInput 判断是否为短窗口内的重复输入(防 webui/GUI 断线重连消息重放)。
|
||||
// key=source+"|"+content;窗口内重复返回 true 并刷新时间戳(持续轰炸时保持拦截)。
|
||||
const duplicateInputWindow = 10 * time.Second
|
||||
|
||||
func (a *Agent) isDuplicateInput(source, content string) bool {
|
||||
a.lastInputMu.Lock()
|
||||
defer a.lastInputMu.Unlock()
|
||||
now := time.Now()
|
||||
key := source + "|" + content
|
||||
if last, ok := a.lastInput[key]; ok && now.Sub(last) < duplicateInputWindow {
|
||||
a.lastInput[key] = now
|
||||
return true
|
||||
}
|
||||
a.lastInput[key] = now
|
||||
// 顺带清理过期项,防止 map 无限增长
|
||||
for k, t := range a.lastInput {
|
||||
if now.Sub(t) > duplicateInputWindow {
|
||||
delete(a.lastInput, k)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDuplicateInput 导出包装,供测试验证去重行为。
|
||||
func (a *Agent) IsDuplicateInput(source, content string) bool {
|
||||
return a.isDuplicateInput(source, content)
|
||||
}
|
||||
|
||||
// SelfInputChan 返回自循环输入通道(只读,供内部测试验证)
|
||||
func (a *Agent) SelfInputChan() <-chan string {
|
||||
return a.selfInputCh
|
||||
|
||||
Reference in New Issue
Block a user