feat: add directory support to move_note and delete_note tools (#518) · basicmachines-co/basic-memory@0b20801 · GitHub
Skip to content

Commit 0b20801

Browse files
phernandezclaude
andauthored
feat: add directory support to move_note and delete_note tools (#518)
Signed-off-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8730067 commit 0b20801

63 files changed

Lines changed: 2148 additions & 585 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 4 additions & 4 deletions

src/basic_memory/api/routers/importer_router.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
2727
async def import_chatgpt(
2828
importer: ChatGPTImporterDep,
2929
file: UploadFile,
30-
folder: str = Form("conversations"),
30+
directory: str = Form("conversations"),
3131
) -> ChatImportResult:
3232
"""Import conversations from ChatGPT JSON export.
3333
3434
Args:
3535
file: The ChatGPT conversations.json file.
36-
folder: The folder to place the files in.
36+
directory: The directory to place the files in.
3737
markdown_processor: MarkdownProcessor instance.
3838
3939
Returns:
@@ -42,20 +42,20 @@ async def import_chatgpt(
4242
Raises:
4343
HTTPException: If import fails.
4444
"""
45-
return await import_file(importer, file, folder)
45+
return await import_file(importer, file, directory)
4646

4747

4848
@router.post("/claude/conversations", response_model=ChatImportResult)
4949
async def import_claude_conversations(
5050
importer: ClaudeConversationsImporterDep,
5151
file: UploadFile,
52-
folder: str = Form("conversations"),
52+
directory: str = Form("conversations"),
5353
) -> ChatImportResult:
5454
"""Import conversations from Claude conversations.json export.
5555
5656
Args:
5757
file: The Claude conversations.json file.
58-
folder: The folder to place the files in.
58+
directory: The directory to place the files in.
5959
markdown_processor: MarkdownProcessor instance.
6060
6161
Returns:
@@ -64,20 +64,20 @@ async def import_claude_conversations(
6464
Raises:
6565
HTTPException: If import fails.
6666
"""
67-
return await import_file(importer, file, folder)
67+
return await import_file(importer, file, directory)
6868

6969

7070
@router.post("/claude/projects", response_model=ProjectImportResult)
7171
async def import_claude_projects(
7272
importer: ClaudeProjectsImporterDep,
7373
file: UploadFile,
74-
folder: str = Form("projects"),
74+
directory: str = Form("projects"),
7575
) -> ProjectImportResult:
7676
"""Import projects from Claude projects.json export.
7777
7878
Args:
7979
file: The Claude projects.json file.
80-
base_folder: The base folder to place the files in.
80+
directory: The directory to place the files in.
8181
markdown_processor: MarkdownProcessor instance.
8282
8383
Returns:
@@ -86,20 +86,20 @@ async def import_claude_projects(
8686
Raises:
8787
HTTPException: If import fails.
8888
"""
89-
return await import_file(importer, file, folder)
89+
return await import_file(importer, file, directory)
9090

9191

9292
@router.post("/memory-json", response_model=EntityImportResult)
9393
async def import_memory_json(
9494
importer: MemoryJsonImporterDep,
9595
file: UploadFile,
96-
folder: str = Form("conversations"),
96+
directory: str = Form("conversations"),
9797
) -> EntityImportResult:
9898
"""Import entities and relations from a memory.json file.
9999
100100
Args:
101101
file: The memory.json file.
102-
destination_folder: Optional destination folder within the project.
102+
directory: Optional destination directory within the project.
103103
markdown_processor: MarkdownProcessor instance.
104104
105105
Returns:
@@ -116,7 +116,7 @@ async def import_memory_json(
116116
json_data = json.loads(line)
117117
file_data.append(json_data)
118118

119-
result = await importer.import_data(file_data, folder)
119+
result = await importer.import_data(file_data, directory)
120120
if not result.success: # pragma: no cover
121121
raise HTTPException(
122122
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,

src/basic_memory/api/routers/knowledge_router.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
DeleteEntitiesResponse,
3030
DeleteEntitiesRequest,
3131
)
32-
from basic_memory.schemas.request import EditEntityRequest, MoveEntityRequest
32+
from basic_memory.schemas.request import EditEntityRequest, MoveEntityRequest, MoveDirectoryRequest
33+
from basic_memory.schemas.response import DirectoryMoveResult
3334
from basic_memory.schemas.base import Permalink, Entity
3435

3536
router = APIRouter(
@@ -231,6 +232,50 @@ async def move_entity(
231232
raise HTTPException(status_code=400, detail=str(e))
232233

233234

235+
@router.post("/move-directory")
236+
async def move_directory(
237+
data: MoveDirectoryRequest,
238+
background_tasks: BackgroundTasks,
239+
entity_service: EntityServiceDep,
240+
project_config: ProjectConfigDep,
241+
app_config: AppConfigDep,
242+
search_service: SearchServiceDep,
243+
) -> DirectoryMoveResult:
244+
"""Move all entities in a directory to a new location.
245+
246+
This endpoint moves all files within a source directory to a destination
247+
directory, updating database records and optionally updating permalinks.
248+
"""
249+
logger.info(
250+
f"API request: endpoint='move_directory', source='{data.source_directory}', destination='{data.destination_directory}'"
251+
)
252+
253+
try:
254+
# Move the directory using the service
255+
result = await entity_service.move_directory(
256+
source_directory=data.source_directory,
257+
destination_directory=data.destination_directory,
258+
project_config=project_config,
259+
app_config=app_config,
260+
)
261+
262+
# Reindex moved entities
263+
for file_path in result.moved_files:
264+
entity = await entity_service.link_resolver.resolve_link(file_path)
265+
if entity:
266+
await search_service.index_entity(entity, background_tasks=background_tasks)
267+
268+
logger.info(
269+
f"API response: endpoint='move_directory', "
270+
f"total={result.total_files}, success={result.successful_moves}, failed={result.failed_moves}"
271+
)
272+
return result
273+
274+
except Exception as e:
275+
logger.error(f"Error moving directory: {e}")
276+
raise HTTPException(status_code=400, detail=str(e))
277+
278+
234279
## Read endpoints
235280

236281

src/basic_memory/api/v2/routers/importer_router.py

Lines changed: 15 additions & 15 deletions

0 commit comments

Comments
 (0)