from typing import Any, Literal from pydantic import BaseModel, Field class SearchInputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") query_text: str = Field(description="检索关键词,应提炼为有助于召回答案的关键词或短语") file_name: str | None = Field(default=None, description="可选文件名关键词过滤,非必要不要使用") class SearchResultSchema(BaseModel): id: str = Field(description="检索结果 ID,通常对应 chunk_id") kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") file_id: str = Field(default="", description="结果所属文件 ID,可用于 Find/Open") content: str = Field(description="chunk 内容") metadata: dict[str, Any] = Field(default_factory=dict, description="来源、分数、chunk_index 等附加信息") class SearchOutputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") results: list[SearchResultSchema] = Field(default_factory=list, description="检索结果列表") class FindInputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") file_id: str = Field(description="要检索的文件 ID") patterns: list[str] = Field(description="关键词或正则模式列表,至少提供一个") use_regex: bool = Field(default=False, description="是否将 patterns 作为正则表达式处理") case_sensitive: bool = Field(default=False, description="是否区分大小写") max_windows: int = Field(default=5, ge=1, le=20, description="最多返回的上下文窗口数量") window_size: int = Field(default=80, ge=1, le=200, description="每个上下文窗口的行数") class FindWindowSchema(BaseModel): start_line: int = Field(description="窗口起始行号,1-based") end_line: int = Field(description="窗口结束行号,1-based") matched_lines: list[int] = Field(default_factory=list, description="该窗口内匹配到的行号") content: str = Field(description="带行号的窗口内容") class FindOutputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") file_id: str = Field(description="文件 ID") semantic: bool = Field(default=False, description="是否为语义查找") match_mode: Literal["keyword", "regex"] = Field(description="匹配模式") total_matches: int = Field(description="匹配到的行数") windows: list[FindWindowSchema] = Field(default_factory=list, description="上下文窗口") class OpenInputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") file_id: str = Field(description="要打开的文件 ID") line: int | None = Field(default=None, ge=1, description="可选,1-based 起始行号") offset: int | None = Field(default=None, ge=0, description="可选,0-based 起始偏移;line 优先于 offset") window_size: int = Field(default=1800, ge=1, le=2000, description="读取窗口行数") class OpenOutputSchema(BaseModel): kb_id: str = Field(description="知识库资源 ID,也就是 kb_id") file_id: str = Field(description="文件 ID") start_line: int = Field(description="窗口起始行号,1-based;空结果为 0") end_line: int = Field(description="窗口结束行号,1-based;空结果为 0") total_lines: int = Field(description="文件总行数") offset: int = Field(description="窗口起始偏移,0-based") window_size: int = Field(description="本次请求的窗口行数") has_more_before: bool = Field(description="窗口前是否还有内容") has_more_after: bool = Field(description="窗口后是否还有内容") next_offset: int | None = Field(default=None, description="下一窗口 offset;没有更多内容时为 null") content: str = Field(description="带行号的窗口内容")