Why: backend main pinned core 019617e (unfetchable post-migration) and the store List* functions returned nil slices that encode as JSON null, which crashed the frontend nav with .map on null (the 2026-09-30 white-screen). Evidence: go test ./... across all packages; store regression TestEmptyListsSerializeAsEmptyArrays asserts [] for empty project lists. Impact: all 17 store list sites now initialize empty slices; build-blocker core pin resolved; frontend no longer receives null for empty lists. Refs: documents/records/2026-09-30-history-migration.md
52 lines
1.5 KiB
Go
52 lines
1.5 KiB
Go
package store
|
||
|
||
import (
|
||
core "agent-system-core"
|
||
)
|
||
|
||
// searchKnowledgePG:PG 档知识检索(设计 D16)。
|
||
// 单查询混合:tsvector('simple' 配置,词级)OR trigram LIKE 子串(中文兜底;
|
||
// LIKE 由 pg_trgm GIN 索引加速)。排序:ts_rank 优先,命中时间次之。
|
||
func (s *Store) searchKnowledgePG(owner string, q core.RetrievalQuery) ([]core.RetrievalHit, error) {
|
||
topK := q.TopK
|
||
if topK <= 0 {
|
||
topK = 5
|
||
}
|
||
text := q.Text
|
||
rows, err := s.db.Query(s.q(`
|
||
SELECT k.id,k.owner,k.project_id,k.source,k.title,k.ref,k.chunk,k.created_at,
|
||
ts_rank(k.tsv, websearch_to_tsquery('simple', ?)) AS r
|
||
FROM knowledge k
|
||
WHERE (k.owner=? OR k.owner='')
|
||
AND (? = '' OR k.tsv @@ websearch_to_tsquery('simple', ?) OR k.chunk LIKE ? OR k.title LIKE ?)
|
||
ORDER BY r DESC, k.created_at DESC
|
||
LIMIT ?`), text, owner, text, text, "%"+text+"%", "%"+text+"%", topK*2)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer rows.Close()
|
||
out := []core.RetrievalHit{}
|
||
for rows.Next() {
|
||
var d core.KnowledgeDoc
|
||
var own, ca string
|
||
var rank float64
|
||
if err := rows.Scan(&d.ID, &own, &d.ProjectID, &d.Source, &d.Title, &d.Ref, &d.Chunk, &ca, &rank); err != nil {
|
||
return nil, err
|
||
}
|
||
d.Owner = own
|
||
d.CreatedAt, _ = parseTime(ca)
|
||
if !knowledgeVisible(owner, q, d) {
|
||
continue
|
||
}
|
||
score := rank
|
||
if score == 0 {
|
||
score = 0.5 // 纯子串命中(trigram/中文兜底)给保底分
|
||
}
|
||
out = append(out, core.RetrievalHit{Doc: d, Score: score, Kind: "fulltext"})
|
||
if len(out) >= topK {
|
||
break
|
||
}
|
||
}
|
||
return out, rows.Err()
|
||
}
|