99991c52cf
- NewSharedKnowledgeTools genera 4 tools prefijadas shared_knowledge_* - shared_knowledge_search/read/write/list - Descripciones indican que es compartido entre agentes - Tests completos con coexistencia privado/compartido - Issue 0018: Shared Knowledge (fase 2b) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
203 lines
5.6 KiB
Go
203 lines
5.6 KiB
Go
package knowledgetools
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/enmanuel/agents/pkg/knowledge"
|
|
)
|
|
|
|
func TestNewSharedKnowledgeTools(t *testing.T) {
|
|
store := newMockKnowledgeStore()
|
|
tools := NewSharedKnowledgeTools(store)
|
|
|
|
if len(tools) != 4 {
|
|
t.Errorf("expected 4 tools, got %d", len(tools))
|
|
}
|
|
|
|
names := make(map[string]bool)
|
|
for _, tool := range tools {
|
|
names[tool.Def.Name] = true
|
|
}
|
|
|
|
expected := []string{
|
|
"shared_knowledge_search",
|
|
"shared_knowledge_read",
|
|
"shared_knowledge_write",
|
|
"shared_knowledge_list",
|
|
}
|
|
|
|
for _, name := range expected {
|
|
if !names[name] {
|
|
t.Errorf("expected tool %q not found", name)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSharedKnowledgeSearchTool(t *testing.T) {
|
|
store := newMockKnowledgeStore()
|
|
store.docs["shared-doc"] = knowledge.Document{
|
|
Slug: "shared-doc", Title: "Shared Doc", Content: "This is shared knowledge",
|
|
}
|
|
|
|
tools := NewSharedKnowledgeTools(store)
|
|
tool := tools[0] // shared_knowledge_search is first
|
|
|
|
// Missing query
|
|
r := tool.Exec(context.Background(), map[string]any{})
|
|
if r.Err == nil {
|
|
t.Error("expected error for missing query")
|
|
}
|
|
|
|
// Valid search
|
|
r = tool.Exec(context.Background(), map[string]any{"query": "shared"})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if r.Output == "" {
|
|
t.Error("expected non-empty output")
|
|
}
|
|
|
|
// Empty results
|
|
store2 := newMockKnowledgeStore()
|
|
tools2 := NewSharedKnowledgeTools(store2)
|
|
r = tools2[0].Exec(context.Background(), map[string]any{"query": "nothing"})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if r.Output != "no documents found in shared knowledge base matching your query" {
|
|
t.Errorf("expected empty message, got %q", r.Output)
|
|
}
|
|
}
|
|
|
|
func TestSharedKnowledgeReadTool(t *testing.T) {
|
|
store := newMockKnowledgeStore()
|
|
store.docs["shared-doc"] = knowledge.Document{
|
|
Slug: "shared-doc", Title: "Shared", Content: "Shared content",
|
|
}
|
|
|
|
tools := NewSharedKnowledgeTools(store)
|
|
tool := tools[1] // shared_knowledge_read is second
|
|
|
|
// Missing slug
|
|
r := tool.Exec(context.Background(), map[string]any{})
|
|
if r.Err == nil {
|
|
t.Error("expected error for missing slug")
|
|
}
|
|
|
|
// Valid read
|
|
r = tool.Exec(context.Background(), map[string]any{"slug": "shared-doc"})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if r.Output != "Shared content" {
|
|
t.Errorf("output = %q, want %q", r.Output, "Shared content")
|
|
}
|
|
|
|
// Not found
|
|
r = tool.Exec(context.Background(), map[string]any{"slug": "nope"})
|
|
if r.Err == nil {
|
|
t.Error("expected error for nonexistent doc")
|
|
}
|
|
}
|
|
|
|
func TestSharedKnowledgeWriteTool(t *testing.T) {
|
|
store := newMockKnowledgeStore()
|
|
tools := NewSharedKnowledgeTools(store)
|
|
tool := tools[2] // shared_knowledge_write is third
|
|
|
|
// Missing params
|
|
r := tool.Exec(context.Background(), map[string]any{"slug": "test"})
|
|
if r.Err == nil {
|
|
t.Error("expected error for missing content")
|
|
}
|
|
|
|
// Valid write
|
|
r = tool.Exec(context.Background(), map[string]any{
|
|
"slug": "shared-doc",
|
|
"content": "# Shared Doc\nShared by agent A",
|
|
})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if _, ok := store.docs["shared-doc"]; !ok {
|
|
t.Error("document was not stored")
|
|
}
|
|
|
|
// Verify the output message mentions "shared"
|
|
if r.Output != "shared document saved: shared-doc (30 bytes)" {
|
|
t.Errorf("output = %q, want mention of shared", r.Output)
|
|
}
|
|
}
|
|
|
|
func TestSharedKnowledgeListTool(t *testing.T) {
|
|
store := newMockKnowledgeStore()
|
|
tools := NewSharedKnowledgeTools(store)
|
|
tool := tools[3] // shared_knowledge_list is fourth
|
|
|
|
// Empty
|
|
r := tool.Exec(context.Background(), map[string]any{})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if r.Output != "shared knowledge base is empty" {
|
|
t.Errorf("expected empty message, got %q", r.Output)
|
|
}
|
|
|
|
// With docs
|
|
store.docs["shared-doc1"] = knowledge.Document{Slug: "shared-doc1", Title: "Shared 1"}
|
|
r = tool.Exec(context.Background(), map[string]any{})
|
|
if r.Err != nil {
|
|
t.Errorf("unexpected error: %v", r.Err)
|
|
}
|
|
if r.Output == "shared knowledge base is empty" {
|
|
t.Error("expected non-empty output after adding docs")
|
|
}
|
|
}
|
|
|
|
// TestSharedAndPrivateCoexist verifies that shared and private tools can coexist
|
|
// with different stores and don't interfere with each other.
|
|
func TestSharedAndPrivateCoexist(t *testing.T) {
|
|
privateStore := newMockKnowledgeStore()
|
|
sharedStore := newMockKnowledgeStore()
|
|
|
|
// Write to private store
|
|
privateStore.docs["private-doc"] = knowledge.Document{
|
|
Slug: "private-doc", Title: "Private", Content: "Private content",
|
|
}
|
|
|
|
// Write to shared store
|
|
sharedStore.docs["shared-doc"] = knowledge.Document{
|
|
Slug: "shared-doc", Title: "Shared", Content: "Shared content",
|
|
}
|
|
|
|
// Verify private has only private doc
|
|
privateDocs, _ := privateStore.List(context.Background())
|
|
if len(privateDocs) != 1 || privateDocs[0].Slug != "private-doc" {
|
|
t.Error("private store should only have private doc")
|
|
}
|
|
|
|
// Verify shared has only shared doc
|
|
sharedDocs, _ := sharedStore.List(context.Background())
|
|
if len(sharedDocs) != 1 || sharedDocs[0].Slug != "shared-doc" {
|
|
t.Error("shared store should only have shared doc")
|
|
}
|
|
|
|
// Verify tools from different stores don't mix data
|
|
privateTool := NewKnowledgeRead(privateStore)
|
|
sharedTools := NewSharedKnowledgeTools(sharedStore)
|
|
sharedTool := sharedTools[1] // shared_knowledge_read
|
|
|
|
// Private tool can't read shared doc
|
|
r := privateTool.Exec(context.Background(), map[string]any{"slug": "shared-doc"})
|
|
if r.Err == nil {
|
|
t.Error("private tool should not be able to read shared doc")
|
|
}
|
|
|
|
// Shared tool can't read private doc
|
|
r = sharedTool.Exec(context.Background(), map[string]any{"slug": "private-doc"})
|
|
if r.Err == nil {
|
|
t.Error("shared tool should not be able to read private doc")
|
|
}
|
|
}
|