Skip to content

Commit d01638b

Browse files
authored
Merge pull request #5 from vybraan/feat/gemini/conversation-switching
Feat/gemini/conversation switching
2 parents 7d85df2 + 3d95cf7 commit d01638b

6 files changed

Lines changed: 219 additions & 77 deletions

File tree

internal/providers/gemini/conversation_manager.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@ func (cm *ConversationManager) StartNewConversation(repo HistoryRepository) *Con
2121
cm.mu.Lock()
2222
defer cm.mu.Unlock()
2323

24-
convo := NewConversation(repo)
25-
cm.conversations[convo.ID] = convo
24+
conversation := NewConversation(repo)
25+
cm.conversations[conversation.ID] = conversation
2626

27-
cm.active = convo
28-
return convo
27+
cm.active = conversation
28+
return conversation
2929
}
3030

3131
func (cm *ConversationManager) SwitchConversation(id string) error {
3232
cm.mu.RLock()
3333
defer cm.mu.RUnlock()
3434

35-
convo, exists := cm.conversations[id]
35+
conversation, exists := cm.conversations[id]
3636
if !exists {
3737
return fmt.Errorf("conversation with ID %s does not exist", id)
3838
}
3939

40-
cm.active = convo
40+
cm.active = conversation
4141
return nil
4242
}
4343

@@ -55,9 +55,9 @@ func (cm *ConversationManager) GetConversationDescription(id string) (string, er
5555
cm.mu.RLock()
5656
defer cm.mu.RUnlock()
5757

58-
convo, exists := cm.conversations[id]
58+
conversation, exists := cm.conversations[id]
5959
if !exists {
6060
return "", fmt.Errorf("no description found for conversation %s", id)
6161
}
62-
return convo.Description, nil
62+
return conversation.Description, nil
6363
}

internal/providers/gemini/repository.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
type HistoryRepository interface {
1313
SendMessage(c context.Context, text genai.Text) (string, error)
14+
GetMessages() ([]string, error)
1415
}
1516

1617
type MemoryHistoryRepository struct {
@@ -23,6 +24,27 @@ func NewMemoryHistoryRepository(cs *genai.ChatSession) *MemoryHistoryRepository
2324
}
2425
}
2526

