mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
rename entity.name to entity.title
This commit is contained in:
@@ -60,7 +60,7 @@ class KnowledgeWriter:
|
||||
# This prevents duplicate titles when raw content already has a title
|
||||
if not (entity.observations or entity.outgoing_relations):
|
||||
sections.extend([
|
||||
f"# {entity.name}",
|
||||
f"# {entity.title}",
|
||||
"", # Empty line after title
|
||||
])
|
||||
|
||||
@@ -88,7 +88,7 @@ class KnowledgeWriter:
|
||||
])
|
||||
|
||||
for rel in entity.outgoing_relations:
|
||||
line = f"- {rel.relation_type} [[{rel.to_entity.name}]]"
|
||||
line = f"- {rel.relation_type} [[{rel.to_entity.title}]]"
|
||||
if rel.context:
|
||||
line += f" ({rel.context})"
|
||||
sections.append(line)
|
||||
@@ -96,4 +96,4 @@ class KnowledgeWriter:
|
||||
|
||||
# Return joined sections, ensure content isn't empty
|
||||
content = "\n".join(sections).strip()
|
||||
return content if content else f"# {entity.name}"
|
||||
return content if content else f"# {entity.title}"
|
||||
|
||||
@@ -42,7 +42,7 @@ class Entity(Base):
|
||||
|
||||
# Core identity
|
||||
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String)
|
||||
title: Mapped[str] = mapped_column(String)
|
||||
entity_type: Mapped[str] = mapped_column(String)
|
||||
entity_metadata: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
|
||||
content_type: Mapped[str] = mapped_column(String)
|
||||
@@ -85,7 +85,7 @@ class Entity(Base):
|
||||
return self.incoming_relations + self.outgoing_relations
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Entity(id={self.id}, name='{self.name}', type='{self.entity_type}', summary='{self.summary}')"
|
||||
return f"Entity(id={self.id}, name='{self.title}', type='{self.entity_type}', summary='{self.summary}')"
|
||||
|
||||
|
||||
class ObservationCategory(str, Enum):
|
||||
|
||||
@@ -81,7 +81,7 @@ class EntityRepository(Repository[Entity]):
|
||||
self.select()
|
||||
.where(
|
||||
or_(
|
||||
Entity.name.ilike(search_term),
|
||||
Entity.title.ilike(search_term),
|
||||
Entity.entity_type.ilike(search_term),
|
||||
Entity.summary.ilike(search_term),
|
||||
Entity.observations.any(Observation.content.ilike(search_term)),
|
||||
|
||||
@@ -96,7 +96,7 @@ class ActivityService:
|
||||
change_type=change_type,
|
||||
timestamp=updated_at,
|
||||
path_id=entity.path_id,
|
||||
summary=f"{change_type.value.title()} entity: {entity.name}",
|
||||
summary=f"{change_type.value.title()} entity: {entity.title}",
|
||||
content=entity.summary
|
||||
)
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ class SearchService:
|
||||
# Build searchable content
|
||||
content = "\n".join(
|
||||
[
|
||||
entity.name,
|
||||
entity.title,
|
||||
entity.summary or "",
|
||||
# Add observations
|
||||
*[f"{obs.category}: {obs.content}" for obs in entity.observations],
|
||||
|
||||
@@ -23,7 +23,7 @@ def entity_model_from_markdown(file_path: str, markdown: EntityMarkdown) -> Enti
|
||||
return obs.category
|
||||
|
||||
model = EntityModel(
|
||||
name=markdown.frontmatter.title,
|
||||
title=markdown.frontmatter.title,
|
||||
entity_type=markdown.frontmatter.type,
|
||||
path_id=markdown.frontmatter.id,
|
||||
file_path=file_path,
|
||||
@@ -82,7 +82,7 @@ class EntitySyncService:
|
||||
raise EntityNotFoundError(f"Entity not found: {path_id}")
|
||||
|
||||
# Update fields from markdown
|
||||
db_entity.name = markdown.frontmatter.title
|
||||
db_entity.title = markdown.frontmatter.title
|
||||
db_entity.entity_type = markdown.frontmatter.type
|
||||
db_entity.summary = markdown.content.content
|
||||
|
||||
@@ -106,7 +106,7 @@ class EntitySyncService:
|
||||
return await self.entity_repository.update(
|
||||
db_entity.id,
|
||||
{
|
||||
"name": db_entity.name,
|
||||
"name": db_entity.title,
|
||||
"entity_type": db_entity.entity_type,
|
||||
"summary": db_entity.summary,
|
||||
# Mark as incomplete
|
||||
|
||||
@@ -68,7 +68,7 @@ async def test_create_entity(entity_repository: EntityRepository):
|
||||
|
||||
# Verify returned object
|
||||
assert entity.id is not None
|
||||
assert entity.name == "Test"
|
||||
assert entity.title == "Test"
|
||||
assert entity.summary == "Test description"
|
||||
assert isinstance(entity.created_at, datetime)
|
||||
assert isinstance(entity.updated_at, datetime)
|
||||
@@ -78,7 +78,7 @@ async def test_create_entity(entity_repository: EntityRepository):
|
||||
assert found is not None
|
||||
assert found.id is not None
|
||||
assert found.id == entity.id
|
||||
assert found.name == entity.name
|
||||
assert found.title == entity.title
|
||||
assert found.summary == entity.summary
|
||||
|
||||
# assert relations are eagerly loaded
|
||||
@@ -117,7 +117,7 @@ async def test_create_all(entity_repository: EntityRepository):
|
||||
assert found is not None
|
||||
assert found.id is not None
|
||||
assert found.id == entity.id
|
||||
assert found.name == entity.name
|
||||
assert found.title == entity.title
|
||||
assert found.summary == entity.summary
|
||||
|
||||
# assert relations are eagerly loaded
|
||||
@@ -152,7 +152,7 @@ async def test_find_by_id(entity_repository: EntityRepository, sample_entity: En
|
||||
found = await entity_repository.find_by_id(sample_entity.id)
|
||||
assert found is not None
|
||||
assert found.id == sample_entity.id
|
||||
assert found.name == sample_entity.name
|
||||
assert found.title == sample_entity.title
|
||||
|
||||
# Verify against direct database query
|
||||
async with db.scoped_session(entity_repository.session_maker) as session:
|
||||
@@ -160,7 +160,7 @@ async def test_find_by_id(entity_repository: EntityRepository, sample_entity: En
|
||||
result = await session.execute(stmt)
|
||||
db_entity = result.scalar_one()
|
||||
assert db_entity.id == found.id
|
||||
assert db_entity.name == found.name
|
||||
assert db_entity.title == found.title
|
||||
assert db_entity.summary == found.summary
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ async def test_update_entity(entity_repository: EntityRepository, sample_entity:
|
||||
)
|
||||
assert updated is not None
|
||||
assert updated.summary == "Updated description"
|
||||
assert updated.name == sample_entity.name # Other fields unchanged
|
||||
assert updated.title == sample_entity.title # Other fields unchanged
|
||||
|
||||
# Verify in database
|
||||
async with db.scoped_session(entity_repository.session_maker) as session:
|
||||
@@ -180,7 +180,7 @@ async def test_update_entity(entity_repository: EntityRepository, sample_entity:
|
||||
result = await session.execute(stmt)
|
||||
db_entity = result.scalar_one()
|
||||
assert db_entity.summary == "Updated description"
|
||||
assert db_entity.name == sample_entity.name
|
||||
assert db_entity.title == sample_entity.title
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -314,21 +314,21 @@ async def test_find_by_path_ids(entity_repository: EntityRepository, test_entiti
|
||||
path_ids = [e.path_id for e in test_entities]
|
||||
found = await entity_repository.find_by_path_ids(path_ids)
|
||||
assert len(found) == 3
|
||||
names = {e.name for e in found}
|
||||
names = {e.title for e in found}
|
||||
assert names == {"entity1", "entity2", "entity3"}
|
||||
|
||||
# Test finding subset of entities
|
||||
path_ids = [e.path_id for e in test_entities if e.name != "entity2"]
|
||||
path_ids = [e.path_id for e in test_entities if e.title != "entity2"]
|
||||
found = await entity_repository.find_by_path_ids(path_ids)
|
||||
assert len(found) == 2
|
||||
names = {e.name for e in found}
|
||||
names = {e.title for e in found}
|
||||
assert names == {"entity1", "entity3"}
|
||||
|
||||
# Test with non-existent entities
|
||||
path_ids = ["type1/entity1", "type3/nonexistent"]
|
||||
found = await entity_repository.find_by_path_ids(path_ids)
|
||||
assert len(found) == 1
|
||||
assert found[0].name == "entity1"
|
||||
assert found[0].title == "entity1"
|
||||
|
||||
# Test empty input
|
||||
found = await entity_repository.find_by_path_ids([])
|
||||
@@ -339,14 +339,14 @@ async def test_find_by_path_ids(entity_repository: EntityRepository, test_entiti
|
||||
async def test_delete_by_path_ids(entity_repository: EntityRepository, test_entities):
|
||||
"""Test deleting entities by type/name pairs."""
|
||||
# Test deleting multiple entities
|
||||
path_ids = [e.path_id for e in test_entities if e.name != "entity3"]
|
||||
path_ids = [e.path_id for e in test_entities if e.title != "entity3"]
|
||||
deleted_count = await entity_repository.delete_by_path_ids(path_ids)
|
||||
assert deleted_count == 2
|
||||
|
||||
# Verify deletions
|
||||
remaining = await entity_repository.find_all()
|
||||
assert len(remaining) == 1
|
||||
assert remaining[0].name == "entity3"
|
||||
assert remaining[0].title == "entity3"
|
||||
|
||||
# Test deleting non-existent entities
|
||||
path__ids = ["type3/nonexistent"]
|
||||
@@ -433,7 +433,7 @@ async def test_list_entities_with_related(entity_repository: EntityRepository, s
|
||||
# Test 1: List without related entities
|
||||
services = await entity_repository.list_entities(entity_type="test", include_related=False)
|
||||
assert len(services) == 2
|
||||
service_names = {s.name for s in services}
|
||||
service_names = {s.title for s in services}
|
||||
assert service_names == {"service_config", "db_service"}
|
||||
|
||||
# Test 2: List services with related entities
|
||||
@@ -442,10 +442,10 @@ async def test_list_entities_with_related(entity_repository: EntityRepository, s
|
||||
)
|
||||
assert len(services_and_related) == 3
|
||||
# Should include both services and the config
|
||||
entity_names = {e.name for e in services_and_related}
|
||||
entity_names = {e.title for e in services_and_related}
|
||||
assert entity_names == {"core_service", "db_service", "service_config"}
|
||||
|
||||
# Test 3: Verify relations are loaded
|
||||
core_service = next(e for e in services_and_related if e.name == "core_service")
|
||||
core_service = next(e for e in services_and_related if e.title == "core_service")
|
||||
assert len(core_service.outgoing_relations) > 0 # Has incoming relation from config
|
||||
assert len(core_service.incoming_relations) > 0 # Has outgoing relation to db
|
||||
|
||||
@@ -41,7 +41,7 @@ async def test_add(repository):
|
||||
# Verify we can find in db
|
||||
found = await repository.find_by_id("test_add")
|
||||
assert found is not None
|
||||
assert found.name == "Test Add"
|
||||
assert found.title == "Test Add"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -54,7 +54,7 @@ async def test_add_all(repository):
|
||||
# Verify we can find them in db
|
||||
found = await repository.find_by_id("test_0")
|
||||
assert found is not None
|
||||
assert found.name == "Test 0"
|
||||
assert found.title == "Test 0"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -69,7 +69,7 @@ async def test_bulk_create(repository):
|
||||
# Verify we can find them in db
|
||||
found = await repository.find_by_id("test_0")
|
||||
assert found is not None
|
||||
assert found.name == "Test 0"
|
||||
assert found.title == "Test 0"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -31,7 +31,7 @@ async def test_create_entity(entity_service: EntityService, file_service: FileSe
|
||||
|
||||
# Assert Entity
|
||||
assert isinstance(entity, EntityModel)
|
||||
assert entity.name == "TestEntity"
|
||||
assert entity.title == "TestEntity"
|
||||
assert entity.path_id == entity_data.path_id
|
||||
assert entity.file_path == entity_data.file_path
|
||||
assert entity.entity_type == "test"
|
||||
@@ -43,7 +43,7 @@ async def test_create_entity(entity_service: EntityService, file_service: FileSe
|
||||
# Verify we can retrieve it using path_id
|
||||
retrieved = await entity_service.get_by_path_id(entity_data.path_id)
|
||||
assert retrieved.summary == "A test entity description"
|
||||
assert retrieved.name == "TestEntity"
|
||||
assert retrieved.title == "TestEntity"
|
||||
assert retrieved.entity_type == "test"
|
||||
assert retrieved.summary == "A test entity description"
|
||||
assert retrieved.created_at is not None
|
||||
@@ -88,7 +88,7 @@ async def test_create_entities(entity_service: EntityService, file_service: File
|
||||
assert len(entities) == 2
|
||||
entity1 = entities[0]
|
||||
assert isinstance(entity1, EntityModel)
|
||||
assert entity1.name == "TestEntity1"
|
||||
assert entity1.title == "TestEntity1"
|
||||
assert entity1.entity_type == "test"
|
||||
assert entity1.summary == "A test entity description"
|
||||
assert entity1.created_at is not None
|
||||
@@ -97,7 +97,7 @@ async def test_create_entities(entity_service: EntityService, file_service: File
|
||||
|
||||
entity2 = entities[1]
|
||||
assert isinstance(entity1, EntityModel)
|
||||
assert entity2.name == "TestEntity2"
|
||||
assert entity2.title == "TestEntity2"
|
||||
assert entity2.entity_type == "test"
|
||||
assert entity2.summary == "A test entity description"
|
||||
assert entity2.created_at is not None
|
||||
@@ -180,7 +180,7 @@ async def test_get_entity_success(entity_service: EntityService):
|
||||
retrieved = await entity_service.get_by_path_id(entity_data.path_id)
|
||||
|
||||
assert isinstance(retrieved, EntityModel)
|
||||
assert retrieved.name == "TestEntity"
|
||||
assert retrieved.title == "TestEntity"
|
||||
assert retrieved.entity_type == "test"
|
||||
assert retrieved.summary == "Test description"
|
||||
|
||||
@@ -226,7 +226,7 @@ async def test_create_entity_with_special_chars(entity_service: EntityService):
|
||||
)
|
||||
entity = await entity_service.create_entity(entity_data)
|
||||
|
||||
assert entity.name == name
|
||||
assert entity.title == name
|
||||
assert entity.summary == description
|
||||
|
||||
# Verify after retrieval using path_id
|
||||
@@ -275,7 +275,7 @@ async def test_open_nodes_by_path_ids(entity_service: EntityService):
|
||||
found = await entity_service.open_nodes(path_ids)
|
||||
|
||||
assert len(found) == 2
|
||||
names = {e.name for e in found}
|
||||
names = {e.title for e in found}
|
||||
assert names == {"Entity1", "Entity2"}
|
||||
|
||||
|
||||
@@ -301,7 +301,7 @@ async def test_open_nodes_some_not_found(entity_service: EntityService):
|
||||
found = await entity_service.open_nodes(path_ids)
|
||||
|
||||
assert len(found) == 1
|
||||
assert found[0].name == "Entity1"
|
||||
assert found[0].title == "Entity1"
|
||||
|
||||
|
||||
async def test_delete_entities_by_path_ids(entity_service: EntityService):
|
||||
@@ -439,7 +439,7 @@ async def test_update_entity_name(entity_service: EntityService, file_service: F
|
||||
updated = await entity_service.update_entity(entity.path_id, name="new-name")
|
||||
|
||||
# Verify name was updated in DB
|
||||
assert updated.name == "new-name"
|
||||
assert updated.title == "new-name"
|
||||
|
||||
# Verify frontmatter was updated in file
|
||||
file_path = file_service.get_entity_path(updated)
|
||||
|
||||
@@ -90,8 +90,8 @@ async def test_create_relations(
|
||||
content, _ = await file_service.read_file(file_path)
|
||||
|
||||
# verify relation format
|
||||
assert f"- type_0 [[{entity2.name}]] (context_0)" in content
|
||||
assert f"- type_1 [[{entity2.name}]] (context_1)" in content
|
||||
assert f"- type_0 [[{entity2.title}]] (context_0)" in content
|
||||
assert f"- type_1 [[{entity2.title}]] (context_1)" in content
|
||||
|
||||
# Verify other entity file is not updated
|
||||
found = await entity_service.get_by_path_id(entity2.path_id)
|
||||
|
||||
@@ -62,7 +62,7 @@ async def test_create_entity_without_relations(
|
||||
entity = await knowledge_sync_service.create_entity_from_markdown("test.md", test_markdown)
|
||||
|
||||
# Check basic fields
|
||||
assert entity.name == "Test Entity"
|
||||
assert entity.title == "Test Entity"
|
||||
assert entity.entity_type == "knowledge"
|
||||
assert entity.path_id == "concept/test_entity"
|
||||
assert entity.summary == "A test entity description"
|
||||
@@ -98,7 +98,7 @@ async def test_update_entity_without_relations(
|
||||
)
|
||||
|
||||
# Check fields updated
|
||||
assert updated.name == "Updated Title"
|
||||
assert updated.title == "Updated Title"
|
||||
assert updated.summary == "Updated description"
|
||||
assert len(updated.observations) == 1
|
||||
assert updated.observations[0].content == "Updated observation"
|
||||
|
||||
Reference in New Issue
Block a user