From 5fb488ca3171de6fb9033ccbd8b535a4801e1162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=92=E6=9F=A0?= <865274218@qq.com> Date: Tue, 10 Mar 2026 20:27:14 +0800 Subject: [PATCH] fix(agent): skip final reply only when message tool sent to same chat When the message tool sends to a different chat_id (e.g. a newly created Feishu group), the final reply to the original chat was incorrectly suppressed. Track the target chat_id in MessageTool and only skip the outbound reply when it matches the inbound message's chat_id. --- pkg/agent/loop.go | 6 ++++-- pkg/tools/message.go | 11 ++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 3d13071c0..1df72fb07 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -336,15 +336,17 @@ func (al *AgentLoop) Run(ctx context.Context) error { } if response != "" { - // Check if the message tool already sent a response during this round. + // Check if the message tool already sent a response to the SAME chat during this round. // If so, skip publishing to avoid duplicate messages to the user. + // Only skip when the target chat_id matches — sending to a different chat + // (e.g. a newly created group) should not suppress the reply to the original chat. // Use default agent's tools to check (message tool is shared). alreadySent := false defaultAgent := al.registry.GetDefaultAgent() if defaultAgent != nil { if tool, ok := defaultAgent.Tools.Get("message"); ok { if mt, ok := tool.(*tools.MessageTool); ok { - alreadySent = mt.HasSentInRound() + alreadySent = mt.HasSentInRound() && mt.SentToChatID() == msg.ChatID } } } diff --git a/pkg/tools/message.go b/pkg/tools/message.go index 438ceeddd..259c0cca7 100644 --- a/pkg/tools/message.go +++ b/pkg/tools/message.go @@ -10,7 +10,8 @@ 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 + 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 } func NewMessageTool() *MessageTool { @@ -50,6 +51,7 @@ 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("") } // HasSentInRound returns true if the message tool sent a message during the current round. @@ -57,6 +59,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 +} + func (t *MessageTool) SetSendCallback(callback SendCallback) { t.sendCallback = callback } @@ -94,6 +102,7 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]any) *ToolRes } t.sentInRound.Store(true) + t.sentChatID.Store(chatID) // Silent: user already received the message directly return &ToolResult{ ForLLM: fmt.Sprintf("Message sent to %s:%s", channel, chatID),