Feat: bot to write for any char in chat (completion only)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
*.txt
|
*.txt
|
||||||
*.json
|
*.json
|
||||||
testlog
|
testlog
|
||||||
elefant
|
|
||||||
history/
|
history/
|
||||||
*.db
|
*.db
|
||||||
config.toml
|
config.toml
|
||||||
@@ -11,4 +10,5 @@ history_bak/
|
|||||||
.aider*
|
.aider*
|
||||||
tags
|
tags
|
||||||
gf-lt
|
gf-lt
|
||||||
|
gflt
|
||||||
chat_exports/*.json
|
chat_exports/*.json
|
||||||
|
|||||||
5
bot.go
5
bot.go
@@ -203,7 +203,7 @@ func sendMsgToLLM(body io.Reader) {
|
|||||||
line, err := reader.ReadBytes('\n')
|
line, err := reader.ReadBytes('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("error reading response body", "error", err, "line", string(line),
|
logger.Error("error reading response body", "error", err, "line", string(line),
|
||||||
"reqbody", string(bodyBytes), "user_role", cfg.UserRole, "parser", chunkParser, "link", cfg.CurrentAPI)
|
"user_role", cfg.UserRole, "parser", chunkParser, "link", cfg.CurrentAPI)
|
||||||
// if err.Error() != "EOF" {
|
// if err.Error() != "EOF" {
|
||||||
streamDone <- true
|
streamDone <- true
|
||||||
break
|
break
|
||||||
@@ -355,6 +355,9 @@ func chatRound(userMsg, role string, tv *tview.TextView, regen, resume bool) {
|
|||||||
logger.Error("empty reader from msgs", "role", role, "error", err)
|
logger.Error("empty reader from msgs", "role", role, "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if cfg.SkipLLMResp {
|
||||||
|
return
|
||||||
|
}
|
||||||
go sendMsgToLLM(reader)
|
go sendMsgToLLM(reader)
|
||||||
logger.Debug("looking at vars in chatRound", "msg", userMsg, "regen", regen, "resume", resume)
|
logger.Debug("looking at vars in chatRound", "msg", userMsg, "regen", regen, "resume", resume)
|
||||||
if !resume {
|
if !resume {
|
||||||
|
|||||||
@@ -15,17 +15,18 @@ type Config struct {
|
|||||||
CurrentProvider string
|
CurrentProvider string
|
||||||
APIMap map[string]string
|
APIMap map[string]string
|
||||||
//
|
//
|
||||||
ShowSys bool `toml:"ShowSys"`
|
ShowSys bool `toml:"ShowSys"`
|
||||||
LogFile string `toml:"LogFile"`
|
LogFile string `toml:"LogFile"`
|
||||||
UserRole string `toml:"UserRole"`
|
UserRole string `toml:"UserRole"`
|
||||||
ToolRole string `toml:"ToolRole"`
|
ToolRole string `toml:"ToolRole"`
|
||||||
ToolUse bool `toml:"ToolUse"`
|
ToolUse bool `toml:"ToolUse"`
|
||||||
ThinkUse bool `toml:"ThinkUse"`
|
ThinkUse bool `toml:"ThinkUse"`
|
||||||
AssistantRole string `toml:"AssistantRole"`
|
AssistantRole string `toml:"AssistantRole"`
|
||||||
SysDir string `toml:"SysDir"`
|
SysDir string `toml:"SysDir"`
|
||||||
ChunkLimit uint32 `toml:"ChunkLimit"`
|
ChunkLimit uint32 `toml:"ChunkLimit"`
|
||||||
WriteNextMsgAs string
|
WriteNextMsgAs string
|
||||||
SkipLLMResp bool
|
WriteNextMsgAsCompletionAgent string
|
||||||
|
SkipLLMResp bool
|
||||||
// embeddings
|
// embeddings
|
||||||
RAGEnabled bool `toml:"RAGEnabled"`
|
RAGEnabled bool `toml:"RAGEnabled"`
|
||||||
EmbedURL string `toml:"EmbedURL"`
|
EmbedURL string `toml:"EmbedURL"`
|
||||||
|
|||||||
18
llm.go
18
llm.go
@@ -92,7 +92,11 @@ func (lcp LlamaCPPeer) FormMsg(msg, role string, resume bool) (io.Reader, error)
|
|||||||
prompt := strings.Join(messages, "\n")
|
prompt := strings.Join(messages, "\n")
|
||||||
// strings builder?
|
// strings builder?
|
||||||
if !resume {
|
if !resume {
|
||||||
botMsgStart := "\n" + cfg.AssistantRole + ":\n"
|
botPersona := cfg.AssistantRole
|
||||||
|
if cfg.WriteNextMsgAsCompletionAgent != "" {
|
||||||
|
botPersona = cfg.WriteNextMsgAsCompletionAgent
|
||||||
|
}
|
||||||
|
botMsgStart := "\n" + botPersona + ":\n"
|
||||||
prompt += botMsgStart
|
prompt += botMsgStart
|
||||||
}
|
}
|
||||||
if cfg.ThinkUse && !cfg.ToolUse {
|
if cfg.ThinkUse && !cfg.ToolUse {
|
||||||
@@ -234,7 +238,11 @@ func (ds DeepSeekerCompletion) FormMsg(msg, role string, resume bool) (io.Reader
|
|||||||
prompt := strings.Join(messages, "\n")
|
prompt := strings.Join(messages, "\n")
|
||||||
// strings builder?
|
// strings builder?
|
||||||
if !resume {
|
if !resume {
|
||||||
botMsgStart := "\n" + cfg.AssistantRole + ":\n"
|
botPersona := cfg.AssistantRole
|
||||||
|
if cfg.WriteNextMsgAsCompletionAgent != "" {
|
||||||
|
botPersona = cfg.WriteNextMsgAsCompletionAgent
|
||||||
|
}
|
||||||
|
botMsgStart := "\n" + botPersona + ":\n"
|
||||||
prompt += botMsgStart
|
prompt += botMsgStart
|
||||||
}
|
}
|
||||||
if cfg.ThinkUse && !cfg.ToolUse {
|
if cfg.ThinkUse && !cfg.ToolUse {
|
||||||
@@ -376,7 +384,11 @@ func (or OpenRouterCompletion) FormMsg(msg, role string, resume bool) (io.Reader
|
|||||||
prompt := strings.Join(messages, "\n")
|
prompt := strings.Join(messages, "\n")
|
||||||
// strings builder?
|
// strings builder?
|
||||||
if !resume {
|
if !resume {
|
||||||
botMsgStart := "\n" + cfg.AssistantRole + ":\n"
|
botPersona := cfg.AssistantRole
|
||||||
|
if cfg.WriteNextMsgAsCompletionAgent != "" {
|
||||||
|
botPersona = cfg.WriteNextMsgAsCompletionAgent
|
||||||
|
}
|
||||||
|
botMsgStart := "\n" + botPersona + ":\n"
|
||||||
prompt += botMsgStart
|
prompt += botMsgStart
|
||||||
}
|
}
|
||||||
if cfg.ThinkUse && !cfg.ToolUse {
|
if cfg.ThinkUse && !cfg.ToolUse {
|
||||||
|
|||||||
11
main.go
11
main.go
@@ -9,11 +9,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
botRespMode = false
|
botRespMode = false
|
||||||
editMode = false
|
editMode = false
|
||||||
selectedIndex = int(-1)
|
selectedIndex = int(-1)
|
||||||
indexLine = "F12 to show keys help | bot resp mode: [orange:-:b]%v[-:-:-] (F6) | char: [orange:-:b]%s[-:-:-] (ctrl+s) | chat: [orange:-:b]%s[-:-:-] (F1) | toolUseAdviced: [orange:-:b]%v[-:-:-] (ctrl+k) | model: [orange:-:b]%s[-:-:-] (ctrl+l) | skip LLM resp: [orange:-:b]%v[-:-:-] (F10)\nAPI_URL: [orange:-:b]%s[-:-:-] (ctrl+v) | ThinkUse: [orange:-:b]%v[-:-:-] (ctrl+p) | Log Level: [orange:-:b]%v[-:-:-] (ctrl+p) | Recording: [orange:-:b]%v[-:-:-] (ctrl+r) | Writing as: [orange:-:b]%s[-:-:-] (ctrl+q)"
|
indexLine = "F12 to show keys help | bot resp mode: [orange:-:b]%v[-:-:-] (F6) | card's char: [orange:-:b]%s[-:-:-] (ctrl+s) | chat: [orange:-:b]%s[-:-:-] (F1) | toolUseAdviced: [orange:-:b]%v[-:-:-] (ctrl+k) | model: [orange:-:b]%s[-:-:-] (ctrl+l) | skip LLM resp: [orange:-:b]%v[-:-:-] (F10)\nAPI_URL: [orange:-:b]%s[-:-:-] (ctrl+v) | ThinkUse: [orange:-:b]%v[-:-:-] (ctrl+p) | Log Level: [orange:-:b]%v[-:-:-] (ctrl+p) | Recording: [orange:-:b]%v[-:-:-] (ctrl+r) | Writing as: [orange:-:b]%s[-:-:-] (ctrl+q)"
|
||||||
focusSwitcher = map[tview.Primitive]tview.Primitive{}
|
indexLineCompletion = "F12 to show keys help | bot resp mode: [orange:-:b]%v[-:-:-] (F6) | card's char: [orange:-:b]%s[-:-:-] (ctrl+s) | chat: [orange:-:b]%s[-:-:-] (F1) | toolUseAdviced: [orange:-:b]%v[-:-:-] (ctrl+k) | model: [orange:-:b]%s[-:-:-] (ctrl+l) | skip LLM resp: [orange:-:b]%v[-:-:-] (F10)\nAPI_URL: [orange:-:b]%s[-:-:-] (ctrl+v) | ThinkUse: [orange:-:b]%v[-:-:-] (ctrl+p) | Log Level: [orange:-:b]%v[-:-:-] (ctrl+p) | Recording: [orange:-:b]%v[-:-:-] (ctrl+r) | Writing as: [orange:-:b]%s[-:-:-] (ctrl+q) | Bot will write as [orange:-:b]%s[-:-:-] (ctrl+x)"
|
||||||
|
focusSwitcher = map[tview.Primitive]tview.Primitive{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func isASCII(s string) bool {
|
func isASCII(s string) bool {
|
||||||
|
|||||||
73
tui.go
73
tui.go
@@ -98,6 +98,15 @@ func loadImage() {
|
|||||||
imgView.SetImage(img)
|
imgView.SetImage(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func strInSlice(s string, sl []string) bool {
|
||||||
|
for _, el := range sl {
|
||||||
|
if strings.EqualFold(s, el) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func colorText() {
|
func colorText() {
|
||||||
text := textView.GetText(false)
|
text := textView.GetText(false)
|
||||||
// Step 1: Extract code blocks and replace them with unique placeholders
|
// Step 1: Extract code blocks and replace them with unique placeholders
|
||||||
@@ -151,8 +160,17 @@ func updateStatusLine() {
|
|||||||
if cfg.WriteNextMsgAs != "" {
|
if cfg.WriteNextMsgAs != "" {
|
||||||
persona = cfg.WriteNextMsgAs
|
persona = cfg.WriteNextMsgAs
|
||||||
}
|
}
|
||||||
position.SetText(fmt.Sprintf(indexLine, botRespMode, cfg.AssistantRole, activeChatName, cfg.ToolUse, chatBody.Model,
|
if strings.Contains(cfg.CurrentAPI, "chat") {
|
||||||
cfg.SkipLLMResp, cfg.CurrentAPI, cfg.ThinkUse, logLevel.Level(), isRecording, persona))
|
position.SetText(fmt.Sprintf(indexLine, botRespMode, cfg.AssistantRole, activeChatName, cfg.ToolUse, chatBody.Model,
|
||||||
|
cfg.SkipLLMResp, cfg.CurrentAPI, cfg.ThinkUse, logLevel.Level(), isRecording, persona))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
botPersona := cfg.AssistantRole
|
||||||
|
if cfg.WriteNextMsgAsCompletionAgent != "" {
|
||||||
|
botPersona = cfg.WriteNextMsgAsCompletionAgent
|
||||||
|
}
|
||||||
|
position.SetText(fmt.Sprintf(indexLineCompletion, botRespMode, cfg.AssistantRole, activeChatName, cfg.ToolUse, chatBody.Model,
|
||||||
|
cfg.SkipLLMResp, cfg.CurrentAPI, cfg.ThinkUse, logLevel.Level(), isRecording, persona, botPersona))
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSysCards() ([]string, error) {
|
func initSysCards() ([]string, error) {
|
||||||
@@ -354,7 +372,6 @@ func init() {
|
|||||||
editArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
editArea.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
// if event.Key() == tcell.KeyEscape && editMode {
|
// if event.Key() == tcell.KeyEscape && editMode {
|
||||||
if event.Key() == tcell.KeyEscape {
|
if event.Key() == tcell.KeyEscape {
|
||||||
logger.Warn("edit debug; esc is pressed")
|
|
||||||
defer colorText()
|
defer colorText()
|
||||||
editedMsg := editArea.GetText()
|
editedMsg := editArea.GetText()
|
||||||
if editedMsg == "" {
|
if editedMsg == "" {
|
||||||
@@ -424,10 +441,7 @@ func init() {
|
|||||||
if err := copyToClipboard(m.Content); err != nil {
|
if err := copyToClipboard(m.Content); err != nil {
|
||||||
logger.Error("failed to copy to clipboard", "error", err)
|
logger.Error("failed to copy to clipboard", "error", err)
|
||||||
}
|
}
|
||||||
previewLen := 30
|
previewLen := min(30, len(m.Content))
|
||||||
if len(m.Content) < 30 {
|
|
||||||
previewLen = len(m.Content)
|
|
||||||
}
|
|
||||||
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:previewLen])
|
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:previewLen])
|
||||||
if err := notifyUser("copied", notification); err != nil {
|
if err := notifyUser("copied", notification); err != nil {
|
||||||
logger.Error("failed to send notification", "error", err)
|
logger.Error("failed to send notification", "error", err)
|
||||||
@@ -573,10 +587,7 @@ func init() {
|
|||||||
if err := copyToClipboard(m.Content); err != nil {
|
if err := copyToClipboard(m.Content); err != nil {
|
||||||
logger.Error("failed to copy to clipboard", "error", err)
|
logger.Error("failed to copy to clipboard", "error", err)
|
||||||
}
|
}
|
||||||
previewLen := 30
|
previewLen := min(30, len(m.Content))
|
||||||
if len(m.Content) < 30 {
|
|
||||||
previewLen = len(m.Content)
|
|
||||||
}
|
|
||||||
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:previewLen])
|
notification := fmt.Sprintf("msg '%s' was copied to the clipboard", m.Content[:previewLen])
|
||||||
if err := notifyUser("copied", notification); err != nil {
|
if err := notifyUser("copied", notification); err != nil {
|
||||||
logger.Error("failed to send notification", "error", err)
|
logger.Error("failed to send notification", "error", err)
|
||||||
@@ -798,7 +809,12 @@ func init() {
|
|||||||
roles := chatBody.ListRoles()
|
roles := chatBody.ListRoles()
|
||||||
if len(roles) == 0 {
|
if len(roles) == 0 {
|
||||||
logger.Warn("empty roles in chat")
|
logger.Warn("empty roles in chat")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
if !strInSlice(cfg.UserRole, roles) {
|
||||||
|
roles = append(roles, cfg.UserRole)
|
||||||
|
}
|
||||||
|
logger.Info("list roles", "roles", roles)
|
||||||
for i, role := range roles {
|
for i, role := range roles {
|
||||||
if strings.EqualFold(role, persona) {
|
if strings.EqualFold(role, persona) {
|
||||||
if i == len(roles)-1 {
|
if i == len(roles)-1 {
|
||||||
@@ -806,6 +822,33 @@ func init() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
cfg.WriteNextMsgAs = roles[i+1] // get next role
|
cfg.WriteNextMsgAs = roles[i+1] // get next role
|
||||||
|
logger.Info("picked role", "roles", roles, "index", i+1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateStatusLine()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if event.Key() == tcell.KeyCtrlX {
|
||||||
|
persona := cfg.AssistantRole
|
||||||
|
if cfg.WriteNextMsgAsCompletionAgent != "" {
|
||||||
|
persona = cfg.WriteNextMsgAsCompletionAgent
|
||||||
|
}
|
||||||
|
roles := chatBody.ListRoles()
|
||||||
|
if len(roles) == 0 {
|
||||||
|
logger.Warn("empty roles in chat")
|
||||||
|
}
|
||||||
|
if !strInSlice(cfg.AssistantRole, roles) {
|
||||||
|
roles = append(roles, cfg.AssistantRole)
|
||||||
|
}
|
||||||
|
for i, role := range roles {
|
||||||
|
if strings.EqualFold(role, persona) {
|
||||||
|
if i == len(roles)-1 {
|
||||||
|
cfg.WriteNextMsgAsCompletionAgent = roles[0] // reached last, get first
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cfg.WriteNextMsgAsCompletionAgent = roles[i+1] // get next role
|
||||||
|
logger.Info("picked role", "roles", roles, "index", i+1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -836,10 +879,10 @@ func init() {
|
|||||||
textView.ScrollToEnd()
|
textView.ScrollToEnd()
|
||||||
colorText()
|
colorText()
|
||||||
}
|
}
|
||||||
if !cfg.SkipLLMResp {
|
go chatRound(msgText, persona, textView, false, false)
|
||||||
// update statue line
|
// if !cfg.SkipLLMResp {
|
||||||
go chatRound(msgText, persona, textView, false, false)
|
// // update statue line
|
||||||
}
|
// }
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyPgUp || event.Key() == tcell.KeyPgDn {
|
if event.Key() == tcell.KeyPgUp || event.Key() == tcell.KeyPgDn {
|
||||||
|
|||||||
Reference in New Issue
Block a user