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:
@@ -17,6 +17,14 @@ from atocore.context.project_state import (
|
||||
set_state,
|
||||
)
|
||||
from atocore.ingestion.pipeline import ingest_file, ingest_folder, get_ingestion_stats
|
||||
from atocore.memory.service import (
|
||||
MEMORY_TYPES,
|
||||
create_memory,
|
||||
get_memories,
|
||||
invalidate_memory,
|
||||
supersede_memory,
|
||||
update_memory,
|
||||
)
|
||||
from atocore.observability.logger import get_logger
|
||||
from atocore.retrieval.retriever import retrieve
|
||||
from atocore.retrieval.vector_store import get_vector_store
|
||||
@@ -63,6 +71,19 @@ class ContextBuildResponse(BaseModel):
|
||||
chunks: list[dict]
|
||||
|
||||
|
||||
class MemoryCreateRequest(BaseModel):
|
||||
memory_type: str
|
||||
content: str
|
||||
project: str = ""
|
||||
confidence: float = 1.0
|
||||
|
||||
|
||||
class MemoryUpdateRequest(BaseModel):
|
||||
content: str | None = None
|
||||
confidence: float | None = None
|
||||
status: str | None = None
|
||||
|
||||
|
||||
class ProjectStateSetRequest(BaseModel):
|
||||
project: str
|
||||
category: str
|
||||
@@ -153,6 +174,77 @@ def api_build_context(req: ContextBuildRequest) -> ContextBuildResponse:
|
||||
)
|
||||
|
||||
|
||||
@router.post("/memory")
|
||||
def api_create_memory(req: MemoryCreateRequest) -> dict:
|
||||
"""Create a new memory entry."""
|
||||
try:
|
||||
mem = create_memory(
|
||||
memory_type=req.memory_type,
|
||||
content=req.content,
|
||||
project=req.project,
|
||||
confidence=req.confidence,
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
return {"status": "ok", "id": mem.id, "memory_type": mem.memory_type}
|
||||
|
||||
|
||||
@router.get("/memory")
|
||||
def api_get_memories(
|
||||
memory_type: str | None = None,
|
||||
active_only: bool = True,
|
||||
min_confidence: float = 0.0,
|
||||
limit: int = 50,
|
||||
) -> dict:
|
||||
"""List memories, optionally filtered."""
|
||||
memories = get_memories(
|
||||
memory_type=memory_type,
|
||||
active_only=active_only,
|
||||
min_confidence=min_confidence,
|
||||
limit=limit,
|
||||
)
|
||||
return {
|
||||
"memories": [
|
||||
{
|
||||
"id": m.id,
|
||||
"memory_type": m.memory_type,
|
||||
"content": m.content,
|
||||
"confidence": m.confidence,
|
||||
"status": m.status,
|
||||
"updated_at": m.updated_at,
|
||||
}
|
||||
for m in memories
|
||||
],
|
||||
"types": MEMORY_TYPES,
|
||||
}
|
||||
|
||||
|
||||
@router.put("/memory/{memory_id}")
|
||||
def api_update_memory(memory_id: str, req: MemoryUpdateRequest) -> dict:
|
||||
"""Update an existing memory."""
|
||||
try:
|
||||
success = update_memory(
|
||||
memory_id=memory_id,
|
||||
content=req.content,
|
||||
confidence=req.confidence,
|
||||
status=req.status,
|
||||
)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Memory not found")
|
||||
return {"status": "updated", "id": memory_id}
|
||||
|
||||
|
||||
@router.delete("/memory/{memory_id}")
|
||||
def api_invalidate_memory(memory_id: str) -> dict:
|
||||
"""Invalidate a memory (error correction)."""
|
||||
success = invalidate_memory(memory_id)
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Memory not found")
|
||||
return {"status": "invalidated", "id": memory_id}
|
||||
|
||||
|
||||
@router.post("/project/state")
|
||||
def api_set_project_state(req: ProjectStateSetRequest) -> dict:
|
||||
"""Set or update a trusted project state entry."""
|
||||
|
||||
Reference in New Issue
Block a user