mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
feat: Add disable_permalinks config flag (#313)
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -90,7 +90,10 @@ async def make_api_request(
|
||||
# Handle both FastAPI HTTPException format (nested under "detail")
|
||||
# and direct format
|
||||
detail_obj = error_detail.get("detail", error_detail)
|
||||
if isinstance(detail_obj, dict) and detail_obj.get("error") == "subscription_required":
|
||||
if (
|
||||
isinstance(detail_obj, dict)
|
||||
and detail_obj.get("error") == "subscription_required"
|
||||
):
|
||||
message = detail_obj.get("message", "Active subscription required")
|
||||
subscribe_url = detail_obj.get(
|
||||
"subscribe_url", "https://basicmemory.com/subscribe"
|
||||
|
||||
@@ -93,11 +93,22 @@ class BasicMemoryConfig(BaseSettings):
|
||||
description="Format for generated filenames. False preserves spaces and special chars, True converts them to hyphens for consistency with permalinks",
|
||||
)
|
||||
|
||||
disable_permalinks: bool = Field(
|
||||
default=False,
|
||||
description="Disable automatic permalink generation in frontmatter. When enabled, new notes won't have permalinks added and sync won't update permalinks. Existing permalinks will still work for reading.",
|
||||
)
|
||||
|
||||
skip_initialization_sync: bool = Field(
|
||||
default=False,
|
||||
description="Skip expensive initialization synchronization. Useful for cloud/stateless deployments where project reconciliation is not needed.",
|
||||
)
|
||||
|
||||
# API connection configuration
|
||||
api_url: Optional[str] = Field(
|
||||
default=None,
|
||||
description="URL of remote Basic Memory API. If set, MCP will connect to this API instead of using local ASGI transport.",
|
||||
)
|
||||
|
||||
# Cloud configuration
|
||||
cloud_client_id: str = Field(
|
||||
default="client_01K6KWQPW6J1M8VV7R3TZP5A6M",
|
||||
|
||||
@@ -260,6 +260,7 @@ async def get_entity_service(
|
||||
entity_parser: EntityParserDep,
|
||||
file_service: FileServiceDep,
|
||||
link_resolver: "LinkResolverDep",
|
||||
app_config: AppConfigDep,
|
||||
) -> EntityService:
|
||||
"""Create EntityService with repository."""
|
||||
return EntityService(
|
||||
@@ -269,6 +270,7 @@ async def get_entity_service(
|
||||
entity_parser=entity_parser,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ class Entity(BaseModel):
|
||||
"""
|
||||
|
||||
# private field to override permalink
|
||||
# Use empty string "" as sentinel to indicate permalinks are explicitly disabled
|
||||
_permalink: Optional[str] = None
|
||||
|
||||
title: str
|
||||
@@ -247,8 +248,11 @@ class Entity(BaseModel):
|
||||
return os.path.join(self.folder, safe_title) if self.folder else safe_title
|
||||
|
||||
@property
|
||||
def permalink(self) -> Permalink:
|
||||
def permalink(self) -> Optional[Permalink]:
|
||||
"""Get a url friendly path}."""
|
||||
# Empty string is a sentinel value indicating permalinks are disabled
|
||||
if self._permalink == "":
|
||||
return None
|
||||
return self._permalink or generate_permalink(self.file_path)
|
||||
|
||||
@model_validator(mode="after")
|
||||
|
||||
@@ -42,6 +42,7 @@ class EntityService(BaseService[EntityModel]):
|
||||
relation_repository: RelationRepository,
|
||||
file_service: FileService,
|
||||
link_resolver: LinkResolver,
|
||||
app_config: Optional[BasicMemoryConfig] = None,
|
||||
):
|
||||
super().__init__(entity_repository)
|
||||
self.observation_repository = observation_repository
|
||||
@@ -49,6 +50,7 @@ class EntityService(BaseService[EntityModel]):
|
||||
self.entity_parser = entity_parser
|
||||
self.file_service = file_service
|
||||
self.link_resolver = link_resolver
|
||||
self.app_config = app_config
|
||||
|
||||
async def detect_file_path_conflicts(self, file_path: str) -> List[Entity]:
|
||||
"""Detect potential file path conflicts for a given file path.
|
||||
@@ -145,9 +147,9 @@ class EntityService(BaseService[EntityModel]):
|
||||
)
|
||||
|
||||
# Try to find existing entity using smart resolution
|
||||
existing = await self.link_resolver.resolve_link(
|
||||
schema.file_path
|
||||
) or await self.link_resolver.resolve_link(schema.permalink)
|
||||
existing = await self.link_resolver.resolve_link(schema.file_path)
|
||||
if not existing and schema.permalink:
|
||||
existing = await self.link_resolver.resolve_link(schema.permalink)
|
||||
|
||||
if existing:
|
||||
logger.debug(f"Found existing entity: {existing.file_path}")
|
||||
@@ -194,9 +196,15 @@ class EntityService(BaseService[EntityModel]):
|
||||
relations=[],
|
||||
)
|
||||
|
||||
# Get unique permalink (prioritizing content frontmatter)
|
||||
permalink = await self.resolve_permalink(file_path, content_markdown)
|
||||
schema._permalink = permalink
|
||||
# Get unique permalink (prioritizing content frontmatter) unless disabled
|
||||
if self.app_config and self.app_config.disable_permalinks:
|
||||
# Use empty string as sentinel to indicate permalinks are disabled
|
||||
# The permalink property will return None when it sees empty string
|
||||
schema._permalink = ""
|
||||
else:
|
||||
# Generate and set permalink
|
||||
permalink = await self.resolve_permalink(file_path, content_markdown)
|
||||
schema._permalink = permalink
|
||||
|
||||
post = await schema_to_markdown(schema)
|
||||
|
||||
@@ -254,15 +262,16 @@ class EntityService(BaseService[EntityModel]):
|
||||
relations=[],
|
||||
)
|
||||
|
||||
# Check if we need to update the permalink based on content frontmatter
|
||||
# Check if we need to update the permalink based on content frontmatter (unless disabled)
|
||||
new_permalink = entity.permalink # Default to existing
|
||||
if content_markdown and content_markdown.frontmatter.permalink:
|
||||
# Resolve permalink with the new content frontmatter
|
||||
resolved_permalink = await self.resolve_permalink(file_path, content_markdown)
|
||||
if resolved_permalink != entity.permalink:
|
||||
new_permalink = resolved_permalink
|
||||
# Update the schema to use the new permalink
|
||||
schema._permalink = new_permalink
|
||||
if self.app_config and not self.app_config.disable_permalinks:
|
||||
if content_markdown and content_markdown.frontmatter.permalink:
|
||||
# Resolve permalink with the new content frontmatter
|
||||
resolved_permalink = await self.resolve_permalink(file_path, content_markdown)
|
||||
if resolved_permalink != entity.permalink:
|
||||
new_permalink = resolved_permalink
|
||||
# Update the schema to use the new permalink
|
||||
schema._permalink = new_permalink
|
||||
|
||||
# Create post with new content from schema
|
||||
post = await schema_to_markdown(schema)
|
||||
@@ -746,8 +755,10 @@ class EntityService(BaseService[EntityModel]):
|
||||
# 6. Prepare database updates
|
||||
updates = {"file_path": destination_path}
|
||||
|
||||
# 7. Update permalink if configured or if entity has null permalink
|
||||
if app_config.update_permalinks_on_move or old_permalink is None:
|
||||
# 7. Update permalink if configured or if entity has null permalink (unless disabled)
|
||||
if not app_config.disable_permalinks and (
|
||||
app_config.update_permalinks_on_move or old_permalink is None
|
||||
):
|
||||
# Generate new permalink from destination path
|
||||
new_permalink = await self.resolve_permalink(destination_path)
|
||||
|
||||
|
||||
@@ -338,8 +338,8 @@ class SyncService:
|
||||
# entity markdown will always contain front matter, so it can be used up create/update the entity
|
||||
entity_markdown = await self.entity_parser.parse_file(path)
|
||||
|
||||
# if the file contains frontmatter, resolve a permalink
|
||||
if file_contains_frontmatter:
|
||||
# if the file contains frontmatter, resolve a permalink (unless disabled)
|
||||
if file_contains_frontmatter and not self.app_config.disable_permalinks:
|
||||
# Resolve permalink - this handles all the cases including conflicts
|
||||
permalink = await self.entity_service.resolve_permalink(path, markdown=entity_markdown)
|
||||
|
||||
@@ -530,8 +530,10 @@ class SyncService:
|
||||
updates = {"file_path": new_path}
|
||||
|
||||
# If configured, also update permalink to match new path
|
||||
if self.app_config.update_permalinks_on_move and self.file_service.is_markdown(
|
||||
new_path
|
||||
if (
|
||||
self.app_config.update_permalinks_on_move
|
||||
and not self.app_config.disable_permalinks
|
||||
and self.file_service.is_markdown(new_path)
|
||||
):
|
||||
# generate new permalink value
|
||||
new_permalink = await self.entity_service.resolve_permalink(new_path)
|
||||
|
||||
@@ -121,7 +121,9 @@ class WatchService:
|
||||
ignore_patterns = self._get_ignore_patterns(project_path)
|
||||
|
||||
if should_ignore_path(file_path, project_path, ignore_patterns):
|
||||
logger.trace(f"Ignoring watched file change: {file_path.relative_to(project_path)}")
|
||||
logger.trace(
|
||||
f"Ignoring watched file change: {file_path.relative_to(project_path)}"
|
||||
)
|
||||
continue
|
||||
|
||||
project_changes[project].append((change, path))
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
"""Integration tests for the disable_permalinks configuration."""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
from basic_memory.config import BasicMemoryConfig
|
||||
from basic_memory.markdown import EntityParser, MarkdownProcessor
|
||||
from basic_memory.models import Project
|
||||
from basic_memory.repository import (
|
||||
EntityRepository,
|
||||
ObservationRepository,
|
||||
RelationRepository,
|
||||
)
|
||||
from basic_memory.repository.search_repository import SearchRepository
|
||||
from basic_memory.schemas import Entity as EntitySchema
|
||||
from basic_memory.services import FileService
|
||||
from basic_memory.services.entity_service import EntityService
|
||||
from basic_memory.services.link_resolver import LinkResolver
|
||||
from basic_memory.services.search_service import SearchService
|
||||
from basic_memory.sync.sync_service import SyncService
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disable_permalinks_create_entity(tmp_path, engine_factory):
|
||||
"""Test that entities created with disable_permalinks=True don't have permalinks."""
|
||||
engine, session_maker = engine_factory
|
||||
|
||||
# Create app config with disable_permalinks=True
|
||||
app_config = BasicMemoryConfig(disable_permalinks=True)
|
||||
|
||||
# Setup repositories
|
||||
entity_repository = EntityRepository(session_maker, project_id=1)
|
||||
observation_repository = ObservationRepository(session_maker, project_id=1)
|
||||
relation_repository = RelationRepository(session_maker, project_id=1)
|
||||
search_repository = SearchRepository(session_maker, project_id=1)
|
||||
|
||||
# Setup services
|
||||
entity_parser = EntityParser(tmp_path)
|
||||
markdown_processor = MarkdownProcessor(entity_parser)
|
||||
file_service = FileService(tmp_path, markdown_processor)
|
||||
search_service = SearchService(search_repository, entity_repository, file_service)
|
||||
await search_service.init_search_index()
|
||||
link_resolver = LinkResolver(entity_repository, search_service)
|
||||
|
||||
entity_service = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
# Create entity via API
|
||||
entity_data = EntitySchema(
|
||||
title="Test Note",
|
||||
folder="test",
|
||||
entity_type="note",
|
||||
content="Test content",
|
||||
)
|
||||
|
||||
created = await entity_service.create_entity(entity_data)
|
||||
|
||||
# Verify entity has no permalink
|
||||
assert created.permalink is None
|
||||
|
||||
# Verify file has no permalink in frontmatter
|
||||
file_path = tmp_path / "test" / "Test Note.md"
|
||||
assert file_path.exists()
|
||||
content = file_path.read_text()
|
||||
assert "permalink:" not in content
|
||||
assert "Test content" in content
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_disable_permalinks_sync_workflow(tmp_path, engine_factory):
|
||||
"""Test full sync workflow with disable_permalinks enabled."""
|
||||
engine, session_maker = engine_factory
|
||||
|
||||
# Create app config with disable_permalinks=True
|
||||
app_config = BasicMemoryConfig(disable_permalinks=True)
|
||||
|
||||
# Create a test markdown file without frontmatter
|
||||
test_file = tmp_path / "test_note.md"
|
||||
test_file.write_text("# Test Note\nThis is test content.")
|
||||
|
||||
# Setup repositories
|
||||
entity_repository = EntityRepository(session_maker, project_id=1)
|
||||
observation_repository = ObservationRepository(session_maker, project_id=1)
|
||||
relation_repository = RelationRepository(session_maker, project_id=1)
|
||||
search_repository = SearchRepository(session_maker, project_id=1)
|
||||
|
||||
# Setup services
|
||||
entity_parser = EntityParser(tmp_path)
|
||||
markdown_processor = MarkdownProcessor(entity_parser)
|
||||
file_service = FileService(tmp_path, markdown_processor)
|
||||
search_service = SearchService(search_repository, entity_repository, file_service)
|
||||
await search_service.init_search_index()
|
||||
link_resolver = LinkResolver(entity_repository, search_service)
|
||||
|
||||
entity_service = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
sync_service = SyncService(
|
||||
app_config=app_config,
|
||||
entity_service=entity_service,
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
relation_repository=relation_repository,
|
||||
search_service=search_service,
|
||||
file_service=file_service,
|
||||
)
|
||||
|
||||
# Run sync
|
||||
report = await sync_service.scan(tmp_path)
|
||||
# Note: scan may pick up database files too, so just check our file is there
|
||||
assert "test_note.md" in report.new
|
||||
|
||||
# Sync the file
|
||||
await sync_service.sync_file("test_note.md", new=True)
|
||||
|
||||
# Verify file has no permalink added
|
||||
content = test_file.read_text()
|
||||
assert "permalink:" not in content
|
||||
assert "# Test Note" in content
|
||||
|
||||
# Verify entity in database has no permalink
|
||||
entities = await entity_repository.find_all()
|
||||
assert len(entities) == 1
|
||||
assert entities[0].permalink is None
|
||||
# Title is extracted from filename when no frontmatter, or from frontmatter when present
|
||||
assert entities[0].title in ("test_note", "Test Note")
|
||||
@@ -70,9 +70,7 @@ class TestAPIClientErrorHandling:
|
||||
mock_response.headers = {}
|
||||
|
||||
# Create HTTPStatusError with the mock response
|
||||
http_error = httpx.HTTPStatusError(
|
||||
"403 Forbidden", request=Mock(), response=mock_response
|
||||
)
|
||||
http_error = httpx.HTTPStatusError("403 Forbidden", request=Mock(), response=mock_response)
|
||||
|
||||
# Mock httpx client to raise the error
|
||||
with patch("basic_memory.cli.commands.cloud.api_client.httpx.AsyncClient") as mock_client:
|
||||
|
||||
@@ -200,6 +200,7 @@ async def entity_service(
|
||||
entity_parser: EntityParser,
|
||||
file_service: FileService,
|
||||
link_resolver: LinkResolver,
|
||||
app_config: BasicMemoryConfig,
|
||||
) -> EntityService:
|
||||
"""Create EntityService."""
|
||||
return EntityService(
|
||||
@@ -209,6 +210,7 @@ async def entity_service(
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
"""Tests for EntityService with disable_permalinks flag."""
|
||||
|
||||
from textwrap import dedent
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from basic_memory.config import BasicMemoryConfig
|
||||
from basic_memory.schemas import Entity as EntitySchema
|
||||
from basic_memory.services import FileService
|
||||
from basic_memory.services.entity_service import EntityService
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_entity_with_permalinks_disabled(
|
||||
entity_repository,
|
||||
observation_repository,
|
||||
relation_repository,
|
||||
entity_parser,
|
||||
file_service: FileService,
|
||||
link_resolver,
|
||||
):
|
||||
"""Test that entities created with disable_permalinks=True don't have permalinks."""
|
||||
# Create entity service with permalinks disabled
|
||||
app_config = BasicMemoryConfig(disable_permalinks=True)
|
||||
entity_service = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
entity_data = EntitySchema(
|
||||
title="Test Entity",
|
||||
folder="test",
|
||||
entity_type="note",
|
||||
content="Test content",
|
||||
)
|
||||
|
||||
# Create entity
|
||||
entity = await entity_service.create_entity(entity_data)
|
||||
|
||||
# Assert entity has no permalink
|
||||
assert entity.permalink is None
|
||||
|
||||
# Verify file frontmatter doesn't contain permalink
|
||||
file_path = file_service.get_entity_path(entity)
|
||||
file_content, _ = await file_service.read_file(file_path)
|
||||
_, frontmatter, doc_content = file_content.split("---", 2)
|
||||
metadata = yaml.safe_load(frontmatter)
|
||||
|
||||
assert "permalink" not in metadata
|
||||
assert metadata["title"] == "Test Entity"
|
||||
assert metadata["type"] == "note"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_entity_with_permalinks_disabled(
|
||||
entity_repository,
|
||||
observation_repository,
|
||||
relation_repository,
|
||||
entity_parser,
|
||||
file_service: FileService,
|
||||
link_resolver,
|
||||
):
|
||||
"""Test that entities updated with disable_permalinks=True don't get permalinks added."""
|
||||
# First create with permalinks enabled
|
||||
app_config_enabled = BasicMemoryConfig(disable_permalinks=False)
|
||||
entity_service_enabled = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config_enabled,
|
||||
)
|
||||
|
||||
entity_data = EntitySchema(
|
||||
title="Test Entity",
|
||||
folder="test",
|
||||
entity_type="note",
|
||||
content="Original content",
|
||||
)
|
||||
|
||||
# Create entity with permalinks enabled
|
||||
entity = await entity_service_enabled.create_entity(entity_data)
|
||||
assert entity.permalink is not None
|
||||
original_permalink = entity.permalink
|
||||
|
||||
# Now create service with permalinks disabled
|
||||
app_config_disabled = BasicMemoryConfig(disable_permalinks=True)
|
||||
entity_service_disabled = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config_disabled,
|
||||
)
|
||||
|
||||
# Update entity with permalinks disabled
|
||||
entity_data.content = "Updated content"
|
||||
updated = await entity_service_disabled.update_entity(entity, entity_data)
|
||||
|
||||
# Permalink should remain unchanged (not removed, just not updated)
|
||||
assert updated.permalink == original_permalink
|
||||
|
||||
# Verify file still has the original permalink
|
||||
file_path = file_service.get_entity_path(updated)
|
||||
file_content, _ = await file_service.read_file(file_path)
|
||||
assert "Updated content" in file_content
|
||||
assert f"permalink: {original_permalink}" in file_content
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_entity_with_content_frontmatter_permalinks_disabled(
|
||||
entity_repository,
|
||||
observation_repository,
|
||||
relation_repository,
|
||||
entity_parser,
|
||||
file_service: FileService,
|
||||
link_resolver,
|
||||
):
|
||||
"""Test that content frontmatter permalinks are ignored when disabled."""
|
||||
# Create entity service with permalinks disabled
|
||||
app_config = BasicMemoryConfig(disable_permalinks=True)
|
||||
entity_service = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
# Content with frontmatter containing permalink
|
||||
content = dedent(
|
||||
"""
|
||||
---
|
||||
permalink: custom-permalink
|
||||
---
|
||||
# Test Content
|
||||
"""
|
||||
).strip()
|
||||
|
||||
entity_data = EntitySchema(
|
||||
title="Test Entity",
|
||||
folder="test",
|
||||
entity_type="note",
|
||||
content=content,
|
||||
)
|
||||
|
||||
# Create entity
|
||||
entity = await entity_service.create_entity(entity_data)
|
||||
|
||||
# Entity should not have a permalink set
|
||||
assert entity.permalink is None
|
||||
|
||||
# Verify file doesn't have permalink in frontmatter
|
||||
file_path = file_service.get_entity_path(entity)
|
||||
file_content, _ = await file_service.read_file(file_path)
|
||||
_, frontmatter, doc_content = file_content.split("---", 2)
|
||||
metadata = yaml.safe_load(frontmatter)
|
||||
|
||||
# The permalink from content frontmatter should not be present
|
||||
assert "permalink" not in metadata
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_move_entity_with_permalinks_disabled(
|
||||
entity_repository,
|
||||
observation_repository,
|
||||
relation_repository,
|
||||
entity_parser,
|
||||
file_service: FileService,
|
||||
link_resolver,
|
||||
project_config,
|
||||
):
|
||||
"""Test that moving an entity with disable_permalinks=True doesn't update permalinks."""
|
||||
# First create with permalinks enabled
|
||||
app_config = BasicMemoryConfig(disable_permalinks=False, update_permalinks_on_move=True)
|
||||
entity_service = EntityService(
|
||||
entity_parser=entity_parser,
|
||||
entity_repository=entity_repository,
|
||||
observation_repository=observation_repository,
|
||||
relation_repository=relation_repository,
|
||||
file_service=file_service,
|
||||
link_resolver=link_resolver,
|
||||
app_config=app_config,
|
||||
)
|
||||
|
||||
entity_data = EntitySchema(
|
||||
title="Test Entity",
|
||||
folder="test",
|
||||
entity_type="note",
|
||||
content="Test content",
|
||||
)
|
||||
|
||||
# Create entity
|
||||
entity = await entity_service.create_entity(entity_data)
|
||||
original_permalink = entity.permalink
|
||||
|
||||
# Now disable permalinks
|
||||
app_config_disabled = BasicMemoryConfig(disable_permalinks=True, update_permalinks_on_move=True)
|
||||
|
||||
# Move entity
|
||||
moved = await entity_service.move_entity(
|
||||
identifier=entity.permalink,
|
||||
destination_path="new_folder/test_entity.md",
|
||||
project_config=project_config,
|
||||
app_config=app_config_disabled,
|
||||
)
|
||||
|
||||
# Permalink should remain unchanged even though update_permalinks_on_move is True
|
||||
assert moved.permalink == original_permalink
|
||||
@@ -169,3 +169,13 @@ class TestConfigManager:
|
||||
|
||||
with pytest.raises(ValueError, match="Project 'nonexistent' not found"):
|
||||
config_manager.set_default_project("nonexistent")
|
||||
|
||||
def test_disable_permalinks_flag_default(self):
|
||||
"""Test that disable_permalinks flag defaults to False."""
|
||||
config = BasicMemoryConfig()
|
||||
assert config.disable_permalinks is False
|
||||
|
||||
def test_disable_permalinks_flag_can_be_enabled(self):
|
||||
"""Test that disable_permalinks flag can be set to True."""
|
||||
config = BasicMemoryConfig(disable_permalinks=True)
|
||||
assert config.disable_permalinks is True
|
||||
|
||||
Reference in New Issue
Block a user