Add SQLAlchemy models for the Agent Memory System: - WorkingMemory: Key-value storage with TTL for active sessions - Episode: Experiential memories from task executions - Fact: Semantic knowledge triples with confidence scores - Procedure: Learned skills and procedures with success tracking - MemoryConsolidationLog: Tracks consolidation jobs between memory tiers Create enums for memory system: - ScopeType: global, project, agent_type, agent_instance, session - EpisodeOutcome: success, failure, partial - ConsolidationType: working_to_episodic, episodic_to_semantic, etc. - ConsolidationStatus: pending, running, completed, failed Add Alembic migration (0005) for all memory tables with: - Foreign key relationships to projects, agent_instances, agent_types - Comprehensive indexes for query patterns - Unique constraints for key lookups and triple uniqueness - Vector embedding column placeholders (Text fallback until pgvector enabled) Fix timezone-naive datetime.now() in types.py TaskState (review feedback) Includes 30 unit tests for models and enums. Closes #88 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
73 lines
2.1 KiB
Python
73 lines
2.1 KiB
Python
# app/models/memory/consolidation.py
|
|
"""
|
|
Memory Consolidation Log database model.
|
|
|
|
Tracks memory consolidation jobs that transfer knowledge
|
|
between memory tiers.
|
|
"""
|
|
|
|
from sqlalchemy import Column, DateTime, Enum, Index, Integer, Text
|
|
|
|
from app.models.base import Base, TimestampMixin, UUIDMixin
|
|
|
|
from .enums import ConsolidationStatus, ConsolidationType
|
|
|
|
|
|
class MemoryConsolidationLog(Base, UUIDMixin, TimestampMixin):
|
|
"""
|
|
Memory consolidation job log.
|
|
|
|
Tracks consolidation operations:
|
|
- Working -> Episodic (session end)
|
|
- Episodic -> Semantic (fact extraction)
|
|
- Episodic -> Procedural (procedure learning)
|
|
- Pruning (removing low-value memories)
|
|
"""
|
|
|
|
__tablename__ = "memory_consolidation_log"
|
|
|
|
# Consolidation type
|
|
consolidation_type: Column[ConsolidationType] = Column(
|
|
Enum(ConsolidationType),
|
|
nullable=False,
|
|
index=True,
|
|
)
|
|
|
|
# Counts
|
|
source_count = Column(Integer, nullable=False, default=0)
|
|
result_count = Column(Integer, nullable=False, default=0)
|
|
|
|
# Timing
|
|
started_at = Column(DateTime(timezone=True), nullable=False)
|
|
completed_at = Column(DateTime(timezone=True), nullable=True)
|
|
|
|
# Status
|
|
status: Column[ConsolidationStatus] = Column(
|
|
Enum(ConsolidationStatus),
|
|
nullable=False,
|
|
default=ConsolidationStatus.PENDING,
|
|
index=True,
|
|
)
|
|
|
|
# Error details if failed
|
|
error = Column(Text, nullable=True)
|
|
|
|
__table_args__ = (
|
|
# Query patterns
|
|
Index("ix_consolidation_type_status", "consolidation_type", "status"),
|
|
Index("ix_consolidation_started", "started_at"),
|
|
)
|
|
|
|
@property
|
|
def duration_seconds(self) -> float | None:
|
|
"""Calculate duration of the consolidation job."""
|
|
if self.completed_at is None or self.started_at is None:
|
|
return None
|
|
return (self.completed_at - self.started_at).total_seconds()
|
|
|
|
def __repr__(self) -> str:
|
|
return (
|
|
f"<MemoryConsolidationLog {self.id} "
|
|
f"type={self.consolidation_type.value} status={self.status.value}>"
|
|
)
|