diff --git a/basic-memory.md b/basic-memory.md index abc40ff1..b1aedc27 100644 --- a/basic-memory.md +++ b/basic-memory.md @@ -394,9 +394,10 @@ def generate_context(self, previous_conversations): """Create a quick summary of relevant past discussions""" recent_decisions = self.extract_key_decisions(previous_conversations) return f"""Previous context: + - Last discussed: {recent_decisions} - Open questions: {self.get_open_questions()} -""" + """ Practical Index Views @@ -619,7 +620,7 @@ continues_from: memory://basic-memory/20241210-previous-chat key_decisions: - adopt_memory_uri_scheme - enhance_frontmatter -related_entities: +related_results: - memory://basic-memory/markdown-service - memory://basic-memory/schema-design tags: [ technical, design, architecture ] @@ -655,7 +656,7 @@ Examples: ```yaml continues_from: memory://basic-memory/previous-chat -related_entities: +related_results: - memory://basic-memory/feature-x - memory://basic-memory/decision-y ``` @@ -866,7 +867,7 @@ async def analyze_feature(uri: str) -> Analysis: feature = await load_entity(uri) # Follow relevant links - related = await load_related_entities(feature.related_features) + related = await load_related_results(feature.related_features) decisions = await load_entities(feature.key_decisions) # Load broader context @@ -1073,7 +1074,7 @@ context = await tools.build_context( # Gets back structured context Context( primary=entity, # The main entity - related_entities=[...], # Related entities + related_results=[...], # Related entities discussions=[...], # Relevant chats/discussions summary="..." # AI-friendly summary ) @@ -1168,7 +1169,7 @@ class ContextBuilder: # Build and cache result context = Context( primary=entity, - related_entities=related, + related_results=related, discussions=discussions, summary=summary ) @@ -1276,7 +1277,7 @@ async def merge_contexts( all_discussions = set() for ctx in contexts: - all_entities.update(ctx.related_entities) + all_entities.update(ctx.related_results) all_discussions.update(ctx.discussions) return Context( diff --git a/src/basic_memory/api/routers/memory_router.py b/src/basic_memory/api/routers/memory_router.py index 6748d932..56b9821a 100644 --- a/src/basic_memory/api/routers/memory_router.py +++ b/src/basic_memory/api/routers/memory_router.py @@ -1,12 +1,15 @@ """Routes for memory:// URI operations.""" + from dataclasses import asdict -from typing import List, Optional from datetime import datetime, timedelta +from typing import Optional + from fastapi import APIRouter +from loguru import logger from basic_memory.config import config -from basic_memory.schemas.memory import MemoryUrl, GraphContext from basic_memory.deps import ContextServiceDep +from basic_memory.schemas.memory import MemoryUrl, GraphContext from basic_memory.schemas.search import SearchResult, RelatedResult router = APIRouter(prefix="/memory", tags=["memory"]) @@ -36,22 +39,26 @@ async def get_memory_context( uri: str, depth: int = 1, timeframe: str = "7d", - max_results: int = 10 + max_results: int = 10, ) -> GraphContext: """Get rich context from memory:// URI.""" # add the project name from the config to the url as the "host # Parse URI + logger.debug(f"Getting context for URI: `{uri}` depth: `{depth}` timeframe: `{timeframe}` max_results: `{max_results}`") memory_url = MemoryUrl(f"memory://{config.project}/{uri}") # Parse timeframe since = parse_timeframe(timeframe) # Build context - context = await context_service.build_context(memory_url, depth=depth, since=since, max_results=max_results) + context = await context_service.build_context( + memory_url, depth=depth, since=since, max_results=max_results + ) - primary_entities = [SearchResult(**asdict(r)) for r in context["primary_entities"]] - related_entities = [RelatedResult(**asdict(r)) for r in context["related_entities"]] + primary_results = [SearchResult(**asdict(r)) for r in context["primary_results"]] + related_results = [RelatedResult(**asdict(r)) for r in context["related_results"]] metadata = context["metadata"] # Transform to GraphContext - return GraphContext(primary_entities=primary_entities, related_entities=related_entities, metadata=metadata) - + return GraphContext( + primary_results=primary_results, related_results=related_results, metadata=metadata + ) diff --git a/src/basic_memory/mcp/tools/memory.py b/src/basic_memory/mcp/tools/memory.py index ece53827..f0b347e6 100644 --- a/src/basic_memory/mcp/tools/memory.py +++ b/src/basic_memory/mcp/tools/memory.py @@ -13,10 +13,7 @@ from basic_memory.schemas.memory import GraphContext, MemoryUrl description="Build context from a memory:// URI to continue conversations naturally.", ) async def build_context( - url: MemoryUrl, - depth: Optional[int] = 1, - timeframe: Optional[str] = "7d", - max_results: int = 10 + url: MemoryUrl, depth: Optional[int] = 1, timeframe: Optional[str] = "7d", max_results: int = 10 ) -> GraphContext: """Get context needed to continue a discussion. @@ -33,14 +30,15 @@ async def build_context( Returns: GraphContext containing: - - primary_entities: Directly matched content - - related_entities: Connected content via relations + - primary_results: Directly matched content + - related_results: Connected content via relations - metadata: Context building info """ logger.info(f"Building context from {url}") # Map directly to the memory endpoint memory_url = MemoryUrl.validate(url) response = await client.get( - f"/memory/{memory_url.relative_path()}", params={"depth": depth, "timeframe": timeframe, "max_results": max_results} + f"/memory/{memory_url.relative_path()}", + params={"depth": depth, "timeframe": timeframe, "max_results": max_results}, ) - return GraphContext.model_validate(response.json()) \ No newline at end of file + return GraphContext.model_validate(response.json()) diff --git a/src/basic_memory/schemas/memory.py b/src/basic_memory/schemas/memory.py index 07e86031..abb4b9a6 100644 --- a/src/basic_memory/schemas/memory.py +++ b/src/basic_memory/schemas/memory.py @@ -1,10 +1,11 @@ """Schemas for memory context.""" -from typing import Dict, List, Optional, Any +from typing import Dict, List, Any + from pydantic import AnyUrl, Field, BaseModel -from basic_memory.schemas.search import SearchResult, RelatedResult from basic_memory.config import config +from basic_memory.schemas.search import SearchResult, RelatedResult """Memory URL schema for knowledge addressing. @@ -18,8 +19,8 @@ Examples: class MemoryUrl(AnyUrl): """memory:// URL scheme for knowledge addressing.""" - - allowed_schemes = {'memory'} + + allowed_schemes = {"memory"} # Query params params: Dict[str, Any] = Field(default_factory=dict) # For special modes like 'related' @@ -29,7 +30,7 @@ class MemoryUrl(AnyUrl): """Validate and construct a MemoryUrl.""" memory_url = cls(url) - + # if the url host value is not the project name, assume the default project if memory_url.host != config.project: memory_url = cls(f"memory://{config.project}/{memory_url.host}{memory_url.path}") @@ -50,10 +51,10 @@ class GraphContext(BaseModel): """Complete context response.""" # Direct matches - primary_entities: List[SearchResult] = Field(description="Entities directly matching URI") + primary_results: List[SearchResult] = Field(description="Entities directly matching URI") # Related entities - related_entities: List[RelatedResult] = Field(description="Entities found via relations") + related_results: List[RelatedResult] = Field(description="Entities found via relations") # Context metadata metadata: Dict[str, Any] = Field( @@ -63,8 +64,8 @@ class GraphContext(BaseModel): "depth": 2, "timeframe": "7d", "generated_at": "2024-01-14T12:00:00Z", - "matched_entities": 3, - "total_entities": 8, + "matched_results": 3, + "total_results": 8, "total_relations": 12, }, - ) \ No newline at end of file + ) diff --git a/src/basic_memory/services/context_service.py b/src/basic_memory/services/context_service.py index 3e81a472..bac0a611 100644 --- a/src/basic_memory/services/context_service.py +++ b/src/basic_memory/services/context_service.py @@ -54,7 +54,9 @@ class ContextService: max_results: int = 10, ): """Build rich context from a memory:// URI.""" - logger.debug(f"Building context for URI {memory_url}") + logger.debug( + f"Building context for URI: '{memory_url}' depth: '{depth}' since: '{since}' max_results: '{max_results}'" + ) # Pattern matching - use search if "*" in memory_url.relative_path(): @@ -73,30 +75,30 @@ class ContextService: type_id_pairs = [(r.type, r.id) for r in primary] if primary else [] logger.debug(f"primary type_id_pairs: {type_id_pairs}") - # Find connected content - related = await self.find_connected( + # Find related content + related = await self.find_related( type_id_pairs, max_depth=depth, since=since, max_results=max_results ) - logger.debug(f"Found {len(related)} related entities") + logger.debug(f"Found {len(related)} related results") for r in related: - logger.debug(f"Found related entity: {r}") + logger.debug(f"Found related result: {r}") # Build response return { - "primary_entities": primary, - "related_entities": related, + "primary_results": primary, + "related_results": related, "metadata": { "uri": memory_url.relative_path(), "depth": depth, "timeframe": since.isoformat() if since else None, "generated_at": datetime.now(timezone.utc).isoformat(), - "matched_entities": len(primary), - "total_entities": len(primary) + len(related), + "matched_results": len(primary), + "total_results": len(primary) + len(related), "total_relations": sum(1 for r in related if r.type == SearchItemType.RELATION), }, } - async def find_connected( + async def find_related( self, type_id_pairs: List[Tuple[str, int]], max_depth: int = 1, @@ -125,11 +127,11 @@ class ContextService: # Build date filter date_filter = "AND base.created_at >= :since_date" if since else "" - r1_date_filter = "AND r1.created_at >= :since_date" if since else "" + r1_date_filter = "AND related.created_at >= :since_date" if since else "" related_date_filter = "AND related.created_at >= :since_date" if since else "" query = text(f""" - WITH RECURSIVE context_graph AS MATERIALIZED ( + WITH RECURSIVE context_graph AS ( -- Base case: seed items SELECT id, @@ -165,27 +167,17 @@ class ContextService: cg.depth + 1, cg.root_id, related.created_at, - r1.created_at as relation_date, + related.created_at as relation_date, CASE - WHEN r1.from_id = cg.id THEN 0 -- Outgoing + WHEN related.from_id = cg.id THEN 0 -- Outgoing ELSE 1 -- Incoming END as is_incoming FROM context_graph cg - JOIN search_index r1 ON ( - cg.type = 'entity' AND - r1.type = 'relation' AND - (r1.from_id = cg.id OR r1.to_id = cg.id) - {r1_date_filter} - ) JOIN search_index related ON ( - related.id = r1.id - OR - (related.type = 'entity' AND - (related.id = r1.from_id OR related.id = r1.to_id)) - OR - (related.type = 'observation' AND - (related.entity_id = r1.from_id OR related.entity_id = r1.to_id)) - {related_date_filter} + cg.type = 'entity' AND + related.type = 'relation' AND + (related.from_id = cg.id OR related.to_id = cg.id) + {r1_date_filter} ) WHERE cg.depth < :max_depth ORDER BY diff --git a/tests/api/test_knowledge_router.py b/tests/api/test_knowledge_router.py index aaf78937..235371a1 100644 --- a/tests/api/test_knowledge_router.py +++ b/tests/api/test_knowledge_router.py @@ -60,7 +60,7 @@ async def add_observations(client, permalink: str) -> List[ObservationResponse]: return obs_response.observations -async def create_related_entities(client) -> List[RelationResponse]: # pyright: ignore [reportReturnType] +async def create_related_results(client) -> List[RelationResponse]: # pyright: ignore [reportReturnType] # Create two entities to relate entities = [ {"title": "SourceEntity", "entity_type": "test"}, @@ -139,7 +139,7 @@ async def test_get_entity(client: AsyncClient): @pytest.mark.asyncio async def test_create_relations(client: AsyncClient): """Should create relations between entities.""" - await create_related_entities(client) + await create_related_results(client) @pytest.mark.asyncio @@ -274,7 +274,7 @@ async def test_delete_observations(client, observation_repository): @pytest.mark.asyncio async def test_delete_relations(client, relation_repository): """Test deleting relations between entities.""" - relations = await create_related_entities(client) + relations = await create_related_results(client) assert len(relations) == 2 relation = relations[0] @@ -354,11 +354,11 @@ async def test_full_knowledge_flow(client: AsyncClient): await client.post("/knowledge/entities", json={"entities": main_entities}) # 2. Create related entities - related_entities = [ + related_results = [ {"title": "RelatedOne", "entity_type": "test"}, {"title": "RelatedTwo", "entity_type": "test"}, ] - await client.post("/knowledge/entities", json={"entities": related_entities}) + await client.post("/knowledge/entities", json={"entities": related_results}) # 3. Add relations relations_response = await client.post( diff --git a/tests/api/test_memory_router.py b/tests/api/test_memory_router.py index c39b8676..cefff054 100644 --- a/tests/api/test_memory_router.py +++ b/tests/api/test_memory_router.py @@ -12,16 +12,16 @@ async def test_get_memory_context(client, test_graph): assert response.status_code == 200 context = GraphContext(**response.json()) - assert len(context.primary_entities) == 1 - assert context.primary_entities[0].permalink == "test/root" - assert len(context.related_entities) > 0 + assert len(context.primary_results) == 1 + assert context.primary_results[0].permalink == "test/root" + assert len(context.related_results) > 0 # Verify metadata assert context.metadata["uri"] == "test/root" assert context.metadata["depth"] == 1 # default depth - #assert context.metadata["timeframe"] == "7d" # default timeframe + # assert context.metadata["timeframe"] == "7d" # default timeframe assert isinstance(context.metadata["generated_at"], str) - assert context.metadata["matched_entities"] == 1 + assert context.metadata["matched_results"] == 1 @pytest.mark.asyncio @@ -31,24 +31,24 @@ async def test_get_memory_context_pattern(client, test_graph): assert response.status_code == 200 context = GraphContext(**response.json()) - assert len(context.primary_entities) > 1 # Should match multiple test/* paths - assert all("test/" in e.permalink for e in context.primary_entities) + assert len(context.primary_results) > 1 # Should match multiple test/* paths + assert all("test/" in e.permalink for e in context.primary_results) @pytest.mark.asyncio async def test_get_memory_context_depth(client, test_graph): """Test depth parameter affects relation traversal.""" # With depth=1, should only get immediate connections - response = await client.get("/memory/test/root?depth=1") + response = await client.get("/memory/test/root?depth=1&max_results=20") assert response.status_code == 200 context1 = GraphContext(**response.json()) # With depth=2, should get deeper connections - response = await client.get("/memory/test/root?depth=2") + response = await client.get("/memory/test/root?depth=3&max_results=20") assert response.status_code == 200 context2 = GraphContext(**response.json()) - assert len(context2.related_entities) > len(context1.related_entities) + assert len(context2.related_results) > len(context1.related_results) @pytest.mark.asyncio @@ -64,7 +64,7 @@ async def test_get_memory_context_timeframe(client, test_graph): assert response.status_code == 200 older = GraphContext(**response.json()) - assert len(older.related_entities) >= len(recent.related_entities) + assert len(older.related_results) >= len(recent.related_results) @pytest.mark.asyncio @@ -76,8 +76,6 @@ async def test_get_related_context_filters(client, test_graph): context = GraphContext(**response.json()) - - @pytest.mark.asyncio async def test_not_found(client): """Test handling of non-existent paths.""" @@ -85,5 +83,5 @@ async def test_not_found(client): assert response.status_code == 200 context = GraphContext(**response.json()) - assert len(context.primary_entities) == 0 - assert len(context.related_entities) == 0 + assert len(context.primary_results) == 0 + assert len(context.related_results) == 0 diff --git a/tests/conftest.py b/tests/conftest.py index 837e1535..d2bb6761 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -291,9 +291,16 @@ async def test_graph(entity_repository, search_service): file_path="test/deep.md", content_type="text/markdown", ), + Entity( + title="Deeper Entity", + entity_type="deeper", + permalink="test/deeper", + file_path="test/deeper.md", + content_type="text/markdown", + ), ] entities = await entity_repository.add_all(entities) - root, conn1, conn2, deep = entities + root, conn1, conn2, deep, deeper = entities # Add some observations root.observations = [ @@ -311,7 +318,9 @@ async def test_graph(entity_repository, search_service): Relation(from_id=root.id, to_id=conn1.id, relation_type="connects_to"), Relation(from_id=conn2.id, to_id=root.id, relation_type="connected_from"), # Deep connection - Relation(from_id=conn1.id, to_id=deep.id, relation_type="deep_connection"), + Relation(from_id=conn2.id, to_id=deep.id, relation_type="deep_connection"), + # Deep connection + Relation(from_id=deep.id, to_id=deeper.id, relation_type="deep_connection"), ] root.outgoing_relations = [relations[0]] diff --git a/tests/mcp/test_tool_memory.py b/tests/mcp/test_tool_memory.py index 567ad340..7a7c853b 100644 --- a/tests/mcp/test_tool_memory.py +++ b/tests/mcp/test_tool_memory.py @@ -1,66 +1,64 @@ """Tests for discussion context MCP tool.""" import pytest + from basic_memory.mcp.tools.memory import build_context from basic_memory.schemas.memory import GraphContext + @pytest.mark.asyncio async def test_get_basic_discussion_context(client, test_graph): """Test getting basic discussion context.""" - context = await build_context( - url="memory://test/root" - ) - + context = await build_context(url="memory://test/root") + assert isinstance(context, GraphContext) - assert len(context.primary_entities) == 1 - assert context.primary_entities[0].permalink == "test/root" - assert len(context.related_entities) > 0 - + assert len(context.primary_results) == 1 + assert context.primary_results[0].permalink == "test/root" + assert len(context.related_results) > 0 + # Verify metadata assert context.metadata["uri"] == "test/root" assert context.metadata["depth"] == 1 # default depth assert context.metadata["timeframe"] is not None assert isinstance(context.metadata["generated_at"], str) - assert context.metadata["matched_entities"] == 1 + assert context.metadata["matched_results"] == 1 + @pytest.mark.asyncio async def test_get_discussion_context_pattern(client, test_graph): """Test getting context with pattern matching.""" - context = await build_context( - url="memory://test/*", - depth=1 - ) - + context = await build_context(url="memory://test/*", depth=1) + assert isinstance(context, GraphContext) - assert len(context.primary_entities) > 1 # Should match multiple test/* paths - assert all("test/" in e.permalink for e in context.primary_entities) + assert len(context.primary_results) > 1 # Should match multiple test/* paths + assert all("test/" in e.permalink for e in context.primary_results) assert context.metadata["depth"] == 1 + @pytest.mark.asyncio async def test_get_discussion_context_timeframe(client, test_graph): """Test timeframe parameter filtering.""" # Get recent context recent_context = await build_context( url="memory://test/root", - timeframe="1d" # Last 24 hours + timeframe="1d", # Last 24 hours ) - + # Get older context older_context = await build_context( url="memory://test/root", - timeframe="30d" # Last 30 days + timeframe="30d", # Last 30 days ) - - assert len(older_context.related_entities) >= len(recent_context.related_entities) + + assert len(older_context.related_results) >= len(recent_context.related_results) + @pytest.mark.asyncio async def test_get_discussion_context_not_found(client): """Test handling of non-existent URIs.""" - context = await build_context( - url="memory://test/does-not-exist" - ) - + context = await build_context(url="memory://test/does-not-exist") + assert isinstance(context, GraphContext) - assert len(context.primary_entities) == 0 - assert len(context.related_entities) == 0 - assert context.metadata["matched_entities"] == 0 + assert len(context.primary_results) == 0 + assert len(context.related_results) == 0 + assert context.metadata["matched_results"] == 0 diff --git a/tests/repository/test_entity_repository.py b/tests/repository/test_entity_repository.py index c50f2207..2914e349 100644 --- a/tests/repository/test_entity_repository.py +++ b/tests/repository/test_entity_repository.py @@ -8,8 +8,8 @@ from sqlalchemy import select from basic_memory import db from basic_memory.models import Entity, Observation, Relation -from basic_memory.utils import generate_permalink from basic_memory.repository.entity_repository import EntityRepository +from basic_memory.utils import generate_permalink @pytest_asyncio.fixture @@ -25,7 +25,7 @@ async def entity_with_observations(session_maker, sample_entity): @pytest_asyncio.fixture -async def related_entities(session_maker): +async def related_results(session_maker): """Create entities with relations between them.""" async with db.scoped_session(session_maker) as session: source = Entity( @@ -245,9 +245,9 @@ async def test_delete_entities_by_type(entity_repository: EntityRepository, samp @pytest.mark.asyncio -async def test_delete_entity_with_relations(entity_repository: EntityRepository, related_entities): +async def test_delete_entity_with_relations(entity_repository: EntityRepository, related_results): """Test deleting an entity cascades to its relations.""" - source, target, relation = related_entities + source, target, relation = related_results # Delete source entity result = await entity_repository.delete(source.id) @@ -454,13 +454,15 @@ async def test_list_entities_with_related(entity_repository: EntityRepository, s async def test_create_entity_with_invalid_permalink(entity_repository: EntityRepository): """Test that creating an entity with invalid permalink raises error.""" with pytest.raises(ValueError, match="Invalid permalink format"): - await entity_repository.create({ - "title": "Test", - "entity_type": "test", - "permalink": "Test/Invalid!!", # Invalid permalink - "file_path": "test/test.md", - "content_type": "text/markdown", - }) + await entity_repository.create( + { + "title": "Test", + "entity_type": "test", + "permalink": "Test/Invalid!!", # Invalid permalink + "file_path": "test/test.md", + "content_type": "text/markdown", + } + ) @pytest.mark.asyncio @@ -485,7 +487,7 @@ async def test_generate_permalink_from_file_path(): entity_type="test", permalink=result, file_path=input_path, - content_type="text/markdown" + content_type="text/markdown", ) # This will raise ValueError if invalid diff --git a/tests/services/test_context_service.py b/tests/services/test_context_service.py index c8c8f41f..6792d547 100644 --- a/tests/services/test_context_service.py +++ b/tests/services/test_context_service.py @@ -17,6 +17,7 @@ async def context_service(search_repository, entity_repository): """Create context service for testing.""" return ContextService(search_repository, entity_repository) + @pytest.mark.asyncio async def test_find_connected_basic(context_service, test_graph, search_service): """Test basic connectivity traversal.""" @@ -26,7 +27,7 @@ async def test_find_connected_basic(context_service, test_graph, search_service) ("observation", test_graph["observations"][0].id), ] - results = await context_service.find_connected(type_id_pairs) + results = await context_service.find_related(type_id_pairs) # Verify types types_found = {r.type for r in results} @@ -54,7 +55,7 @@ async def test_find_connected_depth_limit(context_service, test_graph): type_id_pairs = [("entity", test_graph["root"].id)] # With depth=1, we get direct connections - shallow_results = await context_service.find_connected(type_id_pairs, max_depth=1) + shallow_results = await context_service.find_related(type_id_pairs, max_depth=1) shallow_entities = {(r.id, r.type) for r in shallow_results if r.type == "entity"} # Should find Connected1 and Connected2 assert (test_graph["connected1"].id, "entity") in shallow_entities @@ -63,7 +64,7 @@ async def test_find_connected_depth_limit(context_service, test_graph): assert (test_graph["deep"].id, "entity") not in shallow_entities # With depth=2, we get the next level - deep_results = await context_service.find_connected(type_id_pairs, max_depth=2) + deep_results = await context_service.find_related(type_id_pairs, max_depth=2) deep_entities = {(r.id, r.type) for r in deep_results if r.type == "entity"} # Should now include Deep entity assert (test_graph["deep"].id, "entity") in deep_entities @@ -92,7 +93,7 @@ async def test_find_connected_timeframe(context_service, test_graph, search_repo type=SearchItemType.ENTITY, metadata={"created_at": old_date.isoformat()}, created_at=old_date.isoformat(), - updated_at=old_date.isoformat() + updated_at=old_date.isoformat(), ) ) await search_repository.index_item( @@ -108,7 +109,7 @@ async def test_find_connected_timeframe(context_service, test_graph, search_repo relation_type="connects_to", metadata={"created_at": old_date.isoformat()}, created_at=old_date.isoformat(), - updated_at=old_date.isoformat() + updated_at=old_date.isoformat(), ) ) @@ -123,14 +124,14 @@ async def test_find_connected_timeframe(context_service, test_graph, search_repo type=SearchItemType.ENTITY, metadata={"created_at": recent_date.isoformat()}, created_at=recent_date.isoformat(), - updated_at=recent_date.isoformat() + updated_at=recent_date.isoformat(), ) ) type_id_pairs = [("entity", test_graph["root"].id)] # Search with a 7-day cutoff since_date = now - timedelta(days=7) - results = await context_service.find_connected(type_id_pairs, since=since_date) + results = await context_service.find_related(type_id_pairs, since=since_date) # Only connected1 is recent, but we can't get to it # because its connecting relation is too old @@ -143,17 +144,17 @@ async def test_build_context(context_service, test_graph): """Test exact permalink lookup.""" url = MemoryUrl(f"memory://{config.project}/test/root") results = await context_service.build_context(url) - matched_entities = results["metadata"]["matched_entities"] - primary_entities = results["primary_entities"] - related_entities = results["related_entities"] - total_entities = results["metadata"]["total_entities"] + matched_results = results["metadata"]["matched_results"] + primary_results = results["primary_results"] + related_results = results["related_results"] + total_results = results["metadata"]["total_results"] assert results["metadata"]["uri"] == url.relative_path() assert results["metadata"]["depth"] == 1 - assert matched_entities == 1 - assert len(primary_entities) == 1 - assert len(related_entities) == 8 - assert total_entities == len(primary_entities) + len(related_entities) + assert matched_results == 1 + assert len(primary_results) == 1 + assert len(related_results) == 8 + assert total_results == len(primary_results) + len(related_results) @pytest.mark.asyncio @@ -161,21 +162,20 @@ async def test_build_context_pattern(context_service, test_graph): """Test exact permalink lookup.""" url = MemoryUrl("memory://not_used/test/connected*") results = await context_service.build_context(url) - matched_entities = results["metadata"]["matched_entities"] - primary_entities = results["primary_entities"] - related_entities = results["related_entities"] - total_entities = results["metadata"]["total_entities"] - - #TODO assert pattern found + matched_results = results["metadata"]["matched_results"] + primary_results = results["primary_results"] + related_results = results["related_results"] + total_results = results["metadata"]["total_results"] + # TODO assert pattern found @pytest.mark.asyncio async def test_build_context_not_found(context_service): """Test handling non-existent permalinks.""" context = await context_service.build_context(MemoryUrl("memory://project/does/not/exist")) - assert len(context["primary_entities"]) == 0 - assert len(context["related_entities"]) == 0 + assert len(context["primary_results"]) == 0 + assert len(context["related_results"]) == 0 @pytest.mark.asyncio @@ -186,4 +186,4 @@ async def test_context_metadata(context_service, test_graph): assert metadata["uri"] == "test/root" assert metadata["depth"] == 2 assert metadata["generated_at"] is not None - assert metadata["matched_entities"] > 0 + assert metadata["matched_results"] > 0