summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrail Finder <wohilas@gmail.com>2026-01-17 11:42:35 +0300
committerGrail Finder <wohilas@gmail.com>2026-01-17 11:42:35 +0300
commit8b162ef34f0755e2224c43499218def16d4b6845 (patch)
tree06c5a00c1f6680fbcf50dc5519887c5ff6a6f5c5
parent12be6036902ba9fa1b403310422e5f6f3e6c1875 (diff)
Enha: change textview chat history based on current user persona
-rw-r--r--bot.go15
-rw-r--r--char-specific-context.md3
-rw-r--r--helpfuncs.go2
-rw-r--r--llm.go1
-rw-r--r--tables.go10
-rw-r--r--tools.go4
-rw-r--r--tui.go37
7 files changed, 41 insertions, 31 deletions
diff --git a/bot.go b/bot.go
index 967c060..a5d3b12 100644
--- a/bot.go
+++ b/bot.go
@@ -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 {
diff --git a/char-specific-context.md b/char-specific-context.md
index 93c08c5..c1a7bd6 100644
--- a/char-specific-context.md
+++ b/char-specific-context.md
@@ -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
diff --git a/helpfuncs.go b/helpfuncs.go
index 73f8fb0..ccb5858 100644
--- a/helpfuncs.go
+++ b/helpfuncs.go
@@ -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),
diff --git a/llm.go b/llm.go
index 5599d21..cd5a3fe 100644
--- a/llm.go
+++ b/llm.go
@@ -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())
diff --git a/tables.go b/tables.go
index a88b501..4783cf6 100644
--- a/tables.go
+++ b/tables.go
@@ -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
diff --git a/tools.go b/tools.go
index fddbffe..2eafaf5 100644
--- a/tools.go
+++ b/tools.go
@@ -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)
}
diff --git a/tui.go b/tui.go
index a7570cf..aa9972a 100644
--- a/tui.go
+++ b/tui.go
@@ -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)