forked from cardosofelipe/fast-next-template
feat(memory): add database schema and storage layer (Issue #88)
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>
This commit is contained in:
@@ -6,12 +6,17 @@ Core type definitions and interfaces for the Agent Memory System.
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from datetime import UTC, datetime
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
def _utcnow() -> datetime:
|
||||
"""Get current UTC time as timezone-aware datetime."""
|
||||
return datetime.now(UTC)
|
||||
|
||||
|
||||
class MemoryType(str, Enum):
|
||||
"""Types of memory in the agent memory system."""
|
||||
|
||||
@@ -93,7 +98,7 @@ class MemoryItem:
|
||||
|
||||
def get_age_seconds(self) -> float:
|
||||
"""Get the age of this memory item in seconds."""
|
||||
return (datetime.now() - self.created_at).total_seconds()
|
||||
return (_utcnow() - self.created_at).total_seconds()
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -106,14 +111,14 @@ class WorkingMemoryItem:
|
||||
key: str
|
||||
value: Any
|
||||
expires_at: datetime | None = None
|
||||
created_at: datetime = field(default_factory=datetime.now)
|
||||
updated_at: datetime = field(default_factory=datetime.now)
|
||||
created_at: datetime = field(default_factory=_utcnow)
|
||||
updated_at: datetime = field(default_factory=_utcnow)
|
||||
|
||||
def is_expired(self) -> bool:
|
||||
"""Check if this item has expired."""
|
||||
if self.expires_at is None:
|
||||
return False
|
||||
return datetime.now() > self.expires_at
|
||||
return _utcnow() > self.expires_at
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -128,8 +133,8 @@ class TaskState:
|
||||
total_steps: int = 0
|
||||
progress_percent: float = 0.0
|
||||
context: dict[str, Any] = field(default_factory=dict)
|
||||
started_at: datetime = field(default_factory=datetime.now)
|
||||
updated_at: datetime = field(default_factory=datetime.now)
|
||||
started_at: datetime = field(default_factory=_utcnow)
|
||||
updated_at: datetime = field(default_factory=_utcnow)
|
||||
|
||||
|
||||
@dataclass
|
||||
|
||||
Reference in New Issue
Block a user