orchestrata_ultimate.core.protocols.memory
Reference › orchestrata_ultimate › core › protocols › memory
The memory-engine types of SPEC-010, used by the gateway server's memory wiring and re-exported by interfaces.memory. Two enums set policy: MemoryClassification (private, shared, system) and SummarizationStrategy (relevance, recency, importance). MemoryScope is a dataclass that narrows a search by session, task, volk, project, portfolio and date range. MemoryEntry is a Pydantic model with key, content, optional summary, tags, metadata, classification, embedding, timestamps, volk_id, session and task ids, a relevance score and a token count; volk_id is the canonical identity field and agent_id remains as a deprecated read-only alias. MemorySummary records a produced summary and the keys it came from.
TokenCounterProtocol has count and truncate. MemoryEngineProtocol is the engine contract: store, retrieve, search by query and scope, summarize a context under a token budget and strategy, update, delete and migrate_to_cold for moving a session's entries to cold storage. It builds on base.
At a glance
| Source | src/orchestrata_ultimate/core/protocols/memory.py |
| Lines of code | 262 |
| Classes | 7 |
| Functions | 0 |
| Imports (internal) | orchestrata_ultimate.core.base.traces, orchestrata_ultimate.core.protocols.base |
| Imported by | orchestrata_ultimate.core.interfaces.memory, orchestrata_ultimate.core.protocols, orchestrata_ultimate.gateway.server |
| Tests that import it | tests/generated_core/test_protocols_memory_generated.py |
Class diagram
Dependency diagram
API
Classes
MemoryClassification (enum)
Bases: StrEnum · Decorators: traces(spec='010', story='US-006', reqs=['REQ-010-049']) · Line 29
Classification level for memory entries.
| Member | Value |
|---|---|
PRIVATE |
'private' |
SHARED |
'shared' |
SYSTEM |
'system' |
SummarizationStrategy (enum)
Bases: StrEnum · Line 37
Strategy for memory summarization.
| Member | Value |
|---|---|
RELEVANCE |
'relevance' |
RECENCY |
'recency' |
IMPORTANCE |
'importance' |
MemoryScope (dataclass)
Decorators: dataclass, traces(spec='010', story='US-004', reqs=['REQ-010-005']) · Line 47
Scope filter for memory queries.
| Attribute | Type | Default |
|---|---|---|
session_id |
str | None |
None |
task_id |
str | None |
None |
volk_id |
str | None |
None |
project_id |
str | None |
None |
portfolio_id |
str | None |
None |
date_from |
datetime | None |
None |
date_to |
datetime | None |
None |
| Method | Signature | Summary |
|---|---|---|
agent_id property |
agent_id() -> str | None |
Deprecated alias for volk_id (identity migration → volk_id canonical). |
MemoryEntry (pydantic)
Bases: BaseModel · Decorators: traces(spec='010', story='US-001', reqs=['REQ-010-004']) · Line 65
A memory entry stored by an Agent.
| Attribute | Type | Default |
|---|---|---|
key |
str |
PydanticField(default_factory=lambda: str(uuid.uuid4())) |
content |
str |
'' |
summary |
str | None |
None |
tags |
list[str] |
PydanticField(default_factory=list) |
metadata |
dict[str, Any] |
PydanticField(default_factory=dict) |
classification |
MemoryClassification |
MemoryClassification.PRIVATE |
embedding |
list[float] | None |
None |
created_at |
datetime |
PydanticField(default_factory=lambda: datetime.now(UTC)) |
updated_at |
datetime |
PydanticField(default_factory=lambda: datetime.now(UTC)) |
volk_id |
str |
PydanticField(default='', alias='agent_id') |
session_id |
str |
'' |
task_id |
str | None |
None |
relevance_score |
float | None |
None |
token_count |
int |
0 |
| Method | Signature | Summary |
|---|---|---|
agent_id property |
agent_id() -> str |
Deprecated alias for volk_id (identity migration → volk_id canonical). |
to_dict |
to_dict() -> dict[str, Any] |
Serialize to dict (backward compatibility). |
from_dict classmethod |
from_dict(data: dict[str, Any]) -> MemoryEntry |
Deserialize from dict (backward compatibility). |
MemorySummary (dataclass)
Decorators: dataclass, traces(spec='010', story='US-005', reqs=['REQ-010-023']) · Line 116
Result of memory summarization.
| Attribute | Type | Default |
|---|---|---|
content |
str |
'' |
token_count |
int |
0 |
source_count |
int |
0 |
source_keys |
list[str] |
field(default_factory=list) |
strategy |
SummarizationStrategy |
SummarizationStrategy.RELEVANCE |
created_at |
datetime |
field(default_factory=lambda: datetime.now(UTC)) |
TokenCounterProtocol (protocol)
Bases: Protocol · Decorators: traces(spec='010', story='US-003', reqs=['REQ-010-041']) · Line 133
Provider-aware token counting abstraction.
| Method | Signature | Summary |
|---|---|---|
count |
count(text: str) -> int |
Count tokens in text. |
truncate |
truncate(text: str, max_tokens: int) -> str |
Truncate text to fit within max_tokens. |
MemoryEngineProtocol (protocol)
Bases: ComponentProtocol, Protocol · Decorators: traces(spec='010', story='US-001', reqs=['REQ-010-001']) · Line 153
Unified agent memory abstraction.
| Method | Signature | Summary |
|---|---|---|
store |
async store(content: str, *, volk_id: str, session_id: str, key: str | None = None, tags: list[str] | None = None, metadata: dict[str, Any] | None = None, classification: MemoryClassification = MemoryClassification.PRIVATE, task_id: str | None = None) -> MemoryEntry |
Store a memory entry. |
retrieve |
async retrieve(key: str, *, include_metadata: bool = True) -> MemoryEntry | None |
Retrieve a memory entry by exact key. |
search |
async search(query: str, *, scope: MemoryScope | None = None, limit: int = 10, min_similarity: float = 0.7, max_entries: int | None = None, max_age_seconds: int | None = None) -> list[MemoryEntry] |
Semantic search over memory entries. |
summarize |
async summarize(context_id: str, *, max_tokens: int = 2048, strategy: SummarizationStrategy = SummarizationStrategy.RELEVANCE) -> MemorySummary |
Compress memories for context_id into a token-bounded summary. |
update |
async update(key: str, *, content: str | None = None, tags: list[str] | None = None, metadata: dict[str, Any] | None = None, classification: MemoryClassification | None = None) -> MemoryEntry |
Update an existing memory entry. |
delete |
async delete(key: str) -> bool |
Delete a memory entry by key. |
migrate_to_cold |
async migrate_to_cold(session_id: str) -> int |
Migrate all hot memories for session to cold storage. |
Source
"""
Memory engine protocol types for Orchestrata Ultimate (SPEC-010).
Depends on :mod:`orchestrata_ultimate.core.protocols.base` for the
``ComponentProtocol`` base. ``MemoryEntry`` is a Pydantic model. This module is
the single source of truth: :mod:`orchestrata_ultimate.core.interfaces.memory`
re-exports these types as thin aliases (the interfaces->protocols twin-collapse).
"""
import json
import uuid
from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import StrEnum
from typing import Any, Protocol
from pydantic import BaseModel, ConfigDict
from pydantic import Field as PydanticField
from orchestrata_ultimate.core.base.traces import traces
from orchestrata_ultimate.core.protocols.base import ComponentProtocol
# ============================================================================
# Memory Engine Types (SPEC-010)
# ============================================================================
@traces(spec="010", story="US-006", reqs=["REQ-010-049"])
class MemoryClassification(StrEnum):
"""Classification level for memory entries."""
PRIVATE = "private"
SHARED = "shared"
SYSTEM = "system"
class SummarizationStrategy(StrEnum):
"""Strategy for memory summarization."""
RELEVANCE = "relevance"
RECENCY = "recency"
IMPORTANCE = "importance"
@dataclass
@traces(spec="010", story="US-004", reqs=["REQ-010-005"])
class MemoryScope:
"""Scope filter for memory queries."""
session_id: str | None = None
task_id: str | None = None
volk_id: str | None = None
project_id: str | None = None
portfolio_id: str | None = None
date_from: datetime | None = None
date_to: datetime | None = None
@property
def agent_id(self) -> str | None:
"""Deprecated alias for volk_id (identity migration → volk_id canonical)."""
return self.volk_id
@traces(spec="010", story="US-001", reqs=["REQ-010-004"])
class MemoryEntry(BaseModel):
"""A memory entry stored by an Agent."""
model_config = ConfigDict(populate_by_name=True)
key: str = PydanticField(default_factory=lambda: str(uuid.uuid4()))
content: str = ""
summary: str | None = None
tags: list[str] = PydanticField(default_factory=list)
metadata: dict[str, Any] = PydanticField(default_factory=dict)
classification: MemoryClassification = MemoryClassification.PRIVATE
embedding: list[float] | None = None
created_at: datetime = PydanticField(default_factory=lambda: datetime.now(UTC))
updated_at: datetime = PydanticField(default_factory=lambda: datetime.now(UTC))
volk_id: str = PydanticField(default="", alias="agent_id")
session_id: str = ""
task_id: str | None = None
relevance_score: float | None = None
token_count: int = 0
@property
def agent_id(self) -> str:
"""Deprecated alias for volk_id (identity migration → volk_id canonical)."""
return self.volk_id
def to_dict(self) -> dict[str, Any]:
"""Serialize to dict (backward compatibility)."""
return self.model_dump()
@classmethod
def from_dict(cls, data: dict[str, Any]) -> MemoryEntry:
"""Deserialize from dict (backward compatibility).
Handles stringified JSON for ``tags`` and ``metadata`` fields,
and string ``token_count`` / ``classification`` values.
"""
data = dict(data)
for field_name in ("tags", "metadata"):
value = data.get(field_name)
if isinstance(value, str):
data[field_name] = json.loads(value)
if "token_count" in data and isinstance(data["token_count"], str):
data["token_count"] = int(data["token_count"])
if "classification" in data and isinstance(data["classification"], str):
data["classification"] = MemoryClassification(data["classification"])
return cls.model_validate(data)
@dataclass
@traces(spec="010", story="US-005", reqs=["REQ-010-023"])
class MemorySummary:
"""Result of memory summarization."""
content: str = ""
token_count: int = 0
source_count: int = 0
source_keys: list[str] = field(default_factory=list)
strategy: SummarizationStrategy = SummarizationStrategy.RELEVANCE
created_at: datetime = field(default_factory=lambda: datetime.now(UTC))
# ============================================================================
# Token Counter Protocol (shared SPEC-010 / SPEC-011)
# ============================================================================
@traces(spec="010", story="US-003", reqs=["REQ-010-041"])
class TokenCounterProtocol(Protocol):
"""Provider-aware token counting abstraction."""
@traces(spec="010", story="US-003", reqs=["REQ-010-041"])
def count(self, text: str) -> int:
"""Count tokens in text."""
...
@traces(spec="010", story="US-003", reqs=["REQ-010-042"])
def truncate(self, text: str, max_tokens: int) -> str:
"""Truncate text to fit within max_tokens."""
...
# ============================================================================
# Memory Engine Protocol (SPEC-010)
# ============================================================================
@traces(spec="010", story="US-001", reqs=["REQ-010-001"])
class MemoryEngineProtocol(ComponentProtocol, Protocol):
"""Unified agent memory abstraction.
Provides store, retrieve, search, summarize, and lifecycle
operations over a dual-layer storage system (Redis hot / Neo4j cold).
"""
@traces(spec="010", story="US-001", reqs=["REQ-010-006", "REQ-010-007"])
async def store(
self,
content: str,
*,
volk_id: str,
session_id: str,
key: str | None = None,
tags: list[str] | None = None,
metadata: dict[str, Any] | None = None,
classification: MemoryClassification = MemoryClassification.PRIVATE,
task_id: str | None = None,
) -> MemoryEntry:
"""Store a memory entry. Returns the created entry with generated key."""
...
@traces(spec="010", story="US-001", reqs=["REQ-010-011", "REQ-010-014"])
async def retrieve(
self,
key: str,
*,
include_metadata: bool = True,
) -> MemoryEntry | None:
"""Retrieve a memory entry by exact key."""
...
@traces(
spec="010",
story="US-004",
reqs=["REQ-010-015", "REQ-010-017", "REQ-010-019", "REQ-010-039"],
)
async def search(
self,
query: str,
*,
scope: MemoryScope | None = None,
limit: int = 10,
min_similarity: float = 0.7,
max_entries: int | None = None,
max_age_seconds: int | None = None,
) -> list[MemoryEntry]:
"""Semantic search over memory entries.
Args:
query: Free-text query to match against memory content.
scope: Optional scope filter (session/volk/task/date range).
limit: Maximum results to return after similarity scoring.
min_similarity: Minimum cosine similarity for a candidate.
max_entries: Pre-filter — maximum candidate entries to retrieve
from storage before embedding scoring. Keeps recall latency
bounded when the hot store is large.
max_age_seconds: Pre-filter — only retrieve entries created within
this many seconds of now. Applied before similarity scoring.
"""
...
@traces(spec="010", story="US-005", reqs=["REQ-010-020", "REQ-010-022"])
async def summarize(
self,
context_id: str,
*,
max_tokens: int = 2048,
strategy: SummarizationStrategy = SummarizationStrategy.RELEVANCE,
) -> MemorySummary:
"""Compress memories for context_id into a token-bounded summary."""
...
@traces(spec="010", story="US-006", reqs=["REQ-010-050"])
async def update(
self,
key: str,
*,
content: str | None = None,
tags: list[str] | None = None,
metadata: dict[str, Any] | None = None,
classification: MemoryClassification | None = None,
) -> MemoryEntry:
"""Update an existing memory entry. Only provided fields are modified."""
...
async def delete(self, key: str) -> bool:
"""Delete a memory entry by key. Returns True if found and deleted."""
...
@traces(spec="010", story="US-002", reqs=["REQ-010-032"])
async def migrate_to_cold(self, session_id: str) -> int:
"""Migrate all hot memories for session to cold storage. Returns count."""
...
# Compat alias matching the core.interfaces naming convention (P2.2).
IMemoryEngine = MemoryEngineProtocol
__all__ = [
"MemoryClassification",
"SummarizationStrategy",
"MemoryScope",
"MemoryEntry",
"MemorySummary",
"TokenCounterProtocol",
"MemoryEngineProtocol",
"IMemoryEngine",
]