Changeset 0.19.1 (#83)

This commit is contained in:
2026-03-01 00:28:58 +00:00
parent 748f49bedd
commit 37a9b1a68e
12 changed files with 580 additions and 22 deletions

View File

@@ -791,6 +791,21 @@ func (h *CompletionHandler) loadConversation(channelID, userID, presetSystemProm
})
}
// ── Project system prompt (v0.19.1) ──
if h.stores.Projects != nil {
projID, _ := h.stores.Projects.GetProjectIDForChannel(context.Background(), channelID)
if projID != "" {
if proj, err := h.stores.Projects.GetByID(context.Background(), projID); err == nil {
if sp, ok := proj.Settings["system_prompt"].(string); ok && sp != "" {
messages = append(messages, providers.Message{
Role: "system",
Content: sp,
})
}
}
}
}
// ── KB hint (nudge LLM to use kb_search when KBs are active) ──
if kbHint := BuildKBHint(context.Background(), h.stores, channelID, userID, personaID); kbHint != "" {
messages = append(messages, providers.Message{

View File

@@ -400,6 +400,7 @@ type ProjectPatch struct {
Color *string `json:"color,omitempty"`
Icon *string `json:"icon,omitempty"`
IsArchived *bool `json:"is_archived,omitempty"`
Settings JSONMap `json:"settings,omitempty"`
}
// ProjectChannel represents a channel's membership in a project.
@@ -417,6 +418,7 @@ type ProjectKB struct {
KBID string `json:"kb_id" db:"kb_id"`
AutoSearch bool `json:"auto_search" db:"auto_search"`
AddedAt string `json:"added_at" db:"added_at"`
Name string `json:"name,omitempty" db:"name"` // enriched via JOIN
}
// ProjectNote represents a note's association with a project.
@@ -424,6 +426,7 @@ type ProjectNote struct {
ProjectID string `json:"project_id" db:"project_id"`
NoteID string `json:"note_id" db:"note_id"`
AddedAt string `json:"added_at" db:"added_at"`
Title string `json:"title,omitempty" db:"title"` // enriched via JOIN
}
// =========================================

View File

@@ -69,6 +69,18 @@ func (s *ProjectStore) Update(ctx context.Context, id string, patch models.Proje
if patch.IsArchived != nil {
b.Set("is_archived", *patch.IsArchived)
}
if len(patch.Settings) > 0 {
// Merge: read existing settings, overlay with patch values, write back.
var existing models.JSONMap
_ = DB.QueryRowContext(ctx, "SELECT settings FROM projects WHERE id = $1", id).Scan(&existing)
if existing == nil {
existing = make(models.JSONMap)
}
for k, v := range patch.Settings {
existing[k] = v
}
b.Set("settings", ToJSON(existing))
}
if !b.HasSets() {
return nil
}
@@ -254,10 +266,12 @@ func (s *ProjectStore) RemoveKB(ctx context.Context, projectID, kbID string) err
func (s *ProjectStore) ListKBs(ctx context.Context, projectID string) ([]models.ProjectKB, error) {
rows, err := DB.QueryContext(ctx, `
SELECT project_id, kb_id, auto_search, added_at
FROM project_knowledge_bases
WHERE project_id = $1
ORDER BY added_at`, projectID)
SELECT pk.project_id, pk.kb_id, pk.auto_search, pk.added_at,
COALESCE(kb.name, '') AS name
FROM project_knowledge_bases pk
LEFT JOIN knowledge_bases kb ON kb.id = pk.kb_id
WHERE pk.project_id = $1
ORDER BY pk.added_at`, projectID)
if err != nil {
return nil, err
}
@@ -266,7 +280,7 @@ func (s *ProjectStore) ListKBs(ctx context.Context, projectID string) ([]models.
var result []models.ProjectKB
for rows.Next() {
var pkb models.ProjectKB
if err := rows.Scan(&pkb.ProjectID, &pkb.KBID, &pkb.AutoSearch, &pkb.AddedAt); err != nil {
if err := rows.Scan(&pkb.ProjectID, &pkb.KBID, &pkb.AutoSearch, &pkb.AddedAt, &pkb.Name); err != nil {
return nil, err
}
result = append(result, pkb)
@@ -320,10 +334,12 @@ func (s *ProjectStore) RemoveNote(ctx context.Context, projectID, noteID string)
func (s *ProjectStore) ListNotes(ctx context.Context, projectID string) ([]models.ProjectNote, error) {
rows, err := DB.QueryContext(ctx, `
SELECT project_id, note_id, added_at
FROM project_notes
WHERE project_id = $1
ORDER BY added_at`, projectID)
SELECT pn.project_id, pn.note_id, pn.added_at,
COALESCE(n.title, '') AS title
FROM project_notes pn
LEFT JOIN notes n ON n.id = pn.note_id
WHERE pn.project_id = $1
ORDER BY pn.added_at`, projectID)
if err != nil {
return nil, err
}
@@ -332,7 +348,7 @@ func (s *ProjectStore) ListNotes(ctx context.Context, projectID string) ([]model
var result []models.ProjectNote
for rows.Next() {
var pn models.ProjectNote
if err := rows.Scan(&pn.ProjectID, &pn.NoteID, &pn.AddedAt); err != nil {
if err := rows.Scan(&pn.ProjectID, &pn.NoteID, &pn.AddedAt, &pn.Title); err != nil {
return nil, err
}
result = append(result, pn)

View File

@@ -85,6 +85,18 @@ func (s *ProjectStore) Update(ctx context.Context, id string, patch models.Proje
if patch.IsArchived != nil {
add("is_archived", boolToInt(*patch.IsArchived))
}
if len(patch.Settings) > 0 {
// Merge: read existing settings, overlay with patch values, write back.
var existing models.JSONMap
_ = DB.QueryRowContext(ctx, "SELECT settings FROM projects WHERE id = ?", id).Scan(&existing)
if existing == nil {
existing = make(models.JSONMap)
}
for k, v := range patch.Settings {
existing[k] = v
}
add("settings", ToJSON(existing))
}
if len(sets) == 0 {
return nil
}
@@ -277,10 +289,12 @@ func (s *ProjectStore) RemoveKB(ctx context.Context, projectID, kbID string) err
func (s *ProjectStore) ListKBs(ctx context.Context, projectID string) ([]models.ProjectKB, error) {
rows, err := DB.QueryContext(ctx, `
SELECT project_id, kb_id, auto_search, added_at
FROM project_knowledge_bases
WHERE project_id = ?
ORDER BY added_at`, projectID)
SELECT pk.project_id, pk.kb_id, pk.auto_search, pk.added_at,
COALESCE(kb.name, '') AS name
FROM project_knowledge_bases pk
LEFT JOIN knowledge_bases kb ON kb.id = pk.kb_id
WHERE pk.project_id = ?
ORDER BY pk.added_at`, projectID)
if err != nil {
return nil, err
}
@@ -290,7 +304,7 @@ func (s *ProjectStore) ListKBs(ctx context.Context, projectID string) ([]models.
for rows.Next() {
var pkb models.ProjectKB
var autoSearch int
if err := rows.Scan(&pkb.ProjectID, &pkb.KBID, &autoSearch, &pkb.AddedAt); err != nil {
if err := rows.Scan(&pkb.ProjectID, &pkb.KBID, &autoSearch, &pkb.AddedAt, &pkb.Name); err != nil {
return nil, err
}
pkb.AutoSearch = autoSearch != 0
@@ -344,10 +358,12 @@ func (s *ProjectStore) RemoveNote(ctx context.Context, projectID, noteID string)
func (s *ProjectStore) ListNotes(ctx context.Context, projectID string) ([]models.ProjectNote, error) {
rows, err := DB.QueryContext(ctx, `
SELECT project_id, note_id, added_at
FROM project_notes
WHERE project_id = ?
ORDER BY added_at`, projectID)
SELECT pn.project_id, pn.note_id, pn.added_at,
COALESCE(n.title, '') AS title
FROM project_notes pn
LEFT JOIN notes n ON n.id = pn.note_id
WHERE pn.project_id = ?
ORDER BY pn.added_at`, projectID)
if err != nil {
return nil, err
}
@@ -356,7 +372,7 @@ func (s *ProjectStore) ListNotes(ctx context.Context, projectID string) ([]model
var result []models.ProjectNote
for rows.Next() {
var pn models.ProjectNote
if err := rows.Scan(&pn.ProjectID, &pn.NoteID, &pn.AddedAt); err != nil {
if err := rows.Scan(&pn.ProjectID, &pn.NoteID, &pn.AddedAt, &pn.Title); err != nil {
return nil, err
}
result = append(result, pn)