package connectors import ( "strings" "github.com/bwmarrin/discordgo" "github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/types" "github.com/mudler/LocalAgent/pkg/xlog" ) type Discord struct { token string defaultChannel string } // NewDiscord creates a new Discord connector // with the given configuration // - token: Discord token // - defaultChannel: Discord channel to always answer even if not mentioned func NewDiscord(config map[string]string) *Discord { return &Discord{ token: config["token"], defaultChannel: config["defaultChannel"], } } func (d *Discord) AgentResultCallback() func(state types.ActionState) { return func(state types.ActionState) { // Send the result to the bot } } func (d *Discord) AgentReasoningCallback() func(state types.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool { // Send the reasoning to the bot return true } } func (d *Discord) Start(a *agent.Agent) { Token := d.token // Create a new Discord session using the provided bot token. dg, err := discordgo.New(Token) if err != nil { xlog.Info("error creating Discord session,", err) return } // Register the messageCreate func as a callback for MessageCreate events. dg.AddHandler(d.messageCreate(a)) // In this example, we only care about receiving message events. dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsDirectMessages | discordgo.IntentMessageContent // Open a websocket connection to Discord and begin listening. err = dg.Open() if err != nil { xlog.Info("error opening connection,", err) return } go func() { xlog.Info("Discord bot is now running. Press CTRL-C to exit.") <-a.Context().Done() dg.Close() xlog.Info("Discord bot is now stopped.") }() } // This function will be called (due to AddHandler above) every time a new // message is created on any channel that the authenticated bot has access to. func (d *Discord) messageCreate(a *agent.Agent) func(s *discordgo.Session, m *discordgo.MessageCreate) { return func(s *discordgo.Session, m *discordgo.MessageCreate) { // Ignore all messages created by the bot itself // This isn't required in this specific example but it's a good practice. if m.Author.ID == s.State.User.ID { return } interact := func() { //m := m.ContentWithMentionsReplaced() content := m.Content content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "") xlog.Info("Received message", "content", content) job := a.Ask( types.WithText( content, ), ) if job.Error != nil { xlog.Info("error asking agent,", job.Error) return } xlog.Info("Response", "response", job.Response) _, err := s.ChannelMessageSend(m.ChannelID, job.Response) if err != nil { xlog.Info("error sending message,", err) } } // Interact if we are mentioned for _, mention := range m.Mentions { if mention.ID == s.State.User.ID { go interact() return } } // Or we are in the default channel (if one is set!) if d.defaultChannel != "" && m.ChannelID == d.defaultChannel { go interact() return } } }