package io import ( "context" "errors" "strings" "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/config" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory" ) // stubRetriever is a fake KnowledgeRetriever for testing knowledge responses. type stubRetriever struct { results []memory.Result err error } func (s *stubRetriever) Retrieve(ctx context.Context, personaID, query string, topK int) ([]memory.Result, error) { _ = ctx return s.results, s.err } // knowledgeToolForTest builds a tools set with opts and returns the knowledge // tool. func knowledgeToolForTest(t *testing.T, opts ...Option) *knowledgeTool { t.Helper() return findTool(t, buildTools(t, &config.Config{}, opts...), "knowledge").(*knowledgeTool) } func TestKnowledge_NoKnowledgeBase(t *testing.T) { t.Parallel() kt := knowledgeToolForTest(t) // no retriever wired _, err := kt.Execute(context.Background(), map[string]any{"query": "cyrene"}) if err == nil || !strings.Contains(err.Error(), "no knowledge base") { t.Fatalf("expected no-knowledge-base error, got %v", err) } } func TestKnowledge_ReturnsResults(t *testing.T) { t.Parallel() sr := &stubRetriever{results: []memory.Result{ {Item: memory.MemoryItem{ID: "1", Content: "Cyrene 是主人", Kind: memory.KindWorldEvent, Scope: memory.ScopeProject}, Score: 0.9}, }} kt := knowledgeToolForTest(t, WithKnowledgeRetriever(sr)) got, err := kt.Execute(context.Background(), map[string]any{"query": "cyrene", "persona": "p1", "top_k": 5}) if err != nil { t.Fatalf("Execute: %v", err) } m := got.(map[string]any) if m["count"].(int) != 1 { t.Fatalf("count = %v", m["count"]) } results := m["results"].([]map[string]any) if results[0]["content"] != "Cyrene 是主人" { t.Fatalf("content = %v", results[0]["content"]) } if results[0]["kind"] != "world_event" { t.Fatalf("kind = %v", results[0]["kind"]) } } func TestKnowledge_EmptyResults(t *testing.T) { t.Parallel() kt := knowledgeToolForTest(t, WithKnowledgeRetriever(&stubRetriever{})) got, err := kt.Execute(context.Background(), map[string]any{"query": "nothing"}) if err != nil { t.Fatalf("Execute: %v", err) } m := got.(map[string]any) if m["count"].(int) != 0 { t.Fatalf("count = %v", m["count"]) } if m["note"] != "no relevant knowledge found" { t.Fatalf("note = %v", m["note"]) } if _, ok := m["results"].([]map[string]any); !ok { t.Fatalf("results absent or wrong type: %T", m["results"]) } } func TestKnowledge_RetrieverError(t *testing.T) { t.Parallel() kt := knowledgeToolForTest(t, WithKnowledgeRetriever(&stubRetriever{err: errors.New("boom")})) _, err := kt.Execute(context.Background(), map[string]any{"query": "x"}) if err == nil || !strings.Contains(err.Error(), "retrieve") { t.Fatalf("expected retrieve error, got %v", err) } } func TestKnowledge_MissingQuery(t *testing.T) { t.Parallel() kt := knowledgeToolForTest(t, WithKnowledgeRetriever(&stubRetriever{})) _, err := kt.Execute(context.Background(), map[string]any{}) if err == nil || !strings.Contains(err.Error(), "query is required") { t.Fatalf("expected query-required error, got %v", err) } }