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:
1 parent
496625824b
commit
54ba04c52a
5 files changed
+36
-8
No files matched your search
@@ -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()
|
||||
},
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user