llmgw-kb collections names each collection's owner as people know it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilker ManapandClaude Opus 5.5 committed 2026-10-08 15:42:40 +02:00
1 parent 496625824b
commit 54ba04c52a
5 files changed
+36 -8

No files matched your search

+1 -1
View File
@@ -237,7 +237,7 @@ func collectionsCmd(g *globalFlags) *cobra.Command {
if x.Writable {
access = "read, write"
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s (%d)\n", x.Name, access, x.Owner, x.EmbedModel, x.Dims)
fmt.Fprintf(tw, "%s\t%s\t%s\t%s (%d)\n", x.Name, access, or(x.OwnerName, x.Owner), x.EmbedModel, x.Dims)
}
return tw.Flush()
},
+1
View File
@@ -59,6 +59,7 @@ type Collection struct {
ID string `json:"id"`
Name string `json:"name"`
Owner string `json:"owner"`
OwnerName string `json:"owner_name"`
EmbedModel string `json:"embed_model"`
Dims int `json:"dims"`
Writable bool `json:"writable"`
+9 -6
View File
@@ -43,9 +43,12 @@ const (
// KBCollectionView is a collection as a caller sees it.
type KBCollectionView struct {
ID string `json:"id"`
Name string `json:"name"`
ID string `json:"id"`
Name string `json:"name"`
// Owner is the owning scope as scope:ID; OwnerName how people know it,
// "Acme / hr".
Owner string `json:"owner"`
OwnerName string `json:"owner_name,omitempty"`
EmbedModel string `json:"embed_model"`
Dims int `json:"dims"`
// Writable is whether this caller may add and remove documents.
@@ -119,9 +122,9 @@ func (r *Router) kbCaller(w http.ResponseWriter, req *http.Request) (auth.Princi
return p, e, true
}
func kbView(c storepkg.KBCollection, writable bool) KBCollectionView {
func (r *Router) kbView(ctx context.Context, c storepkg.KBCollection, writable bool) KBCollectionView {
return KBCollectionView{ID: c.ID, Name: c.Name, Owner: string(c.OwnerScope) + ":" + c.OwnerID,
EmbedModel: c.EmbedModel, Dims: c.Dims, Writable: writable}
OwnerName: r.store.OwnerName(ctx, c.OwnerScope, c.OwnerID), EmbedModel: c.EmbedModel, Dims: c.Dims, Writable: writable}
}
// kbCollection finds a collection by id or name among those the caller may
@@ -172,7 +175,7 @@ func (r *Router) handleKBCollections(w http.ResponseWriter, req *http.Request) {
}
out := []KBCollectionView{}
for _, c := range read {
out = append(out, kbView(c, writable[c.ID]))
out = append(out, r.kbView(req.Context(), c, writable[c.ID]))
}
writeJSON(w, http.StatusOK, map[string]any{"object": "list", "data": out})
}
@@ -192,7 +195,7 @@ func (r *Router) handleKBManifest(w http.ResponseWriter, req *http.Request) {
return
}
writable, _ := r.store.CollectionsFor(req.Context(), e, true)
m := KBManifest{Collection: kbView(c, containsCollection(writable, c.ID)), Documents: []KBDocumentView{}}
m := KBManifest{Collection: r.kbView(req.Context(), c, containsCollection(writable, c.ID)), Documents: []KBDocumentView{}}
for _, d := range docs {
m.Documents = append(m.Documents, KBDocumentView{Name: d.Name, Digest: d.Digest, Bytes: d.Bytes,
Chunks: d.Chunks, AddedAt: d.AddedAt})
+1 -1
View File
@@ -138,7 +138,7 @@ func TestKnowledgeBasesKeepTenantsApart(t *testing.T) {
t.Errorf("read grant, put: %d", code)
}
if code, _, body := call(t, h, salesKey, http.MethodGet, "/v1/kb/collections", nil); code != http.StatusOK ||
!strings.Contains(body, "politikalar") {
!strings.Contains(body, "politikalar") || !strings.Contains(body, `"owner_name":"a-`+sfx+` / t / hr"`) {
t.Errorf("read grant, list: %d %s", code, body)
}
if _, _, body := call(t, h, otherKey, http.MethodGet, "/v1/kb/collections", nil); strings.Contains(body, "politikalar") {
+24
View File
@@ -893,3 +893,27 @@ func (s *DB) kbDropPartition(ctx context.Context, c conn, scope Scope, id string
_, err := c.ExecContext(ctx, `DROP TABLE IF EXISTS `+kbPartition(id))
return err
}
// OwnerName is how people know a collection's owner: "Acme / hr", a
// project's path, a person's name. The ID when it cannot be found.
func (s *DB) OwnerName(ctx context.Context, scope Scope, id string) string {
var q string
switch scope {
case ScopeOrg:
q = `SELECT name FROM organizations WHERE id = ?`
case ScopeTeam:
q = `SELECT o.name || ' / ' || t.name FROM teams t JOIN organizations o ON o.id = t.org_id WHERE t.id = ?`
case ScopeProject:
q = `SELECT o.name || ' / ' || t.name || ' / ' || p.name FROM projects p
JOIN teams t ON t.id = p.team_id JOIN organizations o ON o.id = t.org_id WHERE p.id = ?`
case ScopeUser:
q = `SELECT CASE WHEN name <> '' THEN name ELSE email END FROM users WHERE id = ?`
default:
return id
}
var name string
if err := s.db.QueryRowContext(ctx, q, id).Scan(&name); err != nil {
return id
}
return name
}