Refactor: sql on conflict; fix unittest; page names to vars
This commit is contained in:
@@ -48,6 +48,7 @@
|
|||||||
- when bot generation ended with err: need a way to switch back to the bot_resp_false mode; +
|
- when bot generation ended with err: need a way to switch back to the bot_resp_false mode; +
|
||||||
- no selection focus on modal sys buttons after opening it a second time; (cannot reproduce) +
|
- no selection focus on modal sys buttons after opening it a second time; (cannot reproduce) +
|
||||||
- chat should contain char in it (one to many: char: []chats); +
|
- chat should contain char in it (one to many: char: []chats); +
|
||||||
- all page names should be vars;
|
- all page names should be vars; +
|
||||||
- normal case regen omits assistant icon; +
|
- normal case regen omits assistant icon; +
|
||||||
- user icon (and role?) from config is not used; +
|
- user icon (and role?) from config is not used; +
|
||||||
|
- F1 can load any chat, by loading chat of other agent it does not switch agents, if that chat is continued, it will rewrite agent in db; (either allow only chats from current agent OR switch agent on chat loading);
|
||||||
|
|||||||
@@ -53,11 +53,15 @@ func (p ProviderSQL) GetLastChatByAgent(agent string) (*models.Chat, error) {
|
|||||||
return &resp, err
|
return &resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://sqlite.org/lang_upsert.html
|
||||||
|
// on conflict was added
|
||||||
func (p ProviderSQL) UpsertChat(chat *models.Chat) (*models.Chat, error) {
|
func (p ProviderSQL) UpsertChat(chat *models.Chat) (*models.Chat, error) {
|
||||||
// Prepare the SQL statement
|
// Prepare the SQL statement
|
||||||
query := `
|
query := `
|
||||||
INSERT OR REPLACE INTO chats (id, name, msgs, agent, created_at, updated_at)
|
INSERT INTO chats (id, name, msgs, agent, created_at, updated_at)
|
||||||
VALUES (:id, :name, :msgs, :agent, :created_at, :updated_at)
|
VALUES (:id, :name, :msgs, :agent, :created_at, :updated_at)
|
||||||
|
ON CONFLICT(id) DO UPDATE SET msgs=excluded.msgs,
|
||||||
|
updated_at=excluded.updated_at
|
||||||
RETURNING *;`
|
RETURNING *;`
|
||||||
stmt, err := p.db.PrepareNamed(query)
|
stmt, err := p.db.PrepareNamed(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ func TestChatHistory(t *testing.T) {
|
|||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
msgs TEXT NOT NULL,
|
msgs TEXT NOT NULL,
|
||||||
|
agent TEXT NOT NULL,
|
||||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
);`)
|
);`)
|
||||||
|
|||||||
7
tools.go
7
tools.go
@@ -9,9 +9,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
toolCallRE = regexp.MustCompile(`__tool_call__\s*([\s\S]*?)__tool_call__`)
|
toolCallRE = regexp.MustCompile(`__tool_call__\s*([\s\S]*?)__tool_call__`)
|
||||||
quotesRE = regexp.MustCompile(`(".*?")`)
|
quotesRE = regexp.MustCompile(`(".*?")`)
|
||||||
starRE = regexp.MustCompile(`(\*.*?\*)`)
|
starRE = regexp.MustCompile(`(\*.*?\*)`)
|
||||||
|
// codeBlokRE = regexp.MustCompile(`(\x60\x60\x60.*?\x60\x60\x60)`)
|
||||||
basicSysMsg = `Large Language Model that helps user with any of his requests.`
|
basicSysMsg = `Large Language Model that helps user with any of his requests.`
|
||||||
toolSysMsg = `You're a helpful assistant.
|
toolSysMsg = `You're a helpful assistant.
|
||||||
# Tools
|
# Tools
|
||||||
|
|||||||
68
tui.go
68
tui.go
@@ -25,7 +25,15 @@ var (
|
|||||||
sysModal *tview.Modal
|
sysModal *tview.Modal
|
||||||
indexPickWindow *tview.InputField
|
indexPickWindow *tview.InputField
|
||||||
renameWindow *tview.InputField
|
renameWindow *tview.InputField
|
||||||
helpText = `
|
// pages
|
||||||
|
historyPage = "historyPage"
|
||||||
|
agentPage = "agentPage"
|
||||||
|
editMsgPage = "editMsgPage"
|
||||||
|
indexPage = "indexPage"
|
||||||
|
helpPage = "helpPage"
|
||||||
|
renamePage = "renamePage"
|
||||||
|
// help text
|
||||||
|
helpText = `
|
||||||
[yellow]Esc[white]: send msg
|
[yellow]Esc[white]: send msg
|
||||||
[yellow]PgUp/Down[white]: switch focus
|
[yellow]PgUp/Down[white]: switch focus
|
||||||
[yellow]F1[white]: manage chats
|
[yellow]F1[white]: manage chats
|
||||||
@@ -39,15 +47,31 @@ var (
|
|||||||
[yellow]Ctrl+s[white]: load new char/agent
|
[yellow]Ctrl+s[white]: load new char/agent
|
||||||
[yellow]Ctrl+e[white]: export chat to json file
|
[yellow]Ctrl+e[white]: export chat to json file
|
||||||
[yellow]Ctrl+n[white]: start a new chat
|
[yellow]Ctrl+n[white]: start a new chat
|
||||||
|
[yellow]Ctrl+c[white]: close programm
|
||||||
|
|
||||||
Press Enter to go back
|
Press Enter to go back
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// // code block colors get interrupted by " & *
|
||||||
|
// func codeBlockColor(text string) string {
|
||||||
|
// fi := strings.Index(text, "```")
|
||||||
|
// if fi < 0 {
|
||||||
|
// return text
|
||||||
|
// }
|
||||||
|
// li := strings.LastIndex(text, "```")
|
||||||
|
// if li == fi { // only openning backticks
|
||||||
|
// return text
|
||||||
|
// }
|
||||||
|
// return strings.Replace(text, "```", "```[blue:black:i]", 1)
|
||||||
|
// }
|
||||||
|
|
||||||
func colorText() {
|
func colorText() {
|
||||||
// INFO: is there a better way to markdown?
|
// INFO: is there a better way to markdown?
|
||||||
tv := textView.GetText(false)
|
tv := textView.GetText(false)
|
||||||
cq := quotesRE.ReplaceAllString(tv, `[orange:-:-]$1[-:-:-]`)
|
cq := quotesRE.ReplaceAllString(tv, `[orange:-:-]$1[-:-:-]`)
|
||||||
|
// cb := codeBlockColor(cq)
|
||||||
|
// cb := codeBlockRE.ReplaceAllString(cq, `[blue:black:i]$1[-:-:-]`)
|
||||||
textView.SetText(starRE.ReplaceAllString(cq, `[turquoise::i]$1[-:-:-]`))
|
textView.SetText(starRE.ReplaceAllString(cq, `[turquoise::i]$1[-:-:-]`))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,29 +167,29 @@ func init() {
|
|||||||
switch buttonLabel {
|
switch buttonLabel {
|
||||||
case "new":
|
case "new":
|
||||||
startNewChat()
|
startNewChat()
|
||||||
pages.RemovePage("history")
|
pages.RemovePage(historyPage)
|
||||||
return
|
return
|
||||||
// set text
|
// set text
|
||||||
case "cancel":
|
case "cancel":
|
||||||
pages.RemovePage("history")
|
pages.RemovePage(historyPage)
|
||||||
return
|
return
|
||||||
case "rename current":
|
case "rename current":
|
||||||
// add input field
|
// add input field
|
||||||
pages.RemovePage("history")
|
pages.RemovePage(historyPage)
|
||||||
pages.AddPage("renameW", renameWindow, true, true)
|
pages.AddPage(renamePage, renameWindow, true, true)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
fn := buttonLabel
|
fn := buttonLabel
|
||||||
history, err := loadHistoryChat(fn)
|
history, err := loadHistoryChat(fn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to read history file", "chat", fn)
|
logger.Error("failed to read history file", "chat", fn)
|
||||||
pages.RemovePage("history")
|
pages.RemovePage(historyPage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chatBody.Messages = history
|
chatBody.Messages = history
|
||||||
textView.SetText(chatToText(cfg.ShowSys))
|
textView.SetText(chatToText(cfg.ShowSys))
|
||||||
activeChatName = fn
|
activeChatName = fn
|
||||||
pages.RemovePage("history")
|
pages.RemovePage(historyPage)
|
||||||
colorText()
|
colorText()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -175,13 +199,13 @@ func init() {
|
|||||||
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
|
||||||
switch buttonLabel {
|
switch buttonLabel {
|
||||||
case "cancel":
|
case "cancel":
|
||||||
pages.RemovePage("sys")
|
pages.RemovePage(agentPage)
|
||||||
sysModal.ClearButtons()
|
sysModal.ClearButtons()
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
if ok := charToStart(buttonLabel); !ok {
|
if ok := charToStart(buttonLabel); !ok {
|
||||||
logger.Warn("no such sys msg", "name", buttonLabel)
|
logger.Warn("no such sys msg", "name", buttonLabel)
|
||||||
pages.RemovePage("sys")
|
pages.RemovePage(agentPage)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// replace textview
|
// replace textview
|
||||||
@@ -189,7 +213,7 @@ func init() {
|
|||||||
colorText()
|
colorText()
|
||||||
updateStatusLine()
|
updateStatusLine()
|
||||||
sysModal.ClearButtons()
|
sysModal.ClearButtons()
|
||||||
pages.RemovePage("sys")
|
pages.RemovePage(agentPage)
|
||||||
app.SetFocus(textArea)
|
app.SetFocus(textArea)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -203,14 +227,14 @@ func init() {
|
|||||||
if err := notifyUser("edit", "no edit provided"); err != nil {
|
if err := notifyUser("edit", "no edit provided"); err != nil {
|
||||||
logger.Error("failed to send notification", "error", err)
|
logger.Error("failed to send notification", "error", err)
|
||||||
}
|
}
|
||||||
pages.RemovePage("editArea")
|
pages.RemovePage(editMsgPage)
|
||||||
editMode = false
|
editMode = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
chatBody.Messages[selectedIndex].Content = editedMsg
|
chatBody.Messages[selectedIndex].Content = editedMsg
|
||||||
// change textarea
|
// change textarea
|
||||||
textView.SetText(chatToText(cfg.ShowSys))
|
textView.SetText(chatToText(cfg.ShowSys))
|
||||||
pages.RemovePage("editArea")
|
pages.RemovePage(editMsgPage)
|
||||||
editMode = false
|
editMode = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -221,7 +245,7 @@ func init() {
|
|||||||
SetFieldWidth(4).
|
SetFieldWidth(4).
|
||||||
SetAcceptanceFunc(tview.InputFieldInteger).
|
SetAcceptanceFunc(tview.InputFieldInteger).
|
||||||
SetDoneFunc(func(key tcell.Key) {
|
SetDoneFunc(func(key tcell.Key) {
|
||||||
pages.RemovePage("getIndex")
|
pages.RemovePage(indexPage)
|
||||||
})
|
})
|
||||||
indexPickWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
indexPickWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
switch event.Key() {
|
switch event.Key() {
|
||||||
@@ -239,12 +263,12 @@ func init() {
|
|||||||
if err := notifyUser("error", msg); err != nil {
|
if err := notifyUser("error", msg); err != nil {
|
||||||
logger.Error("failed to send notification", "error", err)
|
logger.Error("failed to send notification", "error", err)
|
||||||
}
|
}
|
||||||
pages.RemovePage("getIndex")
|
pages.RemovePage(indexPage)
|
||||||
return event
|
return event
|
||||||
}
|
}
|
||||||
m := chatBody.Messages[selectedIndex]
|
m := chatBody.Messages[selectedIndex]
|
||||||
if editMode && event.Key() == tcell.KeyEnter {
|
if editMode && event.Key() == tcell.KeyEnter {
|
||||||
pages.AddPage("editArea", editArea, true, true)
|
pages.AddPage(editMsgPage, editArea, true, true)
|
||||||
editArea.SetText(m.Content, true)
|
editArea.SetText(m.Content, true)
|
||||||
}
|
}
|
||||||
if !editMode && event.Key() == tcell.KeyEnter {
|
if !editMode && event.Key() == tcell.KeyEnter {
|
||||||
@@ -271,7 +295,7 @@ func init() {
|
|||||||
SetFieldWidth(20).
|
SetFieldWidth(20).
|
||||||
SetAcceptanceFunc(tview.InputFieldMaxLength(100)).
|
SetAcceptanceFunc(tview.InputFieldMaxLength(100)).
|
||||||
SetDoneFunc(func(key tcell.Key) {
|
SetDoneFunc(func(key tcell.Key) {
|
||||||
pages.RemovePage("renameW")
|
pages.RemovePage(renamePage)
|
||||||
})
|
})
|
||||||
renameWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
renameWindow.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
if event.Key() == tcell.KeyEnter {
|
if event.Key() == tcell.KeyEnter {
|
||||||
@@ -297,7 +321,7 @@ func init() {
|
|||||||
})
|
})
|
||||||
//
|
//
|
||||||
helpView = tview.NewTextView().SetDynamicColors(true).SetText(helpText).SetDoneFunc(func(key tcell.Key) {
|
helpView = tview.NewTextView().SetDynamicColors(true).SetText(helpText).SetDoneFunc(func(key tcell.Key) {
|
||||||
pages.RemovePage("helpView")
|
pages.RemovePage(helpPage)
|
||||||
})
|
})
|
||||||
helpView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
helpView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
switch event.Key() {
|
switch event.Key() {
|
||||||
@@ -326,7 +350,7 @@ func init() {
|
|||||||
chatOpts := append(chatOpts, chatList...)
|
chatOpts := append(chatOpts, chatList...)
|
||||||
chatActModal.ClearButtons()
|
chatActModal.ClearButtons()
|
||||||
chatActModal.AddButtons(chatOpts)
|
chatActModal.AddButtons(chatOpts)
|
||||||
pages.AddPage("history", chatActModal, true, true)
|
pages.AddPage(historyPage, chatActModal, true, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyF2 {
|
if event.Key() == tcell.KeyF2 {
|
||||||
@@ -354,7 +378,7 @@ func init() {
|
|||||||
if event.Key() == tcell.KeyF4 {
|
if event.Key() == tcell.KeyF4 {
|
||||||
// edit msg
|
// edit msg
|
||||||
editMode = true
|
editMode = true
|
||||||
pages.AddPage("getIndex", indexPickWindow, true, true)
|
pages.AddPage(indexPage, indexPickWindow, true, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyF5 {
|
if event.Key() == tcell.KeyF5 {
|
||||||
@@ -388,12 +412,12 @@ func init() {
|
|||||||
if event.Key() == tcell.KeyF8 {
|
if event.Key() == tcell.KeyF8 {
|
||||||
// copy msg to clipboard
|
// copy msg to clipboard
|
||||||
editMode = false
|
editMode = false
|
||||||
pages.AddPage("getIndex", indexPickWindow, true, true)
|
pages.AddPage(indexPage, indexPickWindow, true, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyF12 {
|
if event.Key() == tcell.KeyF12 {
|
||||||
// help window cheatsheet
|
// help window cheatsheet
|
||||||
pages.AddPage("helpView", helpView, true, true)
|
pages.AddPage(helpPage, helpView, true, true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if event.Key() == tcell.KeyCtrlE {
|
if event.Key() == tcell.KeyCtrlE {
|
||||||
@@ -427,7 +451,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
sysModal.AddButtons(labels)
|
sysModal.AddButtons(labels)
|
||||||
// load all chars
|
// load all chars
|
||||||
pages.AddPage("sys", sysModal, true, true)
|
pages.AddPage(agentPage, sysModal, true, true)
|
||||||
updateStatusLine()
|
updateStatusLine()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user