-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add pluggable MemoryBackend protocol with models, config, and events #180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1b82823
077dddd
884b7b5
377d4d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -397,25 +397,39 @@ The protocol will follow our established `@runtime_checkable` pattern: | |||||||||||||||
| ```python | ||||||||||||||||
| @runtime_checkable | ||||||||||||||||
| class MemoryBackend(Protocol): | ||||||||||||||||
| """Structural interface for memory storage backends.""" | ||||||||||||||||
| """Structural interface for agent memory storage backends.""" | ||||||||||||||||
|
|
||||||||||||||||
| async def store(self, agent_id: str, memory: MemoryEntry) -> str: ... | ||||||||||||||||
| async def retrieve(self, agent_id: str, query: MemoryQuery) -> list[MemoryEntry]: ... | ||||||||||||||||
| async def delete(self, agent_id: str, memory_id: str) -> bool: ... | ||||||||||||||||
| async def list_memories(self, agent_id: str, ...) -> list[MemoryEntry]: ... | ||||||||||||||||
| async def connect(self) -> None: ... | ||||||||||||||||
| async def disconnect(self) -> None: ... | ||||||||||||||||
| async def health_check(self) -> bool: ... | ||||||||||||||||
|
|
||||||||||||||||
| @property | ||||||||||||||||
| def is_connected(self) -> bool: ... | ||||||||||||||||
| @property | ||||||||||||||||
| def backend_name(self) -> str: ... | ||||||||||||||||
|
|
||||||||||||||||
| async def store(self, agent_id: NotBlankStr, request: MemoryStoreRequest) -> NotBlankStr: ... | ||||||||||||||||
| async def retrieve(self, agent_id: NotBlankStr, query: MemoryQuery) -> tuple[MemoryEntry, ...]: ... | ||||||||||||||||
| async def get(self, agent_id: NotBlankStr, memory_id: NotBlankStr) -> MemoryEntry | None: ... | ||||||||||||||||
| async def delete(self, agent_id: NotBlankStr, memory_id: NotBlankStr) -> bool: ... | ||||||||||||||||
| async def count(self, agent_id: NotBlankStr, *, category: MemoryCategory | None = None) -> int: ... | ||||||||||||||||
|
|
||||||||||||||||
| @runtime_checkable | ||||||||||||||||
| class MemoryCapabilities(Protocol): | ||||||||||||||||
| """Capability discovery — what this backend supports.""" | ||||||||||||||||
|
|
||||||||||||||||
| @property | ||||||||||||||||
| def supported_types(self) -> frozenset[MemoryType]: ... | ||||||||||||||||
| def supported_categories(self) -> frozenset[MemoryCategory]: ... | ||||||||||||||||
| @property | ||||||||||||||||
|
Comment on lines
421
to
423
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Property name mismatch between ADR and implementation. The ADR shows 📝 Suggested fix `@property`
- def supported_types(self) -> frozenset[MemoryCategory]: ...
+ def supported_categories(self) -> frozenset[MemoryCategory]: ...📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||
| def supports_graph(self) -> bool: ... | ||||||||||||||||
| @property | ||||||||||||||||
| def supports_temporal(self) -> bool: ... | ||||||||||||||||
| @property | ||||||||||||||||
| def supports_vector_search(self) -> bool: ... | ||||||||||||||||
| @property | ||||||||||||||||
| def supports_shared_access(self) -> bool: ... | ||||||||||||||||
| @property | ||||||||||||||||
| def max_memories_per_agent(self) -> int | None: ... | ||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||
| ``` | ||||||||||||||||
|
|
||||||||||||||||
| Initial concrete implementation: `Mem0MemoryBackend` (wraps Mem0 `AsyncMemory`). | ||||||||||||||||
|
|
||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
| from ai_company.core.enums import CompanyType, SeniorityLevel | ||
| from ai_company.core.role import CustomRole # noqa: TC001 | ||
| from ai_company.core.types import NotBlankStr # noqa: TC001 | ||
| from ai_company.memory.config import CompanyMemoryConfig | ||
| from ai_company.observability import get_logger | ||
| from ai_company.observability.config import LogConfig # noqa: TC001 | ||
| from ai_company.observability.events.config import CONFIG_VALIDATION_FAILED | ||
|
|
@@ -77,6 +78,14 @@ def _validate_delay_ordering(self) -> Self: | |
| f"base_delay ({self.base_delay}) must be" | ||
| f" <= max_delay ({self.max_delay})" | ||
| ) | ||
| logger.warning( | ||
| CONFIG_VALIDATION_FAILED, | ||
| model="RetryConfig", | ||
| field="base_delay/max_delay", | ||
| base_delay=self.base_delay, | ||
| max_delay=self.max_delay, | ||
| reason=msg, | ||
| ) | ||
| raise ValueError(msg) | ||
| return self | ||
|
|
||
|
|
@@ -459,6 +468,7 @@ class RootConfig(BaseModel): | |
| escalation_paths: Cross-department escalation paths. | ||
| coordination_metrics: Coordination metrics configuration. | ||
| task_assignment: Task assignment configuration. | ||
| memory: Memory backend configuration. | ||
| persistence: Persistence backend configuration. | ||
| """ | ||
|
|
||
|
|
@@ -527,6 +537,10 @@ class RootConfig(BaseModel): | |
| default_factory=TaskAssignmentConfig, | ||
| description="Task assignment configuration", | ||
| ) | ||
| memory: CompanyMemoryConfig = Field( | ||
| default_factory=CompanyMemoryConfig, | ||
| description="Memory backend configuration", | ||
| ) | ||
|
Comment on lines
+540
to
+543
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't default every root config to an unbuildable backend.
🤖 Prompt for AI Agents |
||
| persistence: PersistenceConfig = Field( | ||
| default_factory=PersistenceConfig, | ||
| description="Persistence backend configuration", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Table of Contents entry for section 7 lists 7.5 before 7.4; this is out of numeric order and doesn’t match the section numbering below. Please reorder the referenced subsections (7.4, 7.5, 7.6) so the TOC reflects the actual structure.