Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
topology_chaos_test.go24.7 kB
package inference import ( "context" "fmt" "math" "math/rand" "sync" "testing" "github.com/orneryd/nornicdb/pkg/storage" ) // ============================================================================= // CHAOS TESTS - Stress tests with random/adversarial inputs // ============================================================================= // TestTopologyChaosRandomGraph tests topology integration on random graphs. func TestTopologyChaosRandomGraph(t *testing.T) { sizes := []int{10, 50, 100} densities := []float64{0.1, 0.3, 0.5} for _, size := range sizes { for _, density := range densities { name := fmt.Sprintf("size_%d_density_%.1f", size, density) t.Run(name, func(t *testing.T) { engine := buildRandomStorageGraph(size, density, 42) config := &TopologyConfig{ Enabled: true, Algorithm: "adamic_adar", TopK: 10, MinScore: 0.0, Weight: 0.5, GraphRefreshInterval: 50, } topo := NewTopologyIntegration(engine, config) // Test all algorithms algorithms := []string{ "adamic_adar", "jaccard", "common_neighbors", "resource_allocation", "preferential_attachment", } for _, algo := range algorithms { t.Run(algo, func(t *testing.T) { topo.config.Algorithm = algo // Pick a random node sourceID := fmt.Sprintf("node-%d", rand.Intn(size)) defer func() { if r := recover(); r != nil { t.Errorf("%s panicked: %v", algo, r) } }() suggestions, err := topo.SuggestTopological(context.Background(), sourceID) if err != nil { t.Errorf("%s failed: %v", algo, err) return } // Verify suggestions are valid for _, sug := range suggestions { if sug.Confidence < 0 || sug.Confidence > 1 { t.Errorf("Confidence out of range: %.3f", sug.Confidence) } if sug.SourceID != sourceID { t.Errorf("Wrong source: %s != %s", sug.SourceID, sourceID) } } }) } }) } } } // TestTopologyChaosStarTopology tests with hub-and-spoke pattern. func TestTopologyChaosStarTopology(t *testing.T) { engine := storage.NewMemoryEngine() // Create hub engine.CreateNode(&storage.Node{ID: "hub", Labels: []string{"Hub"}}) // Create 100 spokes for i := 0; i < 100; i++ { nodeID := storage.NodeID(fmt.Sprintf("spoke-%d", i)) engine.CreateNode(&storage.Node{ID: nodeID, Labels: []string{"Spoke"}}) engine.CreateEdge(&storage.Edge{ ID: storage.EdgeID(fmt.Sprintf("e-%d", i)), StartNode: "hub", EndNode: nodeID, Type: "CONNECTS", }) } config := DefaultTopologyConfig() config.Enabled = true config.MinScore = 0.0 topo := NewTopologyIntegration(engine, config) // Hub should have no predictions (connected to everyone) hubSuggestions, err := topo.SuggestTopological(context.Background(), "hub") if err != nil { t.Fatalf("Hub prediction failed: %v", err) } t.Logf("Hub predictions: %d", len(hubSuggestions)) // Spoke should predict other spokes spokeSuggestions, err := topo.SuggestTopological(context.Background(), "spoke-0") if err != nil { t.Fatalf("Spoke prediction failed: %v", err) } // Should have many suggestions (all other spokes via hub) if len(spokeSuggestions) == 0 { t.Error("Expected spoke to predict other spokes") } else { t.Logf("Spoke-0 predictions: %d", len(spokeSuggestions)) // Scores should be low (hub has high degree in Adamic-Adar) displayCount := 5 if len(spokeSuggestions) < displayCount { displayCount = len(spokeSuggestions) } for _, sug := range spokeSuggestions[:displayCount] { t.Logf(" %s: %.4f", sug.TargetID, sug.Confidence) } } } // TestTopologyChaosCliqueTopology tests with fully connected graph. func TestTopologyChaosCliqueTopology(t *testing.T) { engine := storage.NewMemoryEngine() // Create clique of 10 nodes for i := 0; i < 10; i++ { engine.CreateNode(&storage.Node{ID: storage.NodeID(fmt.Sprintf("n%d", i))}) } // Connect everyone to everyone edgeCount := 0 for i := 0; i < 10; i++ { for j := i + 1; j < 10; j++ { engine.CreateEdge(&storage.Edge{ ID: storage.EdgeID(fmt.Sprintf("e-%d", edgeCount)), StartNode: storage.NodeID(fmt.Sprintf("n%d", i)), EndNode: storage.NodeID(fmt.Sprintf("n%d", j)), Type: "CONNECTS", }) edgeCount++ } } config := DefaultTopologyConfig() config.Enabled = true topo := NewTopologyIntegration(engine, config) // In a clique, no predictions should exist (everyone is connected) suggestions, err := topo.SuggestTopological(context.Background(), "n0") if err != nil { t.Fatalf("Clique prediction failed: %v", err) } if len(suggestions) != 0 { t.Errorf("Expected no predictions in clique, got %d", len(suggestions)) } } // TestTopologyChaosEmptyGraph tests with empty storage. func TestTopologyChaosEmptyGraph(t *testing.T) { engine := storage.NewMemoryEngine() config := DefaultTopologyConfig() config.Enabled = true topo := NewTopologyIntegration(engine, config) suggestions, err := topo.SuggestTopological(context.Background(), "nonexistent") if err != nil { t.Logf("Empty graph error (expected): %v", err) } if len(suggestions) != 0 { t.Errorf("Expected no predictions for empty graph, got %d", len(suggestions)) } } // TestTopologyChaosDisabled tests behavior when disabled. func TestTopologyChaosDisabled(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) config := DefaultTopologyConfig() config.Enabled = false // Disabled topo := NewTopologyIntegration(engine, config) suggestions, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Disabled topology failed: %v", err) } if len(suggestions) != 0 { t.Errorf("Expected no predictions when disabled, got %d", len(suggestions)) } } // TestTopologyChaosConcurrent tests thread safety. func TestTopologyChaosConcurrent(t *testing.T) { engine := buildRandomStorageGraph(100, 0.3, 42) config := DefaultTopologyConfig() config.Enabled = true config.GraphRefreshInterval = 10 topo := NewTopologyIntegration(engine, config) var wg sync.WaitGroup errChan := make(chan error, 100) // 100 concurrent predictions for i := 0; i < 100; i++ { wg.Add(1) go func(idx int) { defer wg.Done() defer func() { if r := recover(); r != nil { errChan <- fmt.Errorf("panic: %v", r) } }() sourceID := fmt.Sprintf("node-%d", idx%100) _, err := topo.SuggestTopological(context.Background(), sourceID) if err != nil { errChan <- err } }(i) } wg.Wait() close(errChan) for err := range errChan { t.Error(err) } } // TestTopologyChaosRapidCacheInvalidation tests rapid cache operations. func TestTopologyChaosRapidCacheInvalidation(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) config := DefaultTopologyConfig() config.Enabled = true config.GraphRefreshInterval = 1 // Rebuild every prediction topo := NewTopologyIntegration(engine, config) // Rapidly make predictions and invalidate cache for i := 0; i < 100; i++ { _, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Prediction %d failed: %v", i, err) } if i%10 == 0 { topo.InvalidateCache() } } } // ============================================================================= // COMPLEX USAGE TESTS // ============================================================================= // TestTopologyComplexMultiLayerNetwork tests with multi-relationship graph. func TestTopologyComplexMultiLayerNetwork(t *testing.T) { engine := storage.NewMemoryEngine() // Create users users := []string{"alice", "bob", "charlie", "diana", "eve", "frank"} for _, u := range users { engine.CreateNode(&storage.Node{ID: storage.NodeID(u), Labels: []string{"Person"}}) } // Multiple relationship types relationships := []struct { from, to, relType string }{ // Friendship layer {"alice", "bob", "FRIENDS"}, {"alice", "charlie", "FRIENDS"}, {"bob", "diana", "FRIENDS"}, {"charlie", "diana", "FRIENDS"}, // Work layer {"alice", "eve", "WORKS_WITH"}, {"eve", "frank", "WORKS_WITH"}, {"bob", "frank", "WORKS_WITH"}, // Family layer {"charlie", "eve", "FAMILY"}, } for i, rel := range relationships { engine.CreateEdge(&storage.Edge{ ID: storage.EdgeID(fmt.Sprintf("e%d", i)), StartNode: storage.NodeID(rel.from), EndNode: storage.NodeID(rel.to), Type: rel.relType, }) } config := DefaultTopologyConfig() config.Enabled = true config.TopK = 10 config.MinScore = 0.0 topo := NewTopologyIntegration(engine, config) // Test predictions for alice suggestions, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Multi-layer prediction failed: %v", err) } t.Logf("Alice multi-layer predictions: %d", len(suggestions)) for _, sug := range suggestions { t.Logf(" alice -> %s: %.4f (%s)", sug.TargetID, sug.Confidence, sug.Method) } // Diana should be highly ranked (via bob and charlie) foundDiana := false for _, sug := range suggestions { if sug.TargetID == "diana" { foundDiana = true break } } if !foundDiana { t.Error("Expected diana in predictions") } } // TestTopologyComplexInferenceEngineIntegration tests full Engine integration. func TestTopologyComplexInferenceEngineIntegration(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) // Create inference engine inferConfig := DefaultConfig() inferConfig.SimilarityThreshold = 0.3 inferEngine := New(inferConfig) // Mock semantic search inferEngine.SetSimilaritySearch(func(ctx context.Context, embedding []float32, k int) ([]SimilarityResult, error) { return []SimilarityResult{ {ID: "diana", Score: 0.85}, {ID: "eve", Score: 0.45}, }, nil }) // Enable topology integration topoConfig := DefaultTopologyConfig() topoConfig.Enabled = true topoConfig.Weight = 0.4 // 40% topology, 60% semantic topo := NewTopologyIntegration(engine, topoConfig) inferEngine.SetTopologyIntegration(topo) // Test OnStore with both semantic and topology suggestions, err := inferEngine.OnStore(context.Background(), "alice", []float32{1, 2, 3}) if err != nil { t.Fatalf("OnStore failed: %v", err) } t.Logf("Integrated suggestions: %d", len(suggestions)) for _, sug := range suggestions { t.Logf(" %s: %.3f (%s)", sug.TargetID, sug.Confidence, sug.Method) } // Verify diana appears with combined score foundDiana := false for _, sug := range suggestions { if sug.TargetID == "diana" { foundDiana = true // Should have semantic contribution if sug.Confidence < 0.5 { t.Logf("Diana confidence: %.3f", sug.Confidence) } } } if !foundDiana { t.Error("Expected diana in combined suggestions") } } // TestTopologyComplexCombinedSuggestions tests merging semantic + topological. func TestTopologyComplexCombinedSuggestions(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) config := DefaultTopologyConfig() config.Enabled = true config.Weight = 0.5 // Equal weight topo := NewTopologyIntegration(engine, config) // Mock semantic suggestions semantic := []EdgeSuggestion{ {SourceID: "alice", TargetID: "diana", Confidence: 0.9, Method: "similarity"}, {SourceID: "alice", TargetID: "eve", Confidence: 0.7, Method: "similarity"}, {SourceID: "alice", TargetID: "frank", Confidence: 0.5, Method: "similarity"}, } // Get topological suggestions topological, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Topological failed: %v", err) } // Combine combined := topo.CombinedSuggestions(semantic, topological) t.Logf("Combined suggestions: %d", len(combined)) for _, sug := range combined { t.Logf(" %s: %.3f (%s)", sug.TargetID, sug.Confidence, sug.Method) } // Verify diana has boosted score for _, sug := range combined { if sug.TargetID == "diana" { // Diana appears in both, should have combined score if sug.Confidence < 0.4 { // weighted: 0.9*0.5 = 0.45 minimum t.Errorf("Diana combined score too low: %.3f", sug.Confidence) } } } // Verify sorted descending for i := 1; i < len(combined); i++ { if combined[i].Confidence > combined[i-1].Confidence { t.Error("Combined suggestions not sorted") } } } // TestTopologyComplexAlgorithmComparison tests all algorithms on same graph. func TestTopologyComplexAlgorithmComparison(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) algorithms := []string{ "adamic_adar", "jaccard", "common_neighbors", "resource_allocation", "preferential_attachment", "unknown", // Should default to adamic_adar } for _, algo := range algorithms { t.Run(algo, func(t *testing.T) { config := DefaultTopologyConfig() config.Enabled = true config.Algorithm = algo config.MinScore = 0.0 topo := NewTopologyIntegration(engine, config) suggestions, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("%s failed: %v", algo, err) } t.Logf("%s: %d suggestions", algo, len(suggestions)) for _, sug := range suggestions { t.Logf(" %s: %.4f", sug.TargetID, sug.Confidence) } // Verify method tag for _, sug := range suggestions { expectedMethod := "topology_" + algo if algo == "unknown" { expectedMethod = "topology_adamic_adar" // Default } if sug.Method != expectedMethod { t.Errorf("Wrong method: %s != %s", sug.Method, expectedMethod) } } }) } } // TestTopologyComplexCacheLifecycle tests full cache lifecycle. func TestTopologyComplexCacheLifecycle(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) config := DefaultTopologyConfig() config.Enabled = true config.GraphRefreshInterval = 3 topo := NewTopologyIntegration(engine, config) // Initially no cache if topo.cachedGraph != nil { t.Error("Cache should be nil initially") } // First prediction builds cache _, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("First prediction failed: %v", err) } if topo.cachedGraph == nil { t.Error("Cache should be built after first prediction") } if topo.predictionCount != 1 { t.Errorf("Prediction count should be 1, got %d", topo.predictionCount) } // Second and third predictions use cache for i := 0; i < 2; i++ { _, err = topo.SuggestTopological(context.Background(), "bob") if err != nil { t.Fatalf("Prediction %d failed: %v", i+2, err) } } if topo.predictionCount != 3 { t.Errorf("Prediction count should be 3, got %d", topo.predictionCount) } // Fourth prediction triggers rebuild (interval = 3) _, err = topo.SuggestTopological(context.Background(), "charlie") if err != nil { t.Fatalf("Fourth prediction failed: %v", err) } if topo.predictionCount != 1 { t.Errorf("Prediction count should reset to 1, got %d", topo.predictionCount) } // Manual invalidation topo.InvalidateCache() if topo.cachedGraph != nil { t.Error("Cache should be nil after invalidation") } if topo.predictionCount != 0 { t.Error("Prediction count should be 0 after invalidation") } } // TestTopologyComplexMinScoreFiltering tests minimum score threshold. func TestTopologyComplexMinScoreFiltering(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) thresholds := []float64{0.0, 0.3, 0.5, 0.7, 0.9, 1.0} for _, threshold := range thresholds { t.Run(fmt.Sprintf("threshold_%.1f", threshold), func(t *testing.T) { config := DefaultTopologyConfig() config.Enabled = true config.MinScore = threshold topo := NewTopologyIntegration(engine, config) suggestions, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Prediction failed: %v", err) } t.Logf("Threshold %.1f: %d suggestions", threshold, len(suggestions)) // All suggestions should meet threshold for _, sug := range suggestions { if sug.Confidence < threshold { t.Errorf("Suggestion %.3f below threshold %.1f", sug.Confidence, threshold) } } }) } } // TestTopologyComplexWeightConfiguration tests weight configuration. func TestTopologyComplexWeightConfiguration(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) weights := []float64{0.0, 0.25, 0.5, 0.75, 1.0} for _, weight := range weights { t.Run(fmt.Sprintf("weight_%.2f", weight), func(t *testing.T) { config := DefaultTopologyConfig() config.Enabled = true config.Weight = weight topo := NewTopologyIntegration(engine, config) // Mock semantic and topological suggestions semantic := []EdgeSuggestion{ {TargetID: "diana", Confidence: 0.8, Method: "similarity"}, } topological, err := topo.SuggestTopological(context.Background(), "alice") if err != nil { t.Fatalf("Topological failed: %v", err) } combined := topo.CombinedSuggestions(semantic, topological) for _, sug := range combined { if sug.TargetID == "diana" { // Semantic contribution: 0.8 * (1 - weight) // Topology contribution: topoScore * weight t.Logf("Weight %.2f: diana = %.3f", weight, sug.Confidence) } } }) } } // TestTopologyComplexProcessSuggestionIntegration tests ProcessSuggestion with topology. func TestTopologyComplexProcessSuggestionIntegration(t *testing.T) { engine := storage.NewMemoryEngine() setupTestGraph(t, engine) // Create inference engine with all features inferEngine := New(DefaultConfig()) // Enable topology topoConfig := DefaultTopologyConfig() topoConfig.Enabled = true topo := NewTopologyIntegration(engine, topoConfig) inferEngine.SetTopologyIntegration(topo) // Create a suggestion that would come from topology suggestion := EdgeSuggestion{ SourceID: "alice", TargetID: "diana", Type: "RELATES_TO", Confidence: 0.8, Method: "topology_adamic_adar", } // Process the suggestion result := inferEngine.ProcessSuggestion(suggestion, "session-1") t.Logf("ProcessSuggestion result: materialize=%v, reason=%s", result.ShouldMaterialize, result.Reason) // Without evidence/cooldown enabled, should materialize if !result.ShouldMaterialize { t.Logf("Note: suggestion not materialized (evidence/cooldown may be enabled)") } } // ============================================================================= // HELPER FUNCTIONS // ============================================================================= // buildRandomStorageGraph creates a random graph in storage. func buildRandomStorageGraph(nodes int, density float64, seed int64) storage.Engine { r := rand.New(rand.NewSource(seed)) engine := storage.NewMemoryEngine() // Create nodes for i := 0; i < nodes; i++ { engine.CreateNode(&storage.Node{ ID: storage.NodeID(fmt.Sprintf("node-%d", i)), Labels: []string{"Test"}, }) } // Create random edges edgeCount := 0 for i := 0; i < nodes; i++ { for j := i + 1; j < nodes; j++ { if r.Float64() < density { engine.CreateEdge(&storage.Edge{ ID: storage.EdgeID(fmt.Sprintf("e-%d", edgeCount)), StartNode: storage.NodeID(fmt.Sprintf("node-%d", i)), EndNode: storage.NodeID(fmt.Sprintf("node-%d", j)), Type: "CONNECTS", }) edgeCount++ } } } return engine } // TestTopologyMathHelpers tests that math.Tanh, math.Exp, math.Log10 work as expected. // This is mostly a sanity check that the standard library behaves correctly. func TestTopologyMathHelpers(t *testing.T) { // Test math.Tanh - used in normalizeScore for adamic_adar/resource_allocation tanhTests := []struct { input float64 expected float64 delta float64 }{ {0, 0, 0.001}, {1, 0.761594, 0.001}, {-1, -0.761594, 0.001}, {20, 1.0, 0.0001}, {-20, -1.0, 0.0001}, {100, 1.0, 0.0001}, {-100, -1.0, 0.0001}, } for _, tc := range tanhTests { result := math.Tanh(tc.input) if result < tc.expected-tc.delta || result > tc.expected+tc.delta { t.Errorf("math.Tanh(%.1f) = %.6f, expected %.6f", tc.input, result, tc.expected) } } // Test math.Exp - used for various calculations expTests := []struct { input float64 expected float64 delta float64 }{ {0, 1, 0.0001}, {1, 2.71828, 0.001}, {-1, 0.367879, 0.001}, {2, 7.38906, 0.001}, } for _, tc := range expTests { result := math.Exp(tc.input) if result < tc.expected-tc.delta || result > tc.expected+tc.delta { t.Errorf("math.Exp(%.1f) = %.6f, expected %.6f", tc.input, result, tc.expected) } } // Test math.Log10 - used in normalizeScore for preferential_attachment log10Tests := []struct { input float64 expected float64 delta float64 }{ {1, 0, 0.001}, {10, 1, 0.001}, {100, 2, 0.001}, {1000, 3, 0.001}, } for _, tc := range log10Tests { result := math.Log10(tc.input) if result < tc.expected-tc.delta || result > tc.expected+tc.delta { t.Errorf("math.Log10(%.1f) = %.6f, expected %.6f", tc.input, result, tc.expected) } } // Verify edge cases for Log10 (negative/zero inputs return -Inf or NaN) if !math.IsInf(math.Log10(0), -1) { t.Error("math.Log10(0) should be -Inf") } if !math.IsNaN(math.Log10(-1)) { t.Error("math.Log10(-1) should be NaN") } } // TestTopologySortByConfidence tests the sorting function. func TestTopologySortByConfidence(t *testing.T) { suggestions := []EdgeSuggestion{ {TargetID: "a", Confidence: 0.3}, {TargetID: "b", Confidence: 0.9}, {TargetID: "c", Confidence: 0.1}, {TargetID: "d", Confidence: 0.7}, {TargetID: "e", Confidence: 0.5}, } sortByConfidence(suggestions) // Verify sorted descending for i := 1; i < len(suggestions); i++ { if suggestions[i].Confidence > suggestions[i-1].Confidence { t.Errorf("Not sorted at index %d: %.1f > %.1f", i, suggestions[i].Confidence, suggestions[i-1].Confidence) } } // First should be highest (b = 0.9) if suggestions[0].TargetID != "b" { t.Errorf("First should be 'b', got '%s'", suggestions[0].TargetID) } // Last should be lowest (c = 0.1) if suggestions[len(suggestions)-1].TargetID != "c" { t.Errorf("Last should be 'c', got '%s'", suggestions[len(suggestions)-1].TargetID) } } // TestTopologyNilStorage tests handling of nil storage. func TestTopologyNilStorage(t *testing.T) { config := DefaultTopologyConfig() config.Enabled = true topo := NewTopologyIntegration(nil, config) // Should not panic, should return error or empty suggestions, err := topo.SuggestTopological(context.Background(), "anything") if err == nil && len(suggestions) > 0 { t.Error("Expected error or empty for nil storage") } t.Logf("Nil storage: err=%v, suggestions=%d", err, len(suggestions)) } // BenchmarkTopologyIntegration benchmarks topology integration. func BenchmarkTopologyIntegrationSmall(b *testing.B) { engine := buildRandomStorageGraph(50, 0.3, 42) config := DefaultTopologyConfig() config.Enabled = true topo := NewTopologyIntegration(engine, config) ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { topo.SuggestTopological(ctx, "node-25") } } func BenchmarkTopologyIntegrationMedium(b *testing.B) { engine := buildRandomStorageGraph(200, 0.2, 42) config := DefaultTopologyConfig() config.Enabled = true topo := NewTopologyIntegration(engine, config) ctx := context.Background() b.ResetTimer() for i := 0; i < b.N; i++ { topo.SuggestTopological(ctx, "node-100") } } func BenchmarkTopologyIntegrationCached(b *testing.B) { engine := buildRandomStorageGraph(200, 0.2, 42) config := DefaultTopologyConfig() config.Enabled = true config.GraphRefreshInterval = 1000 // Long cache topo := NewTopologyIntegration(engine, config) // Prime cache ctx := context.Background() topo.SuggestTopological(ctx, "node-0") b.ResetTimer() for i := 0; i < b.N; i++ { topo.SuggestTopological(ctx, "node-100") } } // BenchmarkCombinedSuggestions benchmarks combining suggestions. func BenchmarkCombinedSuggestions(b *testing.B) { config := DefaultTopologyConfig() config.Enabled = true config.Weight = 0.5 topo := NewTopologyIntegration(nil, config) semantic := make([]EdgeSuggestion, 50) topological := make([]EdgeSuggestion, 50) for i := 0; i < 50; i++ { semantic[i] = EdgeSuggestion{ TargetID: fmt.Sprintf("sem-%d", i), Confidence: rand.Float64(), } topological[i] = EdgeSuggestion{ TargetID: fmt.Sprintf("topo-%d", i), Confidence: rand.Float64(), } } b.ResetTimer() for i := 0; i < b.N; i++ { topo.CombinedSuggestions(semantic, topological) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server