Source code for folderbot.tools.list_files

"""List files tool."""

from pydantic import BaseModel, Field

from ..bot import BotContext
from .base import ToolResult
from .constants import MAX_LIST_FILES
from .registry import folder_bot, get_services


[docs] class ListFilesRequest(BaseModel, frozen=True): """Request for listing files in a directory.""" path: str = Field( default="", description=( "Subfolder path relative to root (e.g., 'notes/2024'). " "Empty string or omit for root folder." ), ) pattern: str = Field( default="*", description="Glob pattern to filter files (e.g., '*.md'). Defaults to all files.", )
[docs] @folder_bot.tool( name="list_files", request_type=ListFilesRequest, response_type=ToolResult, ) async def list_files( request: ListFilesRequest, _context: BotContext | None = None ) -> ToolResult: """List files in the folder or a subfolder. Returns file paths relative to the root folder. Use this to discover what files are available before reading them. """ services = get_services(_context) if services is None: return ToolResult(content="Services not available", is_error=True) target_dir = services.validate_path(request.path) if target_dir is None: return ToolResult(content="Invalid path: access denied", is_error=True) if not target_dir.exists(): return ToolResult(content=f"Directory not found: {request.path}", is_error=True) if not target_dir.is_dir(): return ToolResult(content=f"Not a directory: {request.path}", is_error=True) files: list[str] = [] for file_path in target_dir.rglob(request.pattern): if file_path.is_file(): rel_path = str(file_path.relative_to(services.root)) if services.is_file_allowed(rel_path): files.append(rel_path) files.sort() if not files: return ToolResult(content="No matching files found.") total_count = len(files) if total_count > MAX_LIST_FILES: files = files[:MAX_LIST_FILES] return ToolResult( content="\n".join(files) + f"\n\n[Showing first {MAX_LIST_FILES} of {total_count} files]" ) return ToolResult(content="\n".join(files))