Add default conversation title

This commit is contained in:
dwrz
2026-10-31 16:56:08 +00:00
parent 47badbb0d6
commit d9ce81af9c
7 changed files with 439 additions and 41 deletions
+75 -17
View File
@@ -136,20 +136,16 @@ func testConversation(t *testing.T, ctx context.Context, db *SQLite) {
t.Fatalf("expected 1 conversation, got %d", len(conversations))
}
// Rename the conversation. Insert a message first: the insert
// trigger moves updated_at, so the rename can show that it
// keeps the timestamp.
if _, err := qw.InsertMessage(ctx, InsertMessageParams{
ConversationId: c.Id,
Sequence: 1,
Role: MessageRoleUser,
Content: jsontext.Value(`{"role":"user","content":"Hello"}`),
}); err != nil {
t.Fatalf("InsertMessage: %v", err)
}
before, err := qr.SelectConversationId(ctx, c.Id)
if err != nil {
t.Fatalf("SelectConversationId: %v", err)
// Rename the conversation. The rename must refresh updated_at:
// plant a known-old timestamp, then check that the statement
// moved it.
const staleUpdatedAt = "2020-01-01T00:00:00Z"
if _, err := db.Writer.ExecContext(
ctx,
"UPDATE conversations SET updated_at = ? WHERE id = ?",
staleUpdatedAt, c.Id,
); err != nil {
t.Fatalf("plant stale updated_at: %v", err)
}
renamed, err := qw.UpdateConversationTitle(ctx, UpdateConversationTitleParams{
Id: c.Id,
@@ -161,10 +157,14 @@ func testConversation(t *testing.T, ctx context.Context, db *SQLite) {
if renamed.Title == nil || *renamed.Title != "renamed" {
t.Fatalf("Title = %v, want renamed", renamed.Title)
}
if !renamed.UpdatedAt.Equal(before.UpdatedAt) {
stale, err := time.Parse(time.RFC3339, staleUpdatedAt)
if err != nil {
t.Fatalf("parse staleUpdatedAt: %v", err)
}
if !renamed.UpdatedAt.After(stale) {
t.Fatalf(
"UpdatedAt = %v, want %v: a rename must not move updated_at",
renamed.UpdatedAt, before.UpdatedAt,
"UpdatedAt = %v, want a time after %v",
renamed.UpdatedAt, stale,
)
}
@@ -175,6 +175,64 @@ func testConversation(t *testing.T, ctx context.Context, db *SQLite) {
}); !errors.Is(err, sql.ErrNoRows) {
t.Fatalf("UpdateConversationTitle(missing) = %v, want sql.ErrNoRows", err)
}
// The guarded update sets the title of an untitled
// conversation, and does not touch one that is titled. It must
// refresh updated_at: plant the stale timestamp, then check
// that the statement moved it.
blank, err := qw.InsertConversation(ctx, InsertConversationParams{
UserId: u.Id,
})
if err != nil {
t.Fatalf("InsertConversation: %v", err)
}
if _, err := db.Writer.ExecContext(
ctx,
"UPDATE conversations SET updated_at = ? WHERE id = ?",
staleUpdatedAt, blank.Id,
); err != nil {
t.Fatalf("plant stale updated_at: %v", err)
}
titled, err := qw.UpdateConversationTitleIfUnset(
ctx,
UpdateConversationTitleIfUnsetParams{
Id: blank.Id,
Title: "derived",
},
)
if err != nil {
t.Fatalf("UpdateConversationTitleIfUnset: %v", err)
}
if titled.Title == nil || *titled.Title != "derived" {
t.Fatalf("Title = %v, want derived", titled.Title)
}
if !titled.UpdatedAt.After(stale) {
t.Fatalf(
"UpdatedAt = %v, want a time after %v",
titled.UpdatedAt, stale,
)
}
for _, tt := range []struct {
name string
id string
}{
{name: "titled twice", id: blank.Id},
{name: "renamed conversation", id: c.Id},
{name: "missing conversation", id: "missing"},
} {
if _, err := qw.UpdateConversationTitleIfUnset(
ctx,
UpdateConversationTitleIfUnsetParams{
Id: tt.id,
Title: "second",
},
); !errors.Is(err, sql.ErrNoRows) {
t.Fatalf(
"UpdateConversationTitleIfUnset(%s) = %v, want sql.ErrNoRows",
tt.name, err,
)
}
}
}
func testMessaging(t *testing.T, ctx context.Context, db *SQLite) {