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.
96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
type SendCallback func(channel, chatID, content string) error
|
|
|
|
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 {
|
|
return &MessageTool{}
|
|
}
|
|
|
|
func (t *MessageTool) Name() string {
|
|
return "message"
|
|
}
|
|
|
|
func (t *MessageTool) Description() string {
|
|
return "Send a message to user on a chat channel. Use this when you want to communicate something."
|
|
}
|
|
|
|
func (t *MessageTool) Parameters() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"content": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "The message content to send",
|
|
},
|
|
"channel": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "Optional: target channel (telegram, whatsapp, etc.)",
|
|
},
|
|
"chat_id": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "Optional: target chat/user ID",
|
|
},
|
|
},
|
|
"required": []string{"content"},
|
|
}
|
|
}
|
|
|
|
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) {
|
|
t.sendCallback = callback
|
|
}
|
|
|
|
func (t *MessageTool) Execute(ctx context.Context, args map[string]interface{}) (string, error) {
|
|
content, ok := args["content"].(string)
|
|
if !ok {
|
|
return "", fmt.Errorf("content is required")
|
|
}
|
|
|
|
channel, _ := args["channel"].(string)
|
|
chatID, _ := args["chat_id"].(string)
|
|
|
|
if channel == "" {
|
|
channel = t.defaultChannel
|
|
}
|
|
if chatID == "" {
|
|
chatID = t.defaultChatID
|
|
}
|
|
|
|
if channel == "" || chatID == "" {
|
|
return "Error: No target channel/chat specified", nil
|
|
}
|
|
|
|
if t.sendCallback == nil {
|
|
return "Error: Message sending not configured", nil
|
|
}
|
|
|
|
if err := t.sendCallback(channel, chatID, content); 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
|
|
}
|