From f02c3a35edb977bce4654825b350c63f97d806d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=92=E6=9F=A0?= <865274218@qq.com> Date: Wed, 11 Mar 2026 15:26:01 +0800 Subject: [PATCH] fix(tools): track all sent chat_ids to avoid missed duplicate suppression Replace single sentChatID (atomic.Value) with a set of chat_ids so that when the message tool sends to multiple chats in one round, the final reply is correctly suppressed for any chat that was already sent to. --- pkg/agent/loop.go | 2 +- pkg/tools/message.go | 28 ++++++++++++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 1df72fb07..d25afdadc 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -346,7 +346,7 @@ func (al *AgentLoop) Run(ctx context.Context) error { if defaultAgent != nil { if tool, ok := defaultAgent.Tools.Get("message"); ok { if mt, ok := tool.(*tools.MessageTool); ok { - alreadySent = mt.HasSentInRound() && mt.SentToChatID() == msg.ChatID + alreadySent = mt.HasSentInRound() && mt.HasSentToChatID(msg.ChatID) } } } diff --git a/pkg/tools/message.go b/pkg/tools/message.go index 259c0cca7..854309df0 100644 --- a/pkg/tools/message.go +++ b/pkg/tools/message.go @@ -3,6 +3,7 @@ package tools import ( "context" "fmt" + "sync" "sync/atomic" ) @@ -10,8 +11,10 @@ type SendCallback func(channel, chatID, content string) error type MessageTool struct { sendCallback SendCallback - sentInRound atomic.Bool // Tracks whether a message was sent in the current processing round - sentChatID atomic.Value // Tracks the chat_id that the message was sent to in the current round + sentInRound atomic.Bool // Tracks whether a message was sent in the current processing round + + mu sync.Mutex // protects sentChatIDs + sentChatIDs map[string]struct{} // All chat_ids the message tool sent to in the current round } func NewMessageTool() *MessageTool { @@ -51,7 +54,9 @@ func (t *MessageTool) Parameters() map[string]any { // Called by the agent loop at the start of each inbound message processing round. func (t *MessageTool) ResetSentInRound() { t.sentInRound.Store(false) - t.sentChatID.Store("") + t.mu.Lock() + t.sentChatIDs = nil + t.mu.Unlock() } // HasSentInRound returns true if the message tool sent a message during the current round. @@ -59,10 +64,12 @@ func (t *MessageTool) HasSentInRound() bool { return t.sentInRound.Load() } -// SentToChatID returns the chat_id that the message was sent to in the current round. -func (t *MessageTool) SentToChatID() string { - v, _ := t.sentChatID.Load().(string) - return v +// HasSentToChatID returns true if the message tool sent to the given chat_id in this round. +func (t *MessageTool) HasSentToChatID(chatID string) bool { + t.mu.Lock() + defer t.mu.Unlock() + _, ok := t.sentChatIDs[chatID] + return ok } func (t *MessageTool) SetSendCallback(callback SendCallback) { @@ -102,7 +109,12 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]any) *ToolRes } t.sentInRound.Store(true) - t.sentChatID.Store(chatID) + t.mu.Lock() + if t.sentChatIDs == nil { + t.sentChatIDs = make(map[string]struct{}) + } + t.sentChatIDs[chatID] = struct{}{} + t.mu.Unlock() // Silent: user already received the message directly return &ToolResult{ ForLLM: fmt.Sprintf("Message sent to %s:%s", channel, chatID),