feat(agent): shared state, allow to track conversations globally (#148)

* feat(agent): shared state, allow to track conversations globally

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Cleanup

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* track conversations initiated by the bot

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

---------

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto
2025-05-11 22:23:01 +02:00
committed by GitHub
parent 2b07dd79ec
commit c23e655f44
63 changed files with 290 additions and 316 deletions

View File

@@ -8,7 +8,6 @@ import (
"os"
"strings"
"sync"
"time"
"github.com/mudler/LocalAGI/pkg/config"
"github.com/mudler/LocalAGI/pkg/localoperator"
@@ -42,27 +41,19 @@ type Slack struct {
// Track active jobs for cancellation
activeJobs map[string][]*types.Job // map[channelID]bool to track if a channel has active processing
activeJobsMutex sync.RWMutex
conversationTracker *ConversationTracker[string]
}
const thinkingMessage = ":hourglass: thinking..."
func NewSlack(config map[string]string) *Slack {
duration, err := time.ParseDuration(config["lastMessageDuration"])
if err != nil {
duration = 5 * time.Minute
}
return &Slack{
appToken: config["appToken"],
botToken: config["botToken"],
channelID: config["channelID"],
channelMode: config["channelMode"] == "true",
conversationTracker: NewConversationTracker[string](duration),
placeholders: make(map[string]string),
activeJobs: make(map[string][]*types.Job),
appToken: config["appToken"],
botToken: config["botToken"],
channelID: config["channelID"],
channelMode: config["channelMode"] == "true",
placeholders: make(map[string]string),
activeJobs: make(map[string][]*types.Job),
}
}
@@ -140,16 +131,6 @@ func cleanUpUsernameFromMessage(message string, b *slack.AuthTestResponse) strin
return cleaned
}
func extractUserIDsFromMessage(message string) []string {
var userIDs []string
for _, part := range strings.Split(message, " ") {
if strings.HasPrefix(part, "<@") && strings.HasSuffix(part, ">") {
userIDs = append(userIDs, strings.TrimPrefix(strings.TrimSuffix(part, ">"), "<@"))
}
}
return userIDs
}
func replaceUserIDsWithNamesInMessage(api *slack.Client, message string) string {
for _, part := range strings.Split(message, " ") {
if strings.HasPrefix(part, "<@") && strings.HasSuffix(part, ">") {
@@ -279,7 +260,7 @@ func (t *Slack) handleChannelMessage(
// Cancel any active job for this channel before starting a new one
t.cancelActiveJobForChannel(ev.Channel)
currentConv := t.conversationTracker.GetConversation(t.channelID)
currentConv := a.SharedState().ConversationTracker.GetConversation(fmt.Sprintf("slack:%s", t.channelID))
message := replaceUserIDsWithNamesInMessage(api, cleanUpUsernameFromMessage(ev.Text, b))
@@ -323,8 +304,8 @@ func (t *Slack) handleChannelMessage(
})
}
t.conversationTracker.AddMessage(
t.channelID, currentConv[len(currentConv)-1],
a.SharedState().ConversationTracker.AddMessage(
fmt.Sprintf("slack:%s", t.channelID), currentConv[len(currentConv)-1],
)
agentOptions = append(agentOptions, types.WithConversationHistory(currentConv))
@@ -370,14 +351,14 @@ func (t *Slack) handleChannelMessage(
return
}
t.conversationTracker.AddMessage(
t.channelID, openai.ChatCompletionMessage{
a.SharedState().ConversationTracker.AddMessage(
fmt.Sprintf("slack:%s", t.channelID), openai.ChatCompletionMessage{
Role: "assistant",
Content: res.Response,
},
)
xlog.Debug("After adding message to conversation tracker", "conversation", t.conversationTracker.GetConversation(t.channelID))
xlog.Debug("After adding message to conversation tracker", "conversation", a.SharedState().ConversationTracker.GetConversation(fmt.Sprintf("slack:%s", t.channelID)))
//res.Response = githubmarkdownconvertergo.Slack(res.Response)
@@ -752,6 +733,13 @@ func (t *Slack) Start(a *agent.Agent) {
if err != nil {
xlog.Error(fmt.Sprintf("Error posting message: %v", err))
}
a.SharedState().ConversationTracker.AddMessage(
fmt.Sprintf("slack:%s", t.channelID),
openai.ChatCompletionMessage{
Content: ccm.Content,
Role: "assistant",
},
)
})
}
@@ -835,11 +823,5 @@ func SlackConfigMeta() []config.Field {
Label: "Always Reply",
Type: config.FieldTypeCheckbox,
},
{
Name: "lastMessageDuration",
Label: "Last Message Duration",
Type: config.FieldTypeText,
DefaultValue: "5m",
},
}
}