feat: Phase 2 Memory Core — structured memory with context integration

Memory Core implementation:
- Memory service with 6 types: identity, preference, project, episodic, knowledge, adaptation
- CRUD operations: create (with dedup), get (filtered), update, invalidate, supersede
- Confidence scoring (0.0-1.0) and lifecycle management (active/superseded/invalid)
- Memory API endpoints: POST/GET/PUT/DELETE /memory

Context builder integration (trust precedence per Master Plan):
  1. Trusted Project State (highest trust, 20% budget)
  2. Identity + Preference memories (10% budget)
  3. Retrieved chunks (remaining budget)

Also fixed database.py to use dynamic settings reference for test isolation.
45/45 tests passing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 09:54:52 -04:00
parent 531c560db7
commit b48f0c95ab
7 changed files with 505 additions and 33 deletions

View File

@@ -5,7 +5,7 @@ from contextlib import contextmanager
from pathlib import Path
from typing import Generator
from atocore.config import settings
import atocore.config as _config
from atocore.observability.logger import get_logger
log = get_logger("database")
@@ -70,7 +70,7 @@ CREATE INDEX IF NOT EXISTS idx_interactions_project ON interactions(project_id);
def _ensure_data_dir() -> None:
settings.data_dir.mkdir(parents=True, exist_ok=True)
_config.settings.data_dir.mkdir(parents=True, exist_ok=True)
def init_db() -> None:
@@ -78,14 +78,14 @@ def init_db() -> None:
_ensure_data_dir()
with get_connection() as conn:
conn.executescript(SCHEMA_SQL)
log.info("database_initialized", path=str(settings.db_path))
log.info("database_initialized", path=str(_config.settings.db_path))
@contextmanager
def get_connection() -> Generator[sqlite3.Connection, None, None]:
"""Get a database connection with row factory."""
_ensure_data_dir()
conn = sqlite3.connect(str(settings.db_path))
conn = sqlite3.connect(str(_config.settings.db_path))
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
try: