package rag import ( "context" "path/filepath" "testing" "git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/settings" "git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/store" core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git" ) // EXT-8 余项红/绿:向量通道共享——他人 owner 的向量命中经 allow 放行可检。 // 用 hash 档 embedder(确定性向量),owner=alice 建项目知识并嵌入;bob 经 // RetrieveShared 放行后命中(含 vector Kind),拒绝时零命中。 func TestRetrieveSharedVectorChannel(t *testing.T) { st, err := store.OpenSQLite(filepath.Join(t.TempDir(), "t.db")) if err != nil { t.Fatal(err) } t.Cleanup(func() { st.Close() }) set := settings.NewService(st) p := NewPipeline(st, set, nil, nil) p.SetEmbedder(SwitchingEmbedder{Provider: func() string { return "hash" }}) docs := []core.KnowledgeDoc{{Owner: "alice", ProjectID: "prj-s", Source: "plugin:rdm", Ref: "kb-v", Chunk: "向量共享独占词"}} // 只走管线写入(分块行+向量一体;不再手工 AddKnowledge 避免主键冲突)。 if err := indexForTest(t, st, p, docs); err != nil { t.Fatal(err) } allow := func(docOwner, projectID core.ID) bool { return docOwner == "alice" && projectID == "prj-s" } hits, err := p.RetrieveShared(context.Background(), "bob", core.RetrievalQuery{Text: "向量共享独占词", TopK: 5}, allow) if err != nil { t.Fatal(err) } if len(hits) == 0 { t.Fatal("authorized shared vector hit must be retrievable(向量通道共享)") } deny := func(docOwner, projectID core.ID) bool { return false } if hits2, _ := p.RetrieveShared(context.Background(), "bob", core.RetrievalQuery{Text: "向量共享独占词", TopK: 5}, deny); len(hits2) != 0 { t.Fatalf("denied shared search = %d hits, want 0", len(hits2)) } } // indexForTest:把 docs 直接嵌入并落向量(复用管线的公开写入路径)。 func indexForTest(t *testing.T, st *store.Store, p *Pipeline, docs []core.KnowledgeDoc) error { t.Helper() return p.IndexChunks(context.Background(), "alice", docs) }