mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
"""
|
|
Core pydantic models for basic-memory entities, observations, and relations.
|
|
These models define the schema for our core data types while remaining
|
|
independent from storage/persistence concerns.
|
|
"""
|
|
from datetime import datetime, UTC
|
|
from typing import List, Optional, Dict, Any, Annotated
|
|
from uuid import uuid4
|
|
from annotated_types import Gt, Len
|
|
from pydantic import BaseModel, Field, model_validator, ConfigDict
|
|
|
|
# Base Models
|
|
class ObservationIn(BaseModel):
|
|
"""Schema for creating a single observation."""
|
|
content: str
|
|
context: Optional[str] = None
|
|
|
|
class ObservationsIn(BaseModel):
|
|
"""Schema for adding observations to an entity."""
|
|
entity_id: str = Field(alias="entityId") # Maps to Entity.id
|
|
observations: List[ObservationIn]
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
class ObservationOut(ObservationIn):
|
|
"""Schema for observation data returned from the service."""
|
|
id: int
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class ObservationsOut(BaseModel):
|
|
"""Schema for bulk observation operation results."""
|
|
entity_id: str = Field(alias="entityId")
|
|
observations: List[ObservationOut]
|
|
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
|
|
|
|
class RelationIn(BaseModel):
|
|
"""
|
|
Represents a directed edge between entities in the knowledge graph.
|
|
Relations are always stored in active voice (e.g. "created", "teaches", etc.)
|
|
"""
|
|
from_id: str = Field(alias="fromId")
|
|
to_id: str = Field(alias="toId")
|
|
relation_type: str = Field(alias="relationType")
|
|
context: Optional[str] = None
|
|
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
class RelationOut(BaseModel):
|
|
id: int
|
|
from_id: str = Field(alias="fromId")
|
|
to_id: str = Field(alias="toId")
|
|
relation_type: str = Field(alias="relationType")
|
|
context: Optional[str] = None
|
|
model_config = ConfigDict(from_attributes=True, populate_by_name=True)
|
|
|
|
class EntityBase(BaseModel):
|
|
id: str = Field(default=None) # Allow None during creation
|
|
name: str
|
|
entity_type: str = Field(alias="entityType")
|
|
|
|
@model_validator(mode='after')
|
|
def generate_id(self) -> 'EntityBase':
|
|
"""Generate an ID for this entity if not provided"""
|
|
if not self.id:
|
|
timestamp = datetime.now(UTC).strftime("%Y%m%d")
|
|
normalized_name = self.name.lower().replace(" ", "-")
|
|
self.id = f"{timestamp}-{normalized_name}"
|
|
return self
|
|
|
|
def file_name(self) -> str:
|
|
"""Get the markdown file name for this entity."""
|
|
return f"{self.id}.md"
|
|
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class EntityIn(EntityBase):
|
|
"""
|
|
Represents a node in our knowledge graph - could be a person, project,
|
|
concept, etc. Each entity has a unique name, a type, and a list of
|
|
associated observations.
|
|
"""
|
|
observations: List[ObservationIn] = []
|
|
relations: List[RelationIn] = []
|
|
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
|
|
|
|
class EntityOut(EntityBase):
|
|
"""Schema for entity data returned from the service."""
|
|
observations: List[ObservationOut] = []
|
|
relations: List[RelationOut] = []
|
|
model_config = ConfigDict(populate_by_name=True, from_attributes=True)
|
|
|
|
# Tool Input Schemas
|
|
class CreateEntitiesInput(BaseModel):
|
|
"""Input schema for create_entities tool."""
|
|
entities: Annotated[List[EntityIn], Len(min_length=1)]
|
|
|
|
class SearchNodesInput(BaseModel):
|
|
"""Input schema for search_nodes tool."""
|
|
query: str
|
|
|
|
class OpenNodesInput(BaseModel):
|
|
"""Input schema for open_nodes tool."""
|
|
names: Annotated[List[str], Len(min_length=1)]
|
|
|
|
class AddObservationsInput(BaseModel):
|
|
"""Input schema for add_observations tool."""
|
|
entity_id: str = Field(alias="entityId")
|
|
observations: List[ObservationIn]
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
class CreateRelationsInput(BaseModel):
|
|
"""Input schema for create_relations tool."""
|
|
relations: List[RelationIn]
|
|
|
|
class DeleteEntitiesInput(BaseModel):
|
|
"""Input schema for delete_entities tool."""
|
|
names: List[str]
|
|
|
|
class DeleteObservationsInput(BaseModel):
|
|
"""Input schema for delete_observations tool."""
|
|
deletions: List[Dict[str, Any]] # TODO: Make this more specific
|
|
|
|
# Tool Response Schemas
|
|
class CreateEntitiesResponse(BaseModel):
|
|
"""Response for create_entities tool."""
|
|
entities: List[EntityOut]
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class SearchNodesResponse(BaseModel):
|
|
"""Response for search_nodes tool."""
|
|
matches: List[EntityOut]
|
|
query: str
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class OpenNodesResponse(BaseModel):
|
|
"""Response for open_nodes tool."""
|
|
entities: List[EntityOut]
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class AddObservationsResponse(BaseModel):
|
|
"""Response for add_observations tool."""
|
|
entity_id: str
|
|
added_observations: List[ObservationOut]
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class CreateRelationsResponse(BaseModel):
|
|
"""Response for create_relations tool."""
|
|
relations: List[RelationOut]
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class DeleteEntitiesResponse(BaseModel):
|
|
"""Response for delete_entities tool."""
|
|
deleted: List[str]
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
class DeleteObservationsResponse(BaseModel):
|
|
"""Response for delete_observations tool."""
|
|
entity_id: str
|
|
deleted: List[str]
|
|
model_config = ConfigDict(from_attributes=True) |