from dataclasses import dataclass, field from typing import Any, Dict, List from unittest.mock import patch import numpy as np import pytest from semantica.context.agent_context import AgentContext from semantica.context.agent_memory import AgentMemory from semantica.context.context_graph import ContextGraph from semantica.context.context_retriever import ContextRetriever, RetrievedContext from semantica.context.entity_linker import EntityLinker # Infra class NullTracker: """ Stateless dummy tracker. """ def start_tracking(self, *args, **kwargs): return "dummy_id" def update_tracking(self, *args, **kwargs): pass def stop_tracking(self, *args, **kwargs): pass def register_pipeline_modules(self, *args, **kwargs): pass def clear_pipeline_context(self, *args, **kwargs): pass def update_progress(self, *args, **kwargs): pass @property def enabled(self): return False @enabled.setter def enabled(self, value): pass # ~~ MOCK STORES ~~ class MockVectorStore: """ A feather VectorStore sim that does no math. We want to measure the MANAGER overhead. """ def __init__(self): self.vectors = {} self.dim = 384 def embed(self, text): return np.random.rand(self.dim).tolist() def add(self, items): for item in items: self.vectors[item.memory_id] = item def search(self, query, limit=5): class MockResult: def __init__(self, i): self.id = f"mem_{i}" self.content = f"Content for result {i} matching {query[:10]}" self.score = 0.9 - (i * 0.05) self.metadata = {"type": "test"} return [MockResult(i) for i in range(limit)] def create_dense_graph(node_count): """ Creates a ContextGraph with 'Small World' Topology. Used to stress-test BFS traversal scaling. """ graph = ContextGraph() graph.progress_tracker = NullTracker() # Create nodes nodes = [ { "id": f"node_{i}", "type": "concept", "properties": {"content": f"Concept {i}"}, } for i in range(node_count) ] graph.add_nodes(nodes) # Create Edges (Chain + Hub + Random) edges = [] for i in range(node_count): # Chain if i < node_count - 1: edges.append( {"source_id": f"node_{i}", "target_id": f"node_{i+1}", "type": "next"} ) # Hub if i > 0: edges.append( {"source_id": "node_0", "target_id": f"node_{i}", "type": "hub_link"} ) # Rando if i % 5 == 0 and i + 5 < node_count: edges.append( { "source_id": f"node_{i}", "target_id": f"node_{i+5}", "type": "cross_link", } ) graph.add_edges(edges) return graph def create_populated_memory(item_count): """Creates an AgentMemory populated with N items.""" vs = MockVectorStore() memory = AgentMemory(vector_store=vs) memory.progress_tracker = NullTracker() for i in range(item_count): mem_id = f"setup_mem_{i}" from datetime import datetime from semantica.context.agent_memory import MemoryItem memory.memory_items[mem_id] = MemoryItem( content=f"History item {i}", timestamp=datetime.now(), memory_id=mem_id, metadata={"type": "chat"}, ) memory.memory_index.append(mem_id) return memory # ~~ BENCHMARKS ~~ @pytest.mark.parametrize("graph_size", [100, 1000]) @pytest.mark.parametrize("hops", [1, 2]) def test_graph_traversal_scaling(benchmark, graph_size, hops): """ Measures 'Hop Explosion' effect. Retrieving multi-hop neighbors on a dense graph. """ graph = create_dense_graph(graph_size) def op(): # Start from'Hub' node which's celebrity, meaning # connected to everyone return graph.get_neighbors("node_0", hops=hops) benchmark.pedantic(op, iterations=5, rounds=5) @pytest.mark.parametrize("memory_count", [100, 1000]) def test_retriever_ranking_throughput(benchmark, memory_count): """ Measures CPU cost of merging and ranking results. """ retriever = ContextRetriever( vector_store=MockVectorStore(), memory_store=create_populated_memory(10), knowledge_graph=None, hybrid_alpha=0.5, ) retriever.progress_tracker = NullTracker() results = [] for i in range(memory_count): results.append( RetrievedContext( content=f"Vector Item {i}", score=np.random.random(), source=f"vector:{i}", ) ) results.append( RetrievedContext( content=f"Graph Item {i}", score=np.random.random(), source=f"graph:{i}", metadata={"node_id": f"node_{i}"}, ) ) def op(): return retriever._rank_and_merge(results, "query context") benchmark.pedantic(op, iterations=5, rounds=10) @pytest.mark.parametrize("registry_size", [100, 1000]) def test_entity_linking_speed(benchmark, registry_size): """ Measures O(N) linear scan speed in `find_similar_entities`. """ linker = EntityLinker() linker.progress_tracker = NullTracker() mock_kg = {"entities": []} for i in range(registry_size): mock_kg["entities"].append( {"id": f"ent_{i}", "text": f"Entity Number {i}", "type": "TEST"} ) linker.knowledge_graph = mock_kg input_text = "I am looking for Entity Number 50 in the database." def op(): return linker.find_similar_entities(input_text, threshold=0.1) benchmark.pedantic(op, iterations=5, rounds=5) @pytest.mark.parametrize("batch_size", [1, 10, 50]) def test_agent_store_throughput(benchmark, batch_size): """ 'store' pipeline test. """ vs = MockVectorStore() context = AgentContext(vector_store=vs) context._memory.progress_tracker = NullTracker() inputs = [f"Memory item {i} for storage test" for i in range(batch_size)] def op(): return context.batch_store(inputs) benchmark.pedantic(op, iterations=5, rounds=5)