From 01cbad1dbe82e5c7b4fc2f25bfb4c59dc01025b4 Mon Sep 17 00:00:00 2001 From: phernandez Date: Sat, 28 Mar 2026 09:56:22 -0500 Subject: [PATCH] Allow long relation_type values in responses Signed-off-by: phernandez --- src/basic_memory/schemas/base.py | 9 +++-- tests/api/v2/test_knowledge_router.py | 52 +++++++++++++++++++++++++++ tests/schemas/test_schemas.py | 20 +++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/basic_memory/schemas/base.py b/src/basic_memory/schemas/base.py index ed16d5db..c7158e77 100644 --- a/src/basic_memory/schemas/base.py +++ b/src/basic_memory/schemas/base.py @@ -178,8 +178,13 @@ ContentType = Annotated[ ] -RelationType = Annotated[str, MinLen(1), MaxLen(200)] -"""Type of relationship between entities. Always use active voice present tense.""" +RelationType = Annotated[str, MinLen(1)] +"""Type of relationship between entities. Always use active voice present tense. + +The database stores relation_type as an unrestricted string, and response models +need to tolerate existing long-form values written by LLMs. Keeping an API-only +200-character cap here causes reads to fail for valid stored data. +""" ObservationStr = Annotated[ str, diff --git a/tests/api/v2/test_knowledge_router.py b/tests/api/v2/test_knowledge_router.py index 9ff4d202..8f653207 100644 --- a/tests/api/v2/test_knowledge_router.py +++ b/tests/api/v2/test_knowledge_router.py @@ -137,6 +137,58 @@ async def test_get_entity_by_id(client: AsyncClient, test_graph, v2_project_url, assert entity.api_version == "v2" +@pytest.mark.asyncio +async def test_get_entity_by_id_allows_long_relation_type( + client: AsyncClient, + v2_project_url, + relation_repository, +): + """GET entity should not fail when stored relation_type exceeds 200 characters.""" + source_response = await client.post( + f"{v2_project_url}/knowledge/entities", + json={ + "title": "Long Relation Source", + "directory": "test", + "content": "Source entity content", + }, + ) + assert source_response.status_code == 200 + source_entity = EntityResponseV2.model_validate(source_response.json()) + + target_response = await client.post( + f"{v2_project_url}/knowledge/entities", + json={ + "title": "Long Relation Target", + "directory": "test", + "content": "Target entity content", + }, + ) + assert target_response.status_code == 200 + target_entity = EntityResponseV2.model_validate(target_response.json()) + + long_relation_type = ( + "**Architecture/efficiency concern:** " + "the orchestration prompt expanded a short edge label into a full descriptive note " + "that is much longer than 200 characters but should still serialize cleanly." + ) + + await relation_repository.create( + { + "from_id": source_entity.id, + "to_id": target_entity.id, + "to_name": target_entity.title, + "relation_type": long_relation_type, + } + ) + + response = await client.get(f"{v2_project_url}/knowledge/entities/{source_entity.external_id}") + + assert response.status_code == 200 + entity = EntityResponseV2.model_validate(response.json()) + assert len(entity.relations) == 1 + assert entity.relations[0].relation_type == long_relation_type + + @pytest.mark.asyncio async def test_get_entity_by_id_not_found(client: AsyncClient, v2_project_url): """Test getting a non-existent entity by external_id returns 404.""" diff --git a/tests/schemas/test_schemas.py b/tests/schemas/test_schemas.py index f4c3c7a7..2cbfb187 100644 --- a/tests/schemas/test_schemas.py +++ b/tests/schemas/test_schemas.py @@ -91,6 +91,26 @@ def test_relation_response(): assert relation.context is None +def test_relation_response_allows_long_relation_type(): + """Long relation labels should round-trip because stored data has no DB length cap.""" + long_relation_type = ( + "**Architecture/efficiency concern:** " + "the orchestration prompt expanded a short edge label into a full descriptive note " + "that is much longer than 200 characters but still represents the stored relation type." + ) + data = { + "permalink": "test/123/long/test/456", + "from_id": "test/123", + "to_id": "test/456", + "relation_type": long_relation_type, + "from_entity": {"permalink": "test/123"}, + "to_entity": {"permalink": "test/456"}, + } + + relation = RelationResponse.model_validate(data) + assert relation.relation_type == long_relation_type + + def test_relation_response_with_null_permalink(): """Test RelationResponse handles null permalinks by falling back to file_path (fixes issue #483).