bugfix: fix duplicate Telegram message sending
Two issues caused duplicate messages to be sent to users: 1. System messages (from subagent): processSystemMessage set SendResponse:true, causing runAgentLoop to publish outbound. Then Run() also published outbound using the returned response string, resulting in two identical messages. Fix: processSystemMessage now returns empty string since runAgentLoop already handles the send. 2. Message tool double-send: When LLM called the "message" tool during processing, it published outbound immediately. Then Run() published the final response again. Fix: Track whether MessageTool sent a message in the current round (sentInRound flag, reset on each SetContext call). Run() checks HasSentInRound() before publishing to avoid duplicates.
This commit is contained in:
@@ -128,11 +128,22 @@ func (al *AgentLoop) Run(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if response != "" {
|
if response != "" {
|
||||||
al.bus.PublishOutbound(bus.OutboundMessage{
|
// Check if the message tool already sent a response during this round.
|
||||||
Channel: msg.Channel,
|
// If so, skip publishing to avoid duplicate messages to the user.
|
||||||
ChatID: msg.ChatID,
|
alreadySent := false
|
||||||
Content: response,
|
if tool, ok := al.tools.Get("message"); ok {
|
||||||
})
|
if mt, ok := tool.(*tools.MessageTool); ok {
|
||||||
|
alreadySent = mt.HasSentInRound()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alreadySent {
|
||||||
|
al.bus.PublishOutbound(bus.OutboundMessage{
|
||||||
|
Channel: msg.Channel,
|
||||||
|
ChatID: msg.ChatID,
|
||||||
|
Content: response,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,8 +229,10 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe
|
|||||||
// Use the origin session for context
|
// Use the origin session for context
|
||||||
sessionKey := fmt.Sprintf("%s:%s", originChannel, originChatID)
|
sessionKey := fmt.Sprintf("%s:%s", originChannel, originChatID)
|
||||||
|
|
||||||
// Process as system message with routing back to origin
|
// Process as system message with routing back to origin.
|
||||||
return al.runAgentLoop(ctx, processOptions{
|
// SendResponse: true means runAgentLoop will publish the outbound message itself,
|
||||||
|
// so we return empty string to prevent Run() from publishing a duplicate.
|
||||||
|
_, err := al.runAgentLoop(ctx, processOptions{
|
||||||
SessionKey: sessionKey,
|
SessionKey: sessionKey,
|
||||||
Channel: originChannel,
|
Channel: originChannel,
|
||||||
ChatID: originChatID,
|
ChatID: originChatID,
|
||||||
@@ -228,6 +241,8 @@ func (al *AgentLoop) processSystemMessage(ctx context.Context, msg bus.InboundMe
|
|||||||
EnableSummary: false,
|
EnableSummary: false,
|
||||||
SendResponse: true, // Send response back to original channel
|
SendResponse: true, // Send response back to original channel
|
||||||
})
|
})
|
||||||
|
// Return empty string: response was already sent via bus in runAgentLoop
|
||||||
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// runAgentLoop is the core message processing logic.
|
// runAgentLoop is the core message processing logic.
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type MessageTool struct {
|
|||||||
sendCallback SendCallback
|
sendCallback SendCallback
|
||||||
defaultChannel string
|
defaultChannel string
|
||||||
defaultChatID string
|
defaultChatID string
|
||||||
|
sentInRound bool // Tracks whether a message was sent in the current processing round
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageTool() *MessageTool {
|
func NewMessageTool() *MessageTool {
|
||||||
@@ -49,6 +50,12 @@ func (t *MessageTool) Parameters() map[string]interface{} {
|
|||||||
func (t *MessageTool) SetContext(channel, chatID string) {
|
func (t *MessageTool) SetContext(channel, chatID string) {
|
||||||
t.defaultChannel = channel
|
t.defaultChannel = channel
|
||||||
t.defaultChatID = chatID
|
t.defaultChatID = chatID
|
||||||
|
t.sentInRound = false // Reset send tracking for new processing round
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSentInRound returns true if the message tool sent a message during the current round.
|
||||||
|
func (t *MessageTool) HasSentInRound() bool {
|
||||||
|
return t.sentInRound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *MessageTool) SetSendCallback(callback SendCallback) {
|
func (t *MessageTool) SetSendCallback(callback SendCallback) {
|
||||||
@@ -83,5 +90,6 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]interface{})
|
|||||||
return fmt.Sprintf("Error sending message: %v", err), nil
|
return fmt.Sprintf("Error sending message: %v", err), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.sentInRound = true
|
||||||
return fmt.Sprintf("Message sent to %s:%s", channel, chatID), nil
|
return fmt.Sprintf("Message sent to %s:%s", channel, chatID), nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user