27+
func (mhr *MemoryHistoryRepository) GetMessages() ([]string, error) {
28+
29+
if mhr.cs == nil {
30+
return nil, errors.New("chat session is not initialized")
31+
}
32+
if len(mhr.cs.History) == 0 {
33+
return nil, errors.New("no messages in history")
34+
}
35+
36+
var messages []string
37+
for _, content := range mhr.cs.History {
38+
for _, part := range content.Parts {
39+
if text, ok := part.(genai.Text); ok {
40+
messages = append(messages, fmt.Sprintf("[Role:%s, Part:%s]", content.Role, text))
41+
}
42+
}
43+
}
44+
return messages, nil
45+
46+
}
47+
2648
func (mhr *MemoryHistoryRepository) SendMessage(c context.Context, text genai.Text) (string, error) {
2749
result, err := mhr.cs.SendMessage(c, text)
2850

internal/providers/gemini/service.go

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,10 @@ import (
44
"context"
55
"fmt"
66

7-
"github.com/charmbracelet/bubbles/list"
87
"github.com/google/generative-ai-go/genai"
98
"github.com/vybraan/vyai/internal/utils"
109
)
1110

12-
type item struct {
13-
title string
14-
desc string
15-
}
16-
17-
func NewItem(title, description string) *item {
18-
return &item{
19-
title: title,
20-
desc: description,
21-
}
22-
}
23-
24-
func (i item) Title() string { return i.title }
25-
func (i item) Description() string { return i.desc }
26-
func (i item) FilterValue() string { return i.desc }
27-
2811
type GeminiService struct {
2912
cm *ConversationManager
3013
}
@@ -42,7 +25,7 @@ func (gs *GeminiService) SetConversationDescription(c context.Context, lock_desc
4225
// this is a workaround for the fact that the does not have a Description
4326
// field in the conversation when newly created so when create a new one before
4427
// it happens give it description
45-
if gs.cm.active != nil && gs.cm.active.DescriptionLocked != true {
28+
if gs.cm.active != nil && !gs.cm.active.DescriptionLocked {
4629
desc, err := gs.SendEphemeralMessage(c, utils.DESCRIPTION_PROMPT)
4730
if err != nil {
4831
return err
@@ -54,9 +37,20 @@ func (gs *GeminiService) SetConversationDescription(c context.Context, lock_desc
5437

5538
}
5639

40+
func (gs *GeminiService) ClearConversation(c context.Context) error {
41+
_, err := gs.cm.GetActiveConversation()
42+
if err != nil {
43+
return err
44+
}
45+
46+
gs.cm.active = nil
47+
48+
return nil
49+
}
50+
5751
func (gs *GeminiService) NewConversation(c context.Context) (*Conversation, error) {
5852

59-
// Ensure the conversation has a description before the switch
53+
// Ensure the old conversation has a description before the switch
6054
if err := gs.SetConversationDescription(c, true); err != nil {
6155
return nil, err
6256
}
@@ -66,28 +60,28 @@ func (gs *GeminiService) NewConversation(c context.Context) (*Conversation, erro
6660
return nil, err
6761
}
6862
memRepo := NewMemoryHistoryRepository(cs)
69-
convo := gs.cm.StartNewConversation(memRepo)
70-
return convo, nil
63+
conversation := gs.cm.StartNewConversation(memRepo)
64+
return conversation, nil
7165
}
7266

7367
func (gs *GeminiService) SendMessage(c context.Context, message string) (string, error) {
7468

75-
convo, err := gs.cm.GetActiveConversation()
69+
conversation, err := gs.cm.GetActiveConversation()
7670
if err != nil {
77-
convo, err = gs.NewConversation(c)
71+
conversation, err = gs.NewConversation(c)
7872
if err != nil {
7973
return "", err
8074
}
8175
}
8276

83-
result, err := convo.Repo.SendMessage(c, genai.Text(message))
77+
result, err := conversation.Repo.SendMessage(c, genai.Text(message))
8478

8579
if err != nil {
8680
return "", err
8781
}
8882

8983
//Set the first time description and set it to still be able to be updated later
90-
if convo.Description == "" {
84+
if conversation.Description == "" {
9185
gs.SetConversationDescription(c, false)
9286
}
9387

@@ -96,30 +90,27 @@ func (gs *GeminiService) SendMessage(c context.Context, message string) (string,
9690

9791
func (gs *GeminiService) SendEphemeralMessage(c context.Context, message string) (string, error) {
9892

99-
convo, err := gs.cm.GetActiveConversation()
93+
conversation, err := gs.cm.GetActiveConversation()
10094
if err != nil {
10195

102-
convo, err = gs.NewConversation(c)
96+
_, err = gs.NewConversation(c)
10397
return "", err
10498
}
10599

106-
result, err := convo.Repo.SendMessage(c, genai.Text(message))
100+
result, err := conversation.Repo.SendMessage(c, genai.Text(message))
107101

108102
if err != nil {
109103
return "", err
110104
}
111105
return result, nil
112106
}
113107

114-
func (gs *GeminiService) GetAllConversations() ([]list.Item, error) {
115-
var items []list.Item
108+
func (gs *GeminiService) GetAllConversations() ([]utils.Item, error) {
109+
var items []utils.Item
116110

117111
for _, conv := range gs.cm.conversations {
118-
convoItem := item{
119-
title: conv.ID,
120-
desc: conv.Description,
121-
}
122-
items = append(items, convoItem)
112+
conversationItem := utils.NewItem(conv.ID, conv.Description)
113+
items = append(items, conversationItem)
123114
}
124115

125116
if len(items) == 0 {
@@ -128,3 +119,30 @@ func (gs *GeminiService) GetAllConversations() ([]list.Item, error) {
128119

129120
return items, nil
130121
}
122+
123+
func (gs *GeminiService) SwitchConversation(c context.Context, id string) error {
124+
125+
// Ensure the old conversation has a description before the switch
126+
if err := gs.SetConversationDescription(c, true); err != nil {
127+
return err
128+
}
129+
130+
err := gs.cm.SwitchConversation(id)
131+
if err != nil {
132+
return err
133+
}
134+
135+
// if gs.cm.active != nil {
136+
// gs.cm.active.DescriptionLocked = true
137+
// }
138+
139+
return nil
140+
}
141+
142+
func (gs *GeminiService) GetActiveConversation() (*Conversation, error) {
143+
conversation, err := gs.cm.GetActiveConversation()
144+
if err != nil {
145+
return nil, err
146+
}
147+
return conversation, nil
148+
}

0 commit comments

Comments
 (0)