From e26b55a6a823467fae65e82462b0e39eb6a72490 Mon Sep 17 00:00:00 2001 From: mudler Date: Tue, 25 Mar 2025 17:58:59 +0100 Subject: [PATCH] Add tests --- core/agent/agent.go | 4 +- services/connectors/connectors_suite_test.go | 13 ++ .../connectors/conversationstracker_test.go | 111 ++++++++++++++++++ services/connectors/slack.go | 3 + services/connectors/telegram.go | 16 ++- 5 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 services/connectors/connectors_suite_test.go create mode 100644 services/connectors/conversationstracker_test.go diff --git a/core/agent/agent.go b/core/agent/agent.go index 23e208a..45c010e 100644 --- a/core/agent/agent.go +++ b/core/agent/agent.go @@ -473,6 +473,8 @@ func (a *Agent) consumeJob(job *types.Job, role string) { Role: "assistant", Content: reasoning, }) + + xlog.Debug("Finish job with reasoning", "reasoning", reasoning, "agent", a.Character.Name, "conversation", fmt.Sprintf("%+v", conv)) job.Result.Conversation = conv a.saveCurrentConversation(conv) job.Result.SetResponse(reasoning) @@ -864,7 +866,7 @@ func (a *Agent) Run() error { //todoTimer := time.NewTicker(a.options.periodicRuns) timer := time.NewTimer(a.options.periodicRuns) for { - xlog.Debug("Agent is waiting for a job", "agent", a.Character.Name) + xlog.Debug("Agent is now waiting for a new job", "agent", a.Character.Name) select { case job := <-a.jobQueue: a.loop(timer, job) diff --git a/services/connectors/connectors_suite_test.go b/services/connectors/connectors_suite_test.go new file mode 100644 index 0000000..0026378 --- /dev/null +++ b/services/connectors/connectors_suite_test.go @@ -0,0 +1,13 @@ +package connectors_test + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestConnectors(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Connectors test suite") +} diff --git a/services/connectors/conversationstracker_test.go b/services/connectors/conversationstracker_test.go new file mode 100644 index 0000000..cb75e2e --- /dev/null +++ b/services/connectors/conversationstracker_test.go @@ -0,0 +1,111 @@ +package connectors_test + +import ( + "time" + + "github.com/mudler/LocalAgent/services/connectors" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "github.com/sashabaranov/go-openai" +) + +var _ = Describe("ConversationTracker", func() { + var ( + tracker *connectors.ConversationTracker[string] + duration time.Duration + ) + + BeforeEach(func() { + duration = 1 * time.Second + tracker = connectors.NewConversationTracker[string](duration) + }) + + It("should initialize with empty conversations", func() { + Expect(tracker.GetConversation("test")).To(BeEmpty()) + }) + + It("should add a message and retrieve it", func() { + message := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello", + } + tracker.AddMessage("test", message) + conv := tracker.GetConversation("test") + Expect(conv).To(HaveLen(1)) + Expect(conv[0]).To(Equal(message)) + }) + + It("should clear the conversation after the duration", func() { + message := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello", + } + tracker.AddMessage("test", message) + time.Sleep(2 * time.Second) + conv := tracker.GetConversation("test") + Expect(conv).To(BeEmpty()) + }) + + It("should keep the conversation within the duration", func() { + message := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello", + } + tracker.AddMessage("test", message) + time.Sleep(500 * time.Millisecond) // Half the duration + conv := tracker.GetConversation("test") + Expect(conv).To(HaveLen(1)) + Expect(conv[0]).To(Equal(message)) + }) + + It("should handle multiple keys and clear old conversations", func() { + message1 := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello 1", + } + message2 := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello 2", + } + + tracker.AddMessage("key1", message1) + tracker.AddMessage("key2", message2) + + time.Sleep(2 * time.Second) + + conv1 := tracker.GetConversation("key1") + conv2 := tracker.GetConversation("key2") + + Expect(conv1).To(BeEmpty()) + Expect(conv2).To(BeEmpty()) + }) + + It("should handle different key types", func() { + trackerInt := connectors.NewConversationTracker[int](duration) + trackerInt64 := connectors.NewConversationTracker[int64](duration) + + message := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello", + } + + trackerInt.AddMessage(1, message) + trackerInt64.AddMessage(int64(1), message) + + Expect(trackerInt.GetConversation(1)).To(HaveLen(1)) + Expect(trackerInt64.GetConversation(int64(1))).To(HaveLen(1)) + }) + + It("should cleanup other conversations if older", func() { + message := openai.ChatCompletionMessage{ + Role: openai.ChatMessageRoleUser, + Content: "Hello", + } + tracker.AddMessage("key1", message) + tracker.AddMessage("key2", message) + time.Sleep(2 * time.Second) + tracker.GetConversation("key3") + Expect(tracker.GetConversation("key1")).To(BeEmpty()) + Expect(tracker.GetConversation("key2")).To(BeEmpty()) + }) +}) diff --git a/services/connectors/slack.go b/services/connectors/slack.go index c635c21..ab6cb2d 100644 --- a/services/connectors/slack.go +++ b/services/connectors/slack.go @@ -306,6 +306,8 @@ func (t *Slack) handleChannelMessage( }, ) + xlog.Debug("After adding message to conversation tracker", "conversation", t.conversationTracker.GetConversation(t.channelID)) + //res.Response = githubmarkdownconvertergo.Slack(res.Response) _, _, err = api.PostMessage(ev.Channel, @@ -574,6 +576,7 @@ func (t *Slack) handleMention( // Format the final response //finalResponse := githubmarkdownconvertergo.Slack(res.Response) finalResponse := fmt.Sprintf("@%s %s", user.Name, res.Response) + xlog.Debug("Send final response to slack", "response", finalResponse) // Update the placeholder message with the final result t.placeholderMutex.RLock() diff --git a/services/connectors/telegram.go b/services/connectors/telegram.go index b0f3e7b..0c4e91a 100644 --- a/services/connectors/telegram.go +++ b/services/connectors/telegram.go @@ -64,11 +64,15 @@ func (t *Telegram) handleUpdate(ctx context.Context, b *bot.Bot, a *agent.Agent, Role: "user", }) + xlog.Info("New message", "username", username, "conversation", currentConv) res := a.Ask( types.WithConversationHistory(currentConv), ) + xlog.Debug("Response", "response", res.Response) + if res.Response == "" { + xlog.Error("Empty response from agent") return } @@ -80,11 +84,15 @@ func (t *Telegram) handleUpdate(ctx context.Context, b *bot.Bot, a *agent.Agent, }, ) - b.SendMessage(ctx, &bot.SendMessageParams{ - ParseMode: models.ParseModeMarkdown, - ChatID: update.Message.Chat.ID, - Text: res.Response, + xlog.Debug("Sending message back to telegram", "response", res.Response) + _, err := b.SendMessage(ctx, &bot.SendMessageParams{ + // ParseMode: models.ParseModeMarkdown, + ChatID: update.Message.Chat.ID, + Text: res.Response, }) + if err != nil { + xlog.Error("Error sending message", "error", err) + } } // func (t *Telegram) handleNewMessage(ctx context.Context, b *bot.Bot, m openai.ChatCompletionMessage) {