Enha: change textview chat history based on current user persona

This commit is contained in:
Grail Finder
2026-01-17 11:42:35 +03:00
parent 12be603690
commit 8b162ef34f
7 changed files with 41 additions and 31 deletions

15
bot.go
View File

@@ -153,7 +153,8 @@ func filterMessagesForCharacter(messages []models.RoleMsg, character string) []m
return messages
}
filtered := make([]models.RoleMsg, 0, len(messages))
for _, msg := range messages {
for i, msg := range messages {
logger.Info("filtering messages", "character", character, "index", i, "known_to", msg.KnownTo)
// If KnownTo is nil or empty, message is visible to all
if len(msg.KnownTo) == 0 {
filtered = append(filtered, msg)
@@ -1003,9 +1004,9 @@ func findCall(msg, toolCall string, tv *tview.TextView) {
chatRound("", cfg.AssistantRole, tv, false, false)
}
func chatToTextSlice(showSys bool) []string {
resp := make([]string, len(chatBody.Messages))
for i, msg := range chatBody.Messages {
func chatToTextSlice(messages []models.RoleMsg, showSys bool) []string {
resp := make([]string, len(messages))
for i, msg := range messages {
// INFO: skips system msg and tool msg
if !showSys && (msg.Role == cfg.ToolRole || msg.Role == "system") {
continue
@@ -1015,8 +1016,8 @@ func chatToTextSlice(showSys bool) []string {
return resp
}
func chatToText(showSys bool) string {
s := chatToTextSlice(showSys)
func chatToText(messages []models.RoleMsg, showSys bool) string {
s := chatToTextSlice(messages, showSys)
return strings.Join(s, "\n")
}
@@ -1140,7 +1141,7 @@ func summarizeAndStartNewChat() {
}
chatBody.Messages = append(chatBody.Messages, toolMsg)
// Update UI
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
// Update storage
if err := updateStorageChat(activeChatName, chatBody.Messages); err != nil {

View File

@@ -34,3 +34,6 @@ Again, this is not going to work with openais /v1/chat endpoint since it convert
alternative approach to the tag string would be to have a judge agent to determine after each message what characters should hae access to it. but it means to make an additional call to llm after each msg.
need to update character card loader to support multiple characters

View File

@@ -109,7 +109,7 @@ func startNewChat() {
}
// set chat body
chatBody.Messages = chatBody.Messages[:2]
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
newChat := &models.Chat{
ID: id + 1,
Name: fmt.Sprintf("%d_%s", id+1, cfg.AssistantRole),

1
llm.go
View File

@@ -180,7 +180,6 @@ func (lcp LCPCompletion) FormMsg(msg, role string, resume bool) (io.Reader, erro
}
prompt = sb.String()
}
logger.Debug("checking prompt for /completion", "tool_use", cfg.ToolUse,
"msg", msg, "resume", resume, "prompt", prompt, "multimodal_data_count", len(multimodalData))
payload := models.NewLCPReq(prompt, chatBody.Model, multimodalData, defaultLCPProps, chatBody.MakeStopSlice())

View File

@@ -119,7 +119,7 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
return
}
chatBody.Messages = history
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
activeChatName = selectedChat
pages.RemovePage(historyPage)
return
@@ -142,7 +142,7 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
}
// load last chat
chatBody.Messages = loadOldChatOrGetNew()
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
pages.RemovePage(historyPage)
return
case "update card":
@@ -175,7 +175,7 @@ func makeChatTable(chatMap map[string]models.Chat) *tview.Table {
case "move sysprompt onto 1st msg":
chatBody.Messages[1].Content = chatBody.Messages[0].Content + chatBody.Messages[1].Content
chatBody.Messages[0].Content = rpDefenitionSysMsg
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
activeChatName = selectedChat
pages.RemovePage(historyPage)
return
@@ -546,7 +546,7 @@ func makeAgentTable(agentList []string) *tview.Table {
return
}
// replace textview
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
updateStatusLine()
// sysModal.ClearButtons()
@@ -715,7 +715,7 @@ func makeImportChatTable(filenames []string) *tview.Table {
colorText()
updateStatusLine()
// redraw the text in text area
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
pages.RemovePage(historyPage)
app.SetFocus(textArea)
return

View File

@@ -24,7 +24,7 @@ var (
starRE = regexp.MustCompile(`(\*.*?\*)`)
thinkRE = regexp.MustCompile(`(<think>\s*([\s\S]*?)</think>)`)
codeBlockRE = regexp.MustCompile(`(?s)\x60{3}(?:.*?)\n(.*?)\n\s*\x60{3}\s*`)
singleBacktickRE = regexp.MustCompile(`\x60([^\x60]*)\x60`)
singleBacktickRE = regexp.MustCompile(`\x60([^\x60]*)\x60`)
roleRE = regexp.MustCompile(`^(\w+):`)
rpDefenitionSysMsg = `
For this roleplay immersion is at most importance.
@@ -945,7 +945,7 @@ func summarizeChat(args map[string]string) []byte {
return []byte("No chat history to summarize.")
}
// Format chat history for the agent
chatText := chatToText(true) // include system and tool messages
chatText := chatToText(chatBody.Messages, true) // include system and tool messages
return []byte(chatText)
}

37
tui.go
View File

@@ -310,7 +310,7 @@ func performSearch(term string) {
searchResultLengths = nil
originalTextForSearch = ""
// Re-render text without highlights
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
return
}
@@ -517,8 +517,8 @@ func init() {
searchResults = nil // Clear search results
searchResultLengths = nil // Clear search result lengths
originalTextForSearch = ""
textView.SetText(chatToText(cfg.ShowSys)) // Reset text without search regions
colorText() // Apply normal chat coloring
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys)) // Reset text without search regions
colorText() // Apply normal chat coloring
} else {
// Original logic if no search is active
currentSelection := textView.GetHighlights()
@@ -594,7 +594,7 @@ func init() {
}
chatBody.Messages[selectedIndex].Content = editedMsg
// change textarea
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
pages.RemovePage(editMsgPage)
editMode = false
return nil
@@ -627,7 +627,7 @@ func init() {
}
if selectedIndex >= 0 && selectedIndex < len(chatBody.Messages) {
chatBody.Messages[selectedIndex].Role = newRole
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
pages.RemovePage(roleEditPage)
}
@@ -739,7 +739,7 @@ func init() {
searchResults = nil
searchResultLengths = nil
originalTextForSearch = ""
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
return
} else {
@@ -787,7 +787,7 @@ func init() {
//
textArea.SetMovedFunc(updateStatusLine)
updateStatusLine()
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
if scrollToEndEnabled {
textView.ScrollToEnd()
@@ -801,7 +801,7 @@ func init() {
if event.Key() == tcell.KeyRune && event.Rune() == '5' && event.Modifiers()&tcell.ModAlt != 0 {
// switch cfg.ShowSys
cfg.ShowSys = !cfg.ShowSys
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
}
if event.Key() == tcell.KeyRune && event.Rune() == '3' && event.Modifiers()&tcell.ModAlt != 0 {
@@ -866,7 +866,7 @@ func init() {
chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
// there is no case where user msg is regenerated
// lastRole := chatBody.Messages[len(chatBody.Messages)-1].Role
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
go chatRound("", cfg.UserRole, textView, true, false)
return nil
}
@@ -888,7 +888,7 @@ func init() {
return nil
}
chatBody.Messages = chatBody.Messages[:len(chatBody.Messages)-1]
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
return nil
}
@@ -1052,7 +1052,7 @@ func init() {
// clear context
// remove tools and thinking
removeThinking(chatBody)
textView.SetText(chatToText(cfg.ShowSys))
textView.SetText(chatToText(chatBody.Messages, cfg.ShowSys))
colorText()
return nil
}
@@ -1184,20 +1184,26 @@ func init() {
if strings.EqualFold(role, persona) {
if i == len(roles)-1 {
cfg.WriteNextMsgAs = roles[0] // reached last, get first
persona = cfg.WriteNextMsgAs
break
}
cfg.WriteNextMsgAs = roles[i+1] // get next role
persona = cfg.WriteNextMsgAs
logger.Info("picked role", "roles", roles, "index", i+1)
break
}
}
// role got switch, update textview with character specific context for user
filtered := filterMessagesForCharacter(chatBody.Messages, persona)
textView.SetText(chatToText(filtered, cfg.ShowSys))
updateStatusLine()
colorText()
return nil
}
if event.Key() == tcell.KeyCtrlX {
persona := cfg.AssistantRole
botPersona := cfg.AssistantRole
if cfg.WriteNextMsgAsCompletionAgent != "" {
persona = cfg.WriteNextMsgAsCompletionAgent
botPersona = cfg.WriteNextMsgAsCompletionAgent
}
roles := chatBody.ListRoles()
if len(roles) == 0 {
@@ -1207,12 +1213,14 @@ func init() {
roles = append(roles, cfg.AssistantRole)
}
for i, role := range roles {
if strings.EqualFold(role, persona) {
if strings.EqualFold(role, botPersona) {
if i == len(roles)-1 {
cfg.WriteNextMsgAsCompletionAgent = roles[0] // reached last, get first
botPersona = cfg.WriteNextMsgAsCompletionAgent
break
}
cfg.WriteNextMsgAsCompletionAgent = roles[i+1] // get next role
botPersona = cfg.WriteNextMsgAsCompletionAgent
logger.Info("picked role", "roles", roles, "index", i+1)
break
}
@@ -1295,7 +1303,6 @@ func init() {
// cannot send msg in editMode or botRespMode
if event.Key() == tcell.KeyEscape && !editMode && !botRespMode {
msgText := textArea.GetText()
// TODO: add shellmode command -> output to the chat history, or at least have an option
if shellMode && msgText != "" {
// In shell mode, execute command instead of sending to LLM
executeCommandAndDisplay(msgText)