Memory Abstraction¶
The Memory Abstraction layer provides a generic interface for using Memorg's memory capabilities across workflows beyond chat — document analysis, research notebooks, knowledge management, and custom applications.
Internally, it uses the same StorageAdapter and VectorStore as the chat hierarchy, so a single Memorg database holds both worlds side by side.
Overview¶
Originally designed for chat-based interactions, Memorg has grown a generic abstraction that supports:
- Document analysis
- Research workflows
- Content creation
- Knowledge management
- Custom applications with arbitrary
item_type
Core Concepts¶
Memory Types¶
class MemoryType(Enum):
SESSION = "session"
CONVERSATION = "conversation"
TOPIC = "topic"
EXCHANGE = "exchange"
DOCUMENT = "document"
ENTITY = "entity"
CUSTOM = "custom"
When you pass an item_type string to MemorgSystem.create_memory_item, it is matched against MemoryType values. Unknown strings are stored as MemoryType.CUSTOM with the original label preserved at metadata["custom_type"]. So item_type="note" becomes MemoryType.CUSTOM with metadata["custom_type"] = "note".
Memory Scopes¶
class MemoryScope(Enum):
GLOBAL = "global"
SESSION = "session"
CONVERSATION = "conversation"
TOPIC = "topic"
CUSTOM = "custom"
Unknown scope strings fall back to GLOBAL in MemorgSystem.search_memory.
Memory Item¶
@dataclass
class MemoryItem:
id: str
type: MemoryType
content: str
metadata: Dict[str, Any]
created_at: datetime
updated_at: datetime
embedding: Optional[List[float]] = None
importance_score: float = 0.0
parent_id: Optional[str] = None
tags: List[str] = None # defaults to [] via __post_init__
Memory Query¶
@dataclass
class MemoryQuery:
text: str
scope: MemoryScope
filters: Optional[Dict[str, Any]] = None
limit: int = 10
include_metadata: bool = True
Search Result¶
Note that this is a different SearchResult from memorg.models.SearchResult used by the chat hierarchy.
Key Components¶
HierarchicalMemoryStore¶
Bridges the generic memory interface (MemoryStore protocol) with the existing storage and vector layers.
from memorg.memory.store import HierarchicalMemoryStore
store = HierarchicalMemoryStore(storage, vector_store, openai_client)
await store.store(memory_item)
item = await store.retrieve(item_id)
results = await store.search(memory_query)
children = await store.get_children(parent_id, item_type=MemoryType.DOCUMENT)
parent = await store.get_parent(item_id)
GenericMemoryManager¶
High-level CRUD and search.
from memorg.memory.manager import GenericMemoryManager
manager = GenericMemoryManager(store, openai_client)
item = await manager.create_item(
content="Research findings...",
item_type=MemoryType.DOCUMENT,
tags=["research", "analysis"],
)
results = await manager.search(
query="findings",
scope=MemoryScope.GLOBAL,
item_types=[MemoryType.DOCUMENT],
tags=["research"],
)
context = await manager.get_context(item.id, depth=3, include_siblings=True)
optimized = await manager.optimize_context(items, max_tokens=4000)
In practice, you usually access these through MemorgSystem.create_memory_item, search_memory, get_item_context, and optimize_memory_context.
Usage Examples¶
Document Analysis Workflow¶
async def analyze_documents(documents):
system = MemorgSystem(storage, vector_store, client)
session = await system.create_session("analyst", {
"workflow": "document_analysis",
})
for doc in documents:
await system.create_memory_item(
content=doc.content,
item_type="document",
parent_id=session.id,
metadata={"source": doc.source},
tags=doc.tags,
)
return await system.search_memory(
query="key findings",
item_types=["document"],
tags=["analysis"],
)
Research Workflow¶
async def research_workflow():
system = MemorgSystem(storage, vector_store, client)
session = await system.create_session("researcher", {})
topic = await system.create_memory_item(
content="AI Ethics Research",
item_type="topic",
parent_id=session.id,
tags=["ai", "ethics", "research"],
)
await system.create_memory_item(
content="Key insight: transparency is crucial",
item_type="note",
parent_id=topic.id,
tags=["insight", "transparency"],
)
return await system.search_memory(
query="transparency AI",
scope="global",
)
Token-Bounded Context Pack¶
item_ids = [doc.id, summary.id, note.id]
optimized = await system.optimize_memory_context(item_ids, max_tokens=4000)
optimize_memory_context retrieves each item by id, silently skips missing ones, and passes the survivors to GenericMemoryManager.optimize_context.
Benefits¶
- Generic items — store any kind of information, not just conversation turns.
- Flexible scopes — target operations to specific contexts.
- Tag-based organisation — filter by
tagsalongside text anditem_types. - Rich metadata — attach arbitrary JSON-serialisable metadata to items.
- Shared storage — coexists with chat data in the same SQLite + USearch backing files.
Best Practices¶
Consistent Tagging¶
Use a consistent, lowercase, hyphenated tag vocabulary:
# Good
tags=["project-alpha", "research", "2024"]
# Avoid
tags=["Project Alpha", "Research!", "2024"]
Hierarchical Organisation¶
Leverage parent/child relationships to scope retrieval:
session = await system.create_memory_item(item_type="session", ...)
project = await system.create_memory_item(parent_id=session.id, ...)
document = await system.create_memory_item(parent_id=project.id, ...)
note = await system.create_memory_item(parent_id=document.id, ...)
Scope-Based Search¶
await system.search_memory(query, scope="global")
await system.search_memory(query, scope="session")
global searches all stored memory items; narrower scopes restrict to the indicated subtree.
Mixing Chat and Memory¶
You can attach memory items to chat-level entities. The CLI's addnote command does exactly this: it passes the active session_id as parent_id for the new note item. The same pattern works for hooking documents to a topic, or notes to an exchange.