"""
Farnsworth Memory System Tests
Comprehensive tests for:
- Virtual context paging
- Archival memory storage/retrieval
- Knowledge graph operations
- Memory dreaming consolidation
- Working memory management
"""
import asyncio
import pytest
import tempfile
from pathlib import Path
from datetime import datetime
# Test fixtures and helpers
@pytest.fixture
def temp_data_dir():
"""Create temporary data directory for tests."""
with tempfile.TemporaryDirectory() as tmpdir:
yield tmpdir
@pytest.fixture
def event_loop():
"""Create event loop for async tests."""
loop = asyncio.new_event_loop()
yield loop
loop.close()
class TestVirtualContext:
"""Tests for MemGPT-style virtual context."""
def test_context_window_creation(self):
"""Test context window initialization."""
from farnsworth.memory.virtual_context import ContextWindow
window = ContextWindow(max_tokens=4096)
assert window.max_tokens == 4096
assert window.current_tokens == 0
assert len(window.content) == 0
def test_context_add_content(self):
"""Test adding content to context window."""
from farnsworth.memory.virtual_context import ContextWindow
window = ContextWindow(max_tokens=4096)
window.add("Hello, world!", source="test", importance=0.8)
assert window.current_tokens > 0
assert len(window.content) == 1
assert window.content[0].text == "Hello, world!"
def test_context_overflow_eviction(self):
"""Test that low-importance content is evicted on overflow."""
from farnsworth.memory.virtual_context import ContextWindow
window = ContextWindow(max_tokens=100)
# Add low importance content
window.add("Low importance content " * 10, source="test", importance=0.2)
# Add high importance content that would overflow
window.add("High importance content", source="test", importance=0.9)
# Should have evicted some low importance content
assert window.current_tokens <= window.max_tokens
def test_page_manager_tiers(self):
"""Test page manager tier-based caching."""
from farnsworth.memory.virtual_context import PageManager
manager = PageManager(
hot_capacity=100,
warm_capacity=500,
cold_capacity=1000,
)
# Add pages
for i in range(20):
manager.add_page(f"content_{i}", importance=i / 20)
# Should have distributed across tiers
assert manager.hot_count > 0
assert manager.total_pages == 20
class TestArchivalMemory:
"""Tests for archival memory storage."""
@pytest.mark.asyncio
async def test_archival_storage(self, temp_data_dir):
"""Test storing memories in archival storage."""
from farnsworth.memory.archival_memory import ArchivalMemory
memory = ArchivalMemory(data_dir=temp_data_dir)
await memory.initialize()
# Store a memory
memory_id = await memory.store(
content="Test memory content",
tags=["test", "example"],
importance=0.7,
)
assert memory_id is not None
assert memory.count > 0
@pytest.mark.asyncio
async def test_archival_search(self, temp_data_dir):
"""Test semantic search in archival memory."""
from farnsworth.memory.archival_memory import ArchivalMemory
memory = ArchivalMemory(data_dir=temp_data_dir)
await memory.initialize()
# Store some memories
await memory.store("Python is a programming language", tags=["programming"])
await memory.store("Machine learning uses neural networks", tags=["ml"])
await memory.store("The weather is sunny today", tags=["weather"])
# Search
results = await memory.search("programming language", top_k=2)
assert len(results) > 0
assert "Python" in results[0].content or "programming" in results[0].content.lower()
@pytest.mark.asyncio
async def test_archival_hybrid_search(self, temp_data_dir):
"""Test hybrid semantic + keyword search."""
from farnsworth.memory.archival_memory import ArchivalMemory
memory = ArchivalMemory(data_dir=temp_data_dir)
await memory.initialize()
# Store memories
await memory.store("The quick brown fox jumps over the lazy dog")
await memory.store("A fast orange cat leaps across the sleepy canine")
# Hybrid search should find exact keyword matches
results = await memory.hybrid_search(
query="quick fox",
top_k=2,
semantic_weight=0.5,
keyword_weight=0.5,
)
assert len(results) > 0
class TestKnowledgeGraph:
"""Tests for knowledge graph operations."""
def test_entity_creation(self):
"""Test creating entities in knowledge graph."""
from farnsworth.memory.knowledge_graph import KnowledgeGraph
graph = KnowledgeGraph()
entity_id = graph.add_entity(
name="Python",
entity_type="ProgrammingLanguage",
properties={"creator": "Guido van Rossum"},
)
assert entity_id is not None
entity = graph.get_entity(entity_id)
assert entity.name == "Python"
def test_relationship_creation(self):
"""Test creating relationships between entities."""
from farnsworth.memory.knowledge_graph import KnowledgeGraph
graph = KnowledgeGraph()
python_id = graph.add_entity("Python", "Language")
guido_id = graph.add_entity("Guido van Rossum", "Person")
graph.add_relationship(
source_id=guido_id,
target_id=python_id,
relation_type="created",
)
relationships = graph.get_relationships(guido_id)
assert len(relationships) > 0
assert relationships[0].relation_type == "created"
def test_graph_query(self):
"""Test querying the knowledge graph."""
from farnsworth.memory.knowledge_graph import KnowledgeGraph
graph = KnowledgeGraph()
# Build a small graph
farnsworth = graph.add_entity("Farnsworth", "Project")
memory = graph.add_entity("Memory System", "Component")
evolution = graph.add_entity("Evolution", "Feature")
graph.add_relationship(farnsworth, memory, "contains")
graph.add_relationship(farnsworth, evolution, "contains")
# Query
results = graph.query("Farnsworth components", max_hops=1)
assert len(results.entities) >= 1
def test_entity_extraction(self):
"""Test automatic entity extraction from text."""
from farnsworth.memory.knowledge_graph import KnowledgeGraph
graph = KnowledgeGraph()
text = "John works at Google in California. He uses Python for machine learning."
entities = graph.extract_entities(text)
# Should find at least some entities
entity_names = [e["name"] for e in entities]
assert any("John" in name or "Google" in name or "Python" in name for name in entity_names)
class TestRecallMemory:
"""Tests for conversation recall memory."""
def test_conversation_storage(self):
"""Test storing conversation turns."""
from farnsworth.memory.recall_memory import RecallMemory
memory = RecallMemory()
memory.add_turn("user", "Hello, how are you?")
memory.add_turn("assistant", "I'm doing well, thank you!")
assert len(memory.turns) == 2
assert memory.turns[0].role == "user"
def test_conversation_search(self):
"""Test searching conversation history."""
from farnsworth.memory.recall_memory import RecallMemory
memory = RecallMemory()
memory.add_turn("user", "Tell me about Python programming")
memory.add_turn("assistant", "Python is a versatile programming language...")
memory.add_turn("user", "What about JavaScript?")
memory.add_turn("assistant", "JavaScript is primarily used for web development...")
results = memory.search("Python", max_results=5)
assert len(results) > 0
assert "Python" in results[0].content
def test_topic_threading(self):
"""Test topic-based conversation threading."""
from farnsworth.memory.recall_memory import RecallMemory
memory = RecallMemory()
memory.add_turn("user", "Let's discuss machine learning", topic="ml")
memory.add_turn("assistant", "Machine learning is...", topic="ml")
memory.add_turn("user", "Now let's talk about cooking", topic="cooking")
ml_turns = memory.get_by_topic("ml")
assert len(ml_turns) == 2
class TestWorkingMemory:
"""Tests for working memory slots."""
def test_slot_creation(self):
"""Test creating working memory slots."""
from farnsworth.memory.working_memory import WorkingMemory, SlotType
wm = WorkingMemory()
wm.set("current_task", "Implement tests", slot_type=SlotType.TASK)
wm.set("scratch_notes", "Some notes here", slot_type=SlotType.SCRATCH)
assert wm.get("current_task") == "Implement tests"
assert wm.get("scratch_notes") == "Some notes here"
def test_slot_ttl(self):
"""Test slot TTL expiration."""
import time
from farnsworth.memory.working_memory import WorkingMemory, SlotType
wm = WorkingMemory()
wm.set("temp", "temporary value", slot_type=SlotType.SCRATCH, ttl_seconds=0.1)
assert wm.get("temp") == "temporary value"
time.sleep(0.2)
assert wm.get("temp") is None # Should be expired
def test_slot_cross_references(self):
"""Test cross-references between slots."""
from farnsworth.memory.working_memory import WorkingMemory, SlotType
wm = WorkingMemory()
wm.set("entity_a", {"name": "A"}, slot_type=SlotType.REFERENCE)
wm.set("entity_b", {"name": "B", "related_to": "entity_a"}, slot_type=SlotType.REFERENCE)
wm.link("entity_a", "entity_b")
refs = wm.get_references("entity_a")
assert "entity_b" in refs
class TestMemoryDreaming:
"""Tests for memory consolidation (dreaming)."""
@pytest.mark.asyncio
async def test_dream_cycle(self, temp_data_dir):
"""Test a complete dream cycle."""
from farnsworth.memory.memory_dreaming import MemoryDreaming
from farnsworth.memory.archival_memory import ArchivalMemory
archival = ArchivalMemory(data_dir=temp_data_dir)
await archival.initialize()
# Add some memories
for i in range(10):
await archival.store(f"Memory content {i}", importance=0.5)
dreaming = MemoryDreaming(archival_memory=archival)
# Run dream cycle
result = await dreaming.dream()
assert result.memories_processed >= 0
def test_cluster_formation(self):
"""Test memory clustering during dreaming."""
from farnsworth.memory.memory_dreaming import MemoryDreaming
dreaming = MemoryDreaming()
memories = [
"Python programming tutorial",
"Python data science guide",
"JavaScript web development",
"JavaScript frameworks",
"Cooking Italian pasta",
"Italian cuisine recipes",
]
clusters = dreaming._cluster_memories(memories)
# Should form distinct clusters
assert len(clusters) >= 2
def test_forgetting_selection(self):
"""Test intelligent forgetting of low-utility memories."""
from farnsworth.memory.memory_dreaming import MemoryDreaming
dreaming = MemoryDreaming()
memories = [
{"content": "Important fact", "importance": 0.9, "access_count": 10},
{"content": "Rarely accessed", "importance": 0.3, "access_count": 1},
{"content": "Medium importance", "importance": 0.5, "access_count": 5},
]
to_forget = dreaming._select_for_forgetting(memories, forget_ratio=0.3)
# Should select low importance/access memories first
assert len(to_forget) > 0
class TestMemorySystem:
"""Integration tests for the complete memory system."""
@pytest.mark.asyncio
async def test_full_memory_cycle(self, temp_data_dir):
"""Test complete remember -> recall -> consolidate cycle."""
from farnsworth.memory.memory_system import MemorySystem
system = MemorySystem(data_dir=temp_data_dir)
await system.initialize()
# Remember
memory_id = await system.remember(
content="The capital of France is Paris",
tags=["geography", "facts"],
importance=0.8,
)
assert memory_id is not None
# Recall
results = await system.recall("What is the capital of France?")
assert len(results) > 0
assert "Paris" in results[0].content
# Get context
context = system.get_context()
assert len(context) > 0
@pytest.mark.asyncio
async def test_memory_summary(self, temp_data_dir):
"""Test memory summary generation."""
from farnsworth.memory.memory_system import MemorySystem
system = MemorySystem(data_dir=temp_data_dir)
await system.initialize()
# Add some memories
await system.remember("First memory", importance=0.7)
await system.remember("Second memory", importance=0.5)
summary = await system.get_memory_summary()
assert summary is not None
if __name__ == "__main__":
pytest.main([__file__, "-v"])