feat: the assistant keeps several chats - the current one named in the header, the list under its arrow to open or delete; actions as compact cards; folding parts open smoothly

This commit is contained in:
redtea committed 2026-10-16 10:06:06 +03:00
1 parent 6d8f39f2a5
commit b23943ff42
8 files changed
+384 -50

No files matched your search

+49 -4
View File
@@ -1,6 +1,7 @@
package server
import (
"database/sql"
"encoding/json"
"os"
"testing"
@@ -29,9 +30,11 @@ func TestPostgres(t *testing.T) {
if _, err := s.saveSSHHost(a.ID, savedHost{Label: "web", Host: "h", Port: 22, User: "root", Auth: "password"}, sshSecret{Password: "pw"}); err != nil {
t.Fatal(err)
}
s.aiAppend(a.ID, "user", "привет")
chat := s.aiNewChat(a.ID)
s.aiAppendTo(a.ID, chat, "user", "привет")
_ = s.db.SetUserAgents(a.ID, []string{"x1"})
pgReset(t, c)
pg, err := OpenPostgres(c, s.db.path)
if err != nil {
t.Fatal(err)
@@ -58,7 +61,7 @@ func TestPostgres(t *testing.T) {
if err := p.fillSaved(a.ID, tg); err != nil || tg.Password != "pw" {
t.Fatalf("saved host: %+v %v", tg, err)
}
if h := p.aiHistory(a.ID, 10); len(h) != 1 || h[0].Content != "привет" {
if h := p.aiHistoryOf(a.ID, chat, 10); len(h) != 1 || h[0].Content != "привет" {
t.Fatalf("talk: %+v", h)
}
// New rows go on after the copied ids.
@@ -78,8 +81,50 @@ func TestPostgres(t *testing.T) {
if err := pg.SetUserAgents(id, []string{"x1", "x1"}); err != nil {
t.Fatalf("grants: %v", err)
}
p.aiAppend(a.ID, "assistant", "ответ")
if h := p.aiHistory(a.ID, 10); len(h) != 2 {
p.aiAppendTo(a.ID, chat, "assistant", "ответ")
if h := p.aiHistoryOf(a.ID, chat, 10); len(h) != 2 {
t.Fatalf("talk after: %+v", h)
}
}
// Chats on PostgreSQL: past the limit the oldest go.
func TestPostgresChats(t *testing.T) {
raw := os.Getenv("LPRA_TEST_PG")
if raw == "" {
t.Skip("LPRA_TEST_PG not set")
}
var c PGConf
_ = json.Unmarshal([]byte(raw), &c)
s, _ := newTestServer(t)
pgReset(t, c)
pg, err := OpenPostgres(c, s.db.path)
if err != nil {
t.Fatal(err)
}
defer pg.Close()
defer func() {
for i := len(copyTables) - 1; i >= 0; i-- {
_, _ = pg.sql.Exec(`DROP TABLE IF EXISTS ` + copyTables[i] + ` CASCADE`)
}
}()
p := &Server{db: pg}
a, _ := pg.AdminByUsername("adm")
for i := 0; i < aiChatsKeep+3; i++ {
p.aiAppendTo(a.ID, p.aiNewChat(a.ID), "user", "q")
}
if n := len(p.aiChats(a.ID)); n != aiChatsKeep {
t.Fatalf("chats kept: %d", n)
}
}
// pgReset empties the test database: the copy runs only into an empty one.
func pgReset(t *testing.T, c PGConf) {
d, err := sql.Open("pgx", c.DSN())
if err != nil {
t.Fatal(err)
}
defer d.Close()
for i := len(copyTables) - 1; i >= 0; i-- {
_, _ = d.Exec(`DROP TABLE IF EXISTS ` + copyTables[i] + ` CASCADE`)
}
}