mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-29 04:26:20 +00:00
188 lines
6.2 KiB
Python
188 lines
6.2 KiB
Python
import sys
|
|
import os
|
|
from typing import List, Dict, Any, Optional
|
|
from dataclasses import dataclass, field
|
|
|
|
import pytest
|
|
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
from semantica.context import AgentContext, ContextGraph
|
|
|
|
pytestmark = pytest.mark.integration
|
|
|
|
@dataclass
|
|
class VectorSearchResult:
|
|
id: str
|
|
content: str
|
|
score: float
|
|
metadata: Dict[str, Any]
|
|
|
|
class MockVectorStore:
|
|
def __init__(self):
|
|
self.items: Dict[str, Any] = {}
|
|
|
|
def add(self, items: List[Any]) -> List[str]:
|
|
ids = []
|
|
for item in items:
|
|
# Simple ID generation if not present
|
|
if not item.memory_id:
|
|
item.memory_id = f"mem_{len(self.items)}"
|
|
self.items[item.memory_id] = item
|
|
ids.append(item.memory_id)
|
|
print(f"MockVectorStore: Added {len(ids)} items")
|
|
return ids
|
|
|
|
def search(
|
|
self,
|
|
query: str,
|
|
limit: int = 10,
|
|
filters: Optional[Dict[str, Any]] = None
|
|
) -> List[VectorSearchResult]:
|
|
print(f"MockVectorStore: Searching for '{query}'")
|
|
results = []
|
|
# Simple keyword match simulation
|
|
query_terms = query.lower().split()
|
|
for item in self.items.values():
|
|
if any(term in item.content.lower() for term in query_terms):
|
|
results.append(VectorSearchResult(
|
|
id=item.memory_id,
|
|
content=item.content,
|
|
score=0.8,
|
|
metadata=item.metadata
|
|
))
|
|
return results[:limit]
|
|
|
|
def delete(self, ids: List[str]) -> bool:
|
|
count = 0
|
|
for mid in ids:
|
|
if mid in self.items:
|
|
del self.items[mid]
|
|
count += 1
|
|
return count > 0
|
|
|
|
def test_synchronous_context():
|
|
print("--- Testing Synchronous Context Module ---")
|
|
|
|
# 1. Initialize Components
|
|
vs = MockVectorStore()
|
|
kg = ContextGraph()
|
|
|
|
context = AgentContext(vector_store=vs, knowledge_graph=kg)
|
|
print("AgentContext initialized successfully")
|
|
|
|
# 2. Store Memory
|
|
print("\n--- Testing Store ---")
|
|
mem_id = context.store(
|
|
"Python is a popular programming language.",
|
|
conversation_id="test_conv",
|
|
extract_entities=True
|
|
)
|
|
print(f"Stored memory with ID: {mem_id}")
|
|
|
|
# 3. Store Documents (with graph update)
|
|
print("\n--- Testing Document Store with Graph ---")
|
|
docs = [
|
|
{
|
|
"content": "Machine learning uses Python heavily.",
|
|
"entities": [
|
|
{"text": "Machine learning", "type": "CONCEPT"},
|
|
{"text": "Python", "type": "TOOL"}
|
|
],
|
|
"relationships": [
|
|
{"source": "Machine learning", "target": "Python", "type": "uses"}
|
|
]
|
|
},
|
|
{
|
|
"content": "TensorFlow is a Python library for ML.",
|
|
"entities": [
|
|
{"text": "TensorFlow", "type": "TOOL"},
|
|
{"text": "Python", "type": "TOOL"},
|
|
{"text": "ML", "type": "CONCEPT"}
|
|
],
|
|
"relationships": [
|
|
{"source": "TensorFlow", "target": "Python", "type": "based_on"}
|
|
]
|
|
}
|
|
]
|
|
stats = context.store(
|
|
docs,
|
|
extract_entities=True,
|
|
link_entities=True
|
|
)
|
|
print(f"Stored documents stats: {stats}")
|
|
|
|
# 4. Verify Graph
|
|
print("\n--- Verifying Graph ---")
|
|
graph_stats = kg.stats()
|
|
print(f"Graph stats: {graph_stats}")
|
|
if graph_stats["node_count"] > 0:
|
|
print("SUCCESS: Graph nodes created")
|
|
else:
|
|
print("WARNING: No graph nodes created (expected if entity extraction is mocked/empty)")
|
|
|
|
# 5. Retrieve
|
|
print("\n--- Testing Retrieval ---")
|
|
results = context.retrieve("Python", max_results=5)
|
|
print(f"Retrieved {len(results)} results")
|
|
for r in results:
|
|
print(f"- {r['content']} (Score: {r['score']})")
|
|
|
|
# 6. Test Short-Term Memory
|
|
print("\n--- Testing Short-Term Memory (Hierarchical) ---")
|
|
st_id = context.store(
|
|
"This is a fleeting thought.",
|
|
skip_vector=True
|
|
)
|
|
print(f"Stored short-term only memory: {st_id}")
|
|
|
|
# Verify it's not in vector store (mock check)
|
|
is_in_vector = any("fleeting" in item.content for item in vs.items.values())
|
|
print(f"Is in vector store: {is_in_vector} (Expected: False)")
|
|
|
|
# Retrieve it (should come from short-term buffer)
|
|
st_results = context.retrieve("fleeting thought")
|
|
print(f"Retrieved {len(st_results)} results for short-term query")
|
|
for r in st_results:
|
|
source_note = f" [Source: {r.get('source', 'unknown')}]" if 'source' in r else ""
|
|
print(f"- {r['content']} (Score: {r['score']}){source_note}")
|
|
|
|
# 7. Test Token Management
|
|
print("\n--- Testing Token Management ---")
|
|
# Initialize a new memory with small token limit
|
|
from semantica.context import AgentMemory
|
|
|
|
# Create isolated memory instance for testing
|
|
token_memory = AgentMemory(
|
|
vector_store=vs,
|
|
token_limit=10, # Small limit (~40 chars)
|
|
short_term_limit=5 # Count limit
|
|
)
|
|
|
|
token_memory.store("First small item", skip_vector=True) # ~16 chars = 4 tokens
|
|
token_memory.store("Second small item", skip_vector=True) # ~17 chars = 4 tokens
|
|
# Total ~8 tokens. Limit 10. Should fit.
|
|
print(f"Items after 2 small: {len(token_memory.short_term_memory)}")
|
|
|
|
token_memory.store("Third small item", skip_vector=True) # ~16 chars = 4 tokens
|
|
# Total ~12 tokens. Limit 10. Should prune oldest ("First small item").
|
|
print(f"Items after 3rd small: {len(token_memory.short_term_memory)}")
|
|
remaining = [m.content for m in token_memory.short_term_memory]
|
|
print(f"Remaining items: {remaining}")
|
|
|
|
if len(token_memory.short_term_memory) == 2 and remaining[0] == "Second small item":
|
|
print("SUCCESS: Token pruning worked")
|
|
else:
|
|
print(f"FAILURE: Token pruning failed. Items: {len(token_memory.short_term_memory)}")
|
|
|
|
print("\n--- Test Complete ---")
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
test_synchronous_context()
|
|
except Exception as e:
|
|
print(f"\nERROR: Test failed with exception: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
sys.exit(1)
|