Files
basicmachines-co-basic-memory/src/basic_memory/schemas/base.py
T

203 lines
6.1 KiB
Python

"""Core pydantic models for basic-memory entities, observations, and relations.
This module defines the foundational data structures for the knowledge graph system.
The graph consists of entities (nodes) connected by relations (edges), where each
entity can have multiple observations (facts) attached to it.
Key Concepts:
1. Entities are nodes with a type and name, storing factual observations
2. Relations are directed edges between entities using active voice verbs
3. Observations are atomic facts/notes about an entity
4. Everything is stored in both SQLite and markdown files
5. Entity IDs are auto-generated as '{type}/{normalized_name}'
Common Entity Types:
- 'person': People (contributors, users, etc.)
- 'project': Major initiatives or repositories
- 'component': Software components/modules
- 'concept': Ideas or abstract concepts
- 'conversation': Chat discussions
- 'document': Documentation or specifications
- 'implementation': Specific code implementations
- 'test': Test suites or test cases
Common Relation Types:
- 'created': Attribution of creation
- 'depends_on': Technical dependency
- 'implements': Implementation of concept/design
- 'documents': Documentation relationship
- 'related_to': General relation
- 'part_of': Compositional relationship
- 'extends': Inheritance/extension
- 'tested_by': Test coverage
"""
from typing import List, Optional, Annotated
from annotated_types import MinLen, MaxLen
from pydantic import BaseModel, BeforeValidator
# Strip whitespace
def strip_whitespace(obs: str) -> str:
return obs.strip()
def lower_strip_whitespace(val: str) -> str:
return strip_whitespace(val.lower())
Observation = Annotated[str, BeforeValidator(strip_whitespace), MinLen(1), MaxLen(1000)]
"""A single piece of information about an entity. Must be non-empty and under 1000 characters.
Best Practices:
- Keep observations atomic (one fact per observation)
- Use clear, complete sentences
- Include context when relevant
- Avoid duplicating information
Examples:
- "Implements SQLite storage for persistence"
- "Created on December 10, 2024"
- "Depends on SQLAlchemy for database operations"
"""
EntityType = Annotated[str, BeforeValidator(strip_whitespace), MinLen(1), MaxLen(200)]
"""Classification of entity (e.g., 'person', 'project', 'concept').
The type serves multiple purposes:
1. Organizes entities in the filesystem
2. Enables filtering and querying
3. Provides context for relations
4. Helps generate meaningful IDs
Common types are listed in the module docstring.
"""
RelationType = Annotated[str, BeforeValidator(strip_whitespace), MinLen(1), MaxLen(200)]
"""Type of relationship between entities. Always use active voice present tense.
Guidelines:
1. Use verbs that clearly describe the relationship
2. Keep it concise but unambiguous
3. Consider bidirectional meaning
4. Use established types when possible
Common types are listed in the module docstring.
"""
class Relation(BaseModel):
"""Represents a directed edge between entities in the knowledge graph.
Relations are directed connections stored in active voice (e.g., "created", "depends_on").
The from_id represents the source or actor entity, while to_id represents the target
or recipient entity.
Example Relations:
1. Person creates Project:
{
"from_id": "person/alice",
"to_id": "project/basic_memory",
"relation_type": "created"
}
2. Component depends on another:
{
"from_id": "component/memory_service",
"to_id": "component/database_service",
"relation_type": "depends_on"
}
3. Test validates Implementation:
{
"from_id": "test/memory_service_test",
"to_id": "implementation/memory_service",
"relation_type": "validates"
}
4. Document describes Component:
{
"from_id": "document/architecture_spec",
"to_id": "component/memory_service",
"relation_type": "describes"
}
"""
from_id: int
to_id: int
relation_type: RelationType
context: Optional[str] = None
class Entity(BaseModel):
"""Represents a node in our knowledge graph - could be a person, project, concept, etc.
Each entity has:
- A unique name (used to generate its ID)
- An entity type (for classification)
- A list of observations (facts/notes about the entity)
- Optional relations to other entities
- Optional description for high-level overview
Example Entities:
1. Project Entity:
{
"name": "Basic_Memory",
"entity_type": "project",
"description": "Knowledge graph system for AI-human collaboration",
"observations": [
"Uses SQLite for local-first storage",
"Implements MCP protocol for AI interaction",
"Provides markdown file sync"
]
}
2. Component Entity:
{
"name": "MemoryService",
"entity_type": "component",
"description": "Core service managing knowledge persistence",
"observations": [
"Handles both file and database operations",
"Implements entity lifecycle management",
"Uses SQLAlchemy for database access"
]
}
3. Person Entity:
{
"name": "Alice_Smith",
"entity_type": "person",
"description": "Lead developer on Basic Memory project",
"observations": [
"Focuses on knowledge graph implementation",
"Created initial SQLite integration"
]
}
4. Concept Entity:
{
"name": "Semantic_Search",
"entity_type": "concept",
"description": "Advanced search capabilities in knowledge graphs",
"observations": [
"Uses embeddings for semantic matching",
"Enables natural language queries",
"Planned for future implementation"
]
}
"""
id: Optional[int] = None
name: str
entity_type: EntityType
description: Optional[str] = None
observations: List[Observation] = []
@property
def file_path(self) -> str:
"""The relative file path for this entity."""
return f"{id}.md"