diff --git a/memanto/memory.py b/memanto/memory.py new file mode 100644 index 000000000..32d000c42 --- /dev/null +++ b/memanto/memory.py @@ -0,0 +1,26 @@ +from dataclasses import dataclass, field +from datetime import datetime +from typing import Dict, Optional, Union + +@dataclass +class MemoryRecord: + """ + A structured memory record with content, metadata, provenance, and timestamps. + """ + content: str + metadata: Dict[str, Union[str, int, float, bool]] = field(default_factory=dict) + provenance: str = "explicit_statement" # Default provenance + created_at: datetime = field(default_factory=datetime.now) + updated_at: datetime = field(default_factory=datetime.now) + + def update(self, content: Optional[str] = None, metadata: Optional[Dict] = None, provenance: Optional[str] = None): + """ + Update the memory record, preserving existing metadata and provenance unless explicitly changed. + """ + if content is not None: + self.content = content + if metadata is not None: + self.metadata.update(metadata) + if provenance is not None: + self.provenance = provenance + self.updated_at = datetime.now() \ No newline at end of file diff --git a/memanto/storage.py b/memanto/storage.py new file mode 100644 index 000000000..bf079ccdb --- /dev/null +++ b/memanto/storage.py @@ -0,0 +1,17 @@ +from typing import Dict, Optional, Union +from .memory import MemoryRecord + +class MemoryStorage: + def __init__(self): + self.memories: Dict[str, MemoryRecord] = {} + + def update_memory(self, memory_id: str, content: Optional[str] = None, metadata: Optional[Dict] = None, provenance: Optional[str] = None) -> MemoryRecord: + """ + Update an existing memory, preserving existing metadata and provenance unless explicitly changed. + """ + if memory_id not in self.memories: + raise ValueError(f"Memory with ID {memory_id} not found") + + memory = self.memories[memory_id] + memory.update(content, metadata, provenance) + return memory \ No newline at end of file diff --git a/tests/test_memory.py b/tests/test_memory.py new file mode 100644 index 000000000..48e50d43f --- /dev/null +++ b/tests/test_memory.py @@ -0,0 +1,45 @@ +import unittest +from datetime import datetime +from memanto.memory import MemoryRecord + +class TestMemoryRecord(unittest.TestCase): + def test_update_preserves_provenance(self): + """ + Test that updating a memory preserves the original provenance unless explicitly changed. + """ + original_provenance = "validated" + memory = MemoryRecord( + content="Original content", + metadata={"key": "value"}, + provenance=original_provenance + ) + + # Update with new content and metadata, but no provenance change + memory.update( + content="Updated content", + metadata={"new_key": "new_value"} + ) + + # Verify provenance is preserved + self.assertEqual(memory.provenance, original_provenance) + self.assertEqual(memory.content, "Updated content") + self.assertIn("key", memory.metadata) + self.assertIn("new_key", memory.metadata) + + def test_update_changes_provenance(self): + """ + Test that updating a memory with a new provenance changes the provenance. + """ + original_provenance = "validated" + memory = MemoryRecord( + content="Original content", + metadata={"key": "value"}, + provenance=original_provenance + ) + + # Update with new provenance + new_provenance = "corrected" + memory.update(provenance=new_provenance) + + # Verify provenance is updated + self.assertEqual(memory.provenance, new_provenance) \ No newline at end of file diff --git a/tests/test_storage.py b/tests/test_storage.py new file mode 100644 index 000000000..71ecf025d --- /dev/null +++ b/tests/test_storage.py @@ -0,0 +1,44 @@ +import unittest +from memanto.storage import MemoryStorage +from memanto.memory import MemoryRecord + +class TestMemoryStorage(unittest.TestCase): + def setUp(self): + self.storage = MemoryStorage() + self.memory_id = "test_memory" + self.original_provenance = "validated" + self.memory = MemoryRecord( + content="Original content", + metadata={"key": "value"}, + provenance=self.original_provenance + ) + self.storage.memories[self.memory_id] = self.memory + + def test_update_memory_preserves_provenance(self): + """ + Test that updating a memory through the storage preserves the original provenance unless explicitly changed. + """ + updated_memory = self.storage.update_memory( + memory_id=self.memory_id, + content="Updated content", + metadata={"new_key": "new_value"} + ) + + # Verify provenance is preserved + self.assertEqual(updated_memory.provenance, self.original_provenance) + self.assertEqual(updated_memory.content, "Updated content") + self.assertIn("key", updated_memory.metadata) + self.assertIn("new_key", updated_memory.metadata) + + def test_update_memory_changes_provenance(self): + """ + Test that updating a memory through the storage with a new provenance changes the provenance. + """ + new_provenance = "corrected" + updated_memory = self.storage.update_memory( + memory_id=self.memory_id, + provenance=new_provenance + ) + + # Verify provenance is updated + self.assertEqual(updated_memory.provenance, new_provenance) \ No newline at end of file