""" Workspace management routes for LightRAG server. """ import logging from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException, Query, Request from pydantic import BaseModel, Field from lightrag.api.utils_api import get_combined_auth_dependency from lightrag.api.workspace_manager import WorkspaceManager logger = logging.getLogger(__name__) router = APIRouter( prefix="/workspaces", tags=["workspaces"], ) class WorkspaceCreateRequest(BaseModel): name: str = Field(..., min_length=1, max_length=100, description="Workspace name (alphanumeric, underscores, hyphens)") class WorkspaceRenameRequest(BaseModel): new_name: str = Field(..., min_length=1, max_length=100, description="New workspace name (alphanumeric, underscores, hyphens)") class WorkspaceResponse(BaseModel): name: str path: str def get_workspace_manager(request: Request): """Dependency to get workspace manager instance.""" # Access workspace manager from app state via request return request.app.state.workspace_manager @router.get("/", response_model=List[WorkspaceResponse]) async def list_workspaces( search: Optional[str] = Query(None, description="Search workspaces by keyword in name"), workspace_manager: WorkspaceManager = Depends(get_workspace_manager), ): """List all existing workspaces with optional keyword search.""" try: workspaces = workspace_manager.list_workspaces() # Filter by search keyword if provided if search: search_lower = search.lower() workspaces = [ws for ws in workspaces if search_lower in ws.lower()] return [ WorkspaceResponse(name=ws, path=str(workspace_manager.base_working_dir / ws)) for ws in workspaces ] except Exception as e: logger.error(f"Error listing workspaces: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.post("/", response_model=WorkspaceResponse) async def create_workspace( create_request: WorkspaceCreateRequest, workspace_manager: WorkspaceManager = Depends(get_workspace_manager), ): """Create a new workspace.""" try: workspace_manager.create_workspace(create_request.name) return WorkspaceResponse( name=create_request.name, path=str(workspace_manager.base_working_dir / create_request.name) ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error creating workspace: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.patch("/{workspace_name}", response_model=WorkspaceResponse) async def rename_workspace( workspace_name: str, rename_request: WorkspaceRenameRequest, workspace_manager: WorkspaceManager = Depends(get_workspace_manager), ): """Rename a workspace.""" try: await workspace_manager.rename_workspace(workspace_name, rename_request.new_name) return WorkspaceResponse( name=rename_request.new_name, path=str(workspace_manager.base_working_dir / rename_request.new_name) ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error renaming workspace: {e}") raise HTTPException(status_code=500, detail=str(e)) @router.delete("/{workspace_name}") async def delete_workspace( workspace_name: str, workspace_manager: WorkspaceManager = Depends(get_workspace_manager), ): """Delete a workspace.""" try: await workspace_manager.delete_workspace(workspace_name) return {"message": f"Workspace '{workspace_name}' deleted successfully"} except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Error deleting workspace: {e}") raise HTTPException(status_code=500, detail=str(e))