Files
Apple 90758facae 🧠 Add Agent Memory System with PostgreSQL + Qdrant + Cohere
Features:
- Three-tier memory architecture (short/mid/long-term)
- PostgreSQL schema for conversations, events, memories
- Qdrant vector database for semantic search
- Cohere embeddings (embed-multilingual-v3.0, 1024 dims)
- FastAPI Memory Service with full CRUD
- External Secrets integration with Vault
- Kubernetes deployment manifests

Components:
- infrastructure/database/agent-memory-schema.sql
- infrastructure/kubernetes/apps/qdrant/
- infrastructure/kubernetes/apps/memory-service/
- services/memory-service/ (FastAPI app)

Also includes:
- External Secrets Operator
- Traefik Ingress Controller
- Cert-Manager with Let's Encrypt
- ArgoCD for GitOps
2026-01-10 07:52:32 -08:00

250 lines
6.2 KiB
Python

"""
DAARION Memory Service - Pydantic Models
"""
from datetime import datetime
from typing import Optional, List, Any
from uuid import UUID
from enum import Enum
from pydantic import BaseModel, Field
# ============================================================================
# ENUMS
# ============================================================================
class EventType(str, Enum):
MESSAGE = "message"
TOOL_CALL = "tool_call"
TOOL_RESULT = "tool_result"
DECISION = "decision"
SUMMARY = "summary"
MEMORY_WRITE = "memory_write"
MEMORY_RETRACT = "memory_retract"
ERROR = "error"
class MessageRole(str, Enum):
USER = "user"
ASSISTANT = "assistant"
SYSTEM = "system"
TOOL = "tool"
class MemoryCategory(str, Enum):
PREFERENCE = "preference"
IDENTITY = "identity"
CONSTRAINT = "constraint"
PROJECT_FACT = "project_fact"
RELATIONSHIP = "relationship"
SKILL = "skill"
GOAL = "goal"
CONTEXT = "context"
FEEDBACK = "feedback"
class RetentionPolicy(str, Enum):
PERMANENT = "permanent"
SESSION = "session"
TTL_DAYS = "ttl_days"
UNTIL_REVOKED = "until_revoked"
class FeedbackAction(str, Enum):
CONFIRM = "confirm"
REJECT = "reject"
EDIT = "edit"
DELETE = "delete"
# ============================================================================
# REQUEST MODELS
# ============================================================================
class CreateThreadRequest(BaseModel):
"""Create new conversation thread"""
org_id: UUID
workspace_id: Optional[UUID] = None
user_id: UUID
agent_id: Optional[UUID] = None
title: Optional[str] = None
tags: List[str] = []
metadata: dict = {}
class AddEventRequest(BaseModel):
"""Add event to conversation"""
thread_id: UUID
event_type: EventType
role: Optional[MessageRole] = None
content: Optional[str] = None
tool_name: Optional[str] = None
tool_input: Optional[dict] = None
tool_output: Optional[dict] = None
payload: dict = {}
token_count: Optional[int] = None
model_used: Optional[str] = None
latency_ms: Optional[int] = None
metadata: dict = {}
class CreateMemoryRequest(BaseModel):
"""Create long-term memory item"""
org_id: UUID
workspace_id: Optional[UUID] = None
user_id: UUID
agent_id: Optional[UUID] = None # null = global
category: MemoryCategory
fact_text: str
confidence: float = Field(default=0.8, ge=0, le=1)
source_event_id: Optional[UUID] = None
source_thread_id: Optional[UUID] = None
extraction_method: str = "explicit"
is_sensitive: bool = False
retention: RetentionPolicy = RetentionPolicy.UNTIL_REVOKED
ttl_days: Optional[int] = None
tags: List[str] = []
metadata: dict = {}
class MemoryFeedbackRequest(BaseModel):
"""User feedback on memory"""
memory_id: UUID
user_id: UUID
action: FeedbackAction
new_value: Optional[str] = None
reason: Optional[str] = None
class RetrievalRequest(BaseModel):
"""Semantic retrieval request"""
org_id: UUID
user_id: UUID
agent_id: Optional[UUID] = None
workspace_id: Optional[UUID] = None
queries: List[str]
top_k: int = 10
min_confidence: float = 0.5
include_global: bool = True
categories: Optional[List[MemoryCategory]] = None
class SummaryRequest(BaseModel):
"""Generate summary for thread"""
thread_id: UUID
force: bool = False # force even if under token threshold
# ============================================================================
# RESPONSE MODELS
# ============================================================================
class ThreadResponse(BaseModel):
thread_id: UUID
org_id: UUID
workspace_id: Optional[UUID]
user_id: UUID
agent_id: Optional[UUID]
title: Optional[str]
status: str
message_count: int
total_tokens: int
created_at: datetime
last_activity_at: datetime
class EventResponse(BaseModel):
event_id: UUID
thread_id: UUID
event_type: EventType
role: Optional[MessageRole]
content: Optional[str]
tool_name: Optional[str]
tool_input: Optional[dict]
tool_output: Optional[dict]
payload: dict
token_count: Optional[int]
sequence_num: int
created_at: datetime
class MemoryResponse(BaseModel):
memory_id: UUID
org_id: UUID
workspace_id: Optional[UUID]
user_id: UUID
agent_id: Optional[UUID]
category: MemoryCategory
fact_text: str
confidence: float
is_verified: bool
is_sensitive: bool
retention: RetentionPolicy
valid_from: datetime
valid_to: Optional[datetime]
last_used_at: Optional[datetime]
use_count: int
created_at: datetime
class SummaryResponse(BaseModel):
summary_id: UUID
thread_id: UUID
version: int
summary_text: str
state: dict
events_count: int
compression_ratio: Optional[float]
created_at: datetime
class RetrievalResult(BaseModel):
"""Single retrieval result"""
memory_id: UUID
fact_text: str
category: MemoryCategory
confidence: float
relevance_score: float
agent_id: Optional[UUID]
is_global: bool
class RetrievalResponse(BaseModel):
"""Retrieval response with results"""
results: List[RetrievalResult]
query_count: int
total_results: int
class ContextResponse(BaseModel):
"""Full context for agent prompt"""
thread_id: UUID
summary: Optional[SummaryResponse]
recent_messages: List[EventResponse]
retrieved_memories: List[RetrievalResult]
token_estimate: int
# ============================================================================
# INTERNAL MODELS
# ============================================================================
class EmbeddingRequest(BaseModel):
"""Internal embedding request"""
texts: List[str]
input_type: str = "search_document" # or "search_query"
class QdrantPayload(BaseModel):
"""Qdrant point payload"""
org_id: str
workspace_id: Optional[str]
user_id: str
agent_id: Optional[str]
thread_id: Optional[str]
memory_id: Optional[str]
event_id: Optional[str]
type: str # "memory", "summary", "message"
category: Optional[str]
text: str
created_at: str