wrolpi/modules/ai/schema.py
Roland 61f2cb20ee
ai: list_files tool — browse the media directory tree
New read-only GET /api/ai/files/list lists one directory of the media
directory (directories first, then files with size and guessed
mimetype), paged at 100 entries.  Every entry carries its relative
path for list_files or read_file.  Same guards as read_file via a
shared resolver: no escaping the media directory, and the config
directory is refused and hidden from the root listing.

The agent loop picks the operation up from the spec; library mode
allowlists it.  wrolpi_mcp gains the matching list_files proxy tool.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-24 18:23:25 -06:00

85 lines
1.9 KiB
Python

import dataclasses
from typing import List, Optional
@dataclasses.dataclass
class AISearchRequest:
search_str: Optional[str] = None
limit: int = 5
offset: int = 0
mimetypes: Optional[List[str]] = None
tag_names: Optional[List[str]] = None
@dataclasses.dataclass
class AIVideoSearchRequest:
search_str: Optional[str] = None
limit: int = 5
offset: int = 0
channel_id: Optional[int] = None
tag_names: Optional[List[str]] = None
@dataclasses.dataclass
class AIArchiveSearchRequest:
search_str: Optional[str] = None
limit: int = 5
offset: int = 0
domain: Optional[str] = None
tag_names: Optional[List[str]] = None
@dataclasses.dataclass
class AIDocSearchRequest:
search_str: Optional[str] = None
author: Optional[str] = None
subject: Optional[str] = None
language: Optional[str] = None
mimetype: Optional[str] = None
limit: int = 5
offset: int = 0
tag_names: Optional[List[str]] = None
@dataclasses.dataclass
class AIZimSearchRequest:
search_str: Optional[str] = None
zim_id: Optional[int] = None
limit: int = 5
offset: int = 0
@dataclasses.dataclass
class AIHelpSearchRequest:
search_str: Optional[str] = None
limit: int = 5
@dataclasses.dataclass
class AIManageSettingsRequest:
enabled: Optional[bool] = None
active_model: Optional[str] = None
idle_unload_minutes: Optional[int] = None
context_size: Optional[int] = None
@dataclasses.dataclass
class AISearchResponse:
results: list = dataclasses.field(default_factory=list)
total: int = 0
@dataclasses.dataclass
class AIPagedTextResponse:
content: str = ''
next_offset: Optional[int] = None
total_chars: int = 0
@dataclasses.dataclass
class AIListFilesResponse:
path: str = ''
directories: list = dataclasses.field(default_factory=list)
files: list = dataclasses.field(default_factory=list)
total: int = 0
next_offset: Optional[int] = None