diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 90e6659..1a63734 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -157,11 +157,22 @@ func (al *AgentLoop) Run(ctx context.Context) error { } if response != "" { - al.bus.PublishOutbound(bus.OutboundMessage{ - Channel: msg.Channel, - ChatID: msg.ChatID, - Content: response, - }) + // Check if the message tool already sent a response during this round. + // If so, skip publishing to avoid duplicate messages to the user. + alreadySent := false + 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, + }) + } } } } diff --git a/pkg/tools/message.go b/pkg/tools/message.go index 9c803ba..2801b39 100644 --- a/pkg/tools/message.go +++ b/pkg/tools/message.go @@ -11,6 +11,7 @@ type MessageTool struct { sendCallback SendCallback defaultChannel string defaultChatID string + sentInRound bool // Tracks whether a message was sent in the current processing round } func NewMessageTool() *MessageTool { @@ -49,6 +50,12 @@ func (t *MessageTool) Parameters() map[string]interface{} { func (t *MessageTool) SetContext(channel, chatID string) { t.defaultChannel = channel 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) { @@ -87,6 +94,7 @@ func (t *MessageTool) Execute(ctx context.Context, args map[string]interface{}) } } + t.sentInRound = true // Silent: user already received the message directly return &ToolResult{ ForLLM: fmt.Sprintf("Message sent to %s:%s", channel, chatID),