English

# 架构 ## 概述 dsh-zotero 是一个 Cordis 服务插件,提供 `ctx.zotero` 服务边界。加载器将默认导出与行的验证配置一起挂载。 ## 数据流 ```mermaid graph LR U[用户] --> A[Agent] A --> T[dsh Zotero 工具] T --> S[ZoteroService] S --> P[Provider] P --> Z[Zotero Local API
127.0.0.1:23119] Z --> L[Zotero 文献库] ``` 用户 → Agent → dsh Zotero 工具 → ZoteroService → Provider → 127.0.0.1 Zotero Local API → Zotero 文献库 ## 关键层 ### 服务层 (`src/service.ts`) - `ZoteroService` 扩展 `Service`,注册为 `ctx.zotero` - 负责 provider 选择、能力门控、领域方法 - 配置是实时的:附加时使用 settings section,否则使用 composition entry - `rebuild()` 在**同一** `ZoteroService` 实例上,从当前配置重建 HTTP 客户端与 local provider;不替换服务实例 - 连接恢复门(`ConnectivityRecovery` / `service.recovery`)与服务实例同寿命,**不**随 settings rebuild 重置(避免并发失败叠卡) - 请求驱动:加载从不触及 Zotero ### Provider 层 (`src/local/provider.ts`) - `LocalApiProvider` 实现 `ZoteroProvider` - 能力:search、metadata、attachments、fulltext、citation、browse、retrieve、changes - 客户端侧解析作用域(Local API 无服务端名称搜索) - 笔记体扫描:客户端侧第一页(offset 0),受 maxNoteScanRecords 限制 - 证据排名:基于 passage 语料库的 BM25(annotations、notes、abstract、fulltext chunks) - 导出:引用批次遵循 API 的 50 键上限;translator 格式最多 50 条引用 ### HTTP 传输层 (`src/http-client.ts`) - 纯回环 fetch,固定 API 版本(`Zotero-API-Version: 3`) - 实例身份保护(`Zotero-Server-ID` 头) - 流式响应字节上限(`maxResponseBytes`) - 全实例在途请求上限(`ZOTERO_MAX_INFLIGHT_REQUESTS`,默认 8):各域并发池只约束单次调用的扇出,多个并行工具调用会相乘,因此由 HTTP 客户端统一持有槽位(连接、响应体、流式读取全程),排队请求可被调用方取消,请求超时从拿到槽位后开始计时(排队不计入超时) - 不跟随重定向、不保持连接、无后台工作 - 超时通过 deadline 融合与调用者取消实现 ### 证据管线 (`src/evidence.ts`) - 分词:`Intl.Segmenter` 词分割(CJK 感知),词元先按 Zotero 自身的 `normalizeForSearch` 折叠(音调符号、NFKD 特殊字母、排版引号/破折号、格式标签),与服务器侧搜索的判据一致;折叠只作用于匹配侧,原文不被改写 - BM25 排名(k1=1.2, b=0.75)在 passage 语料库上 - 文档频率是 passage 级别(在条目自身 passages 中越罕见得分越高) - 平局保留调用者 passage 顺序(确定性) - 零分 passage 排除(未命中查询词的 passage 不进入结果) ### 浏览器客户端 (`src/client/`) - 配置页:`settings.section` 插槽(设置面板左侧导航的独立一项),经 `ctx.configForms.get` 读 `zotero` 命名空间的共享表单 - Sources tab:`conversation.view` 插槽,文献/证据/导出的会话快照 - Sources 子视图:搜索命中和引用条目的稳定联合 - Evidence 子视图:按文献分组的段落,带 Zotero 的页标签 - Exports 子视图:成功导出的产物,带格式/样式/区域设置 - 连接条:tab 打开时探测一次,刷新时再探测一次(无轮询) - `zotero://` 深链接:"在 Zotero 中打开"、"打开 PDF"、"打开批注" - `webEnabled` 开关:实时生效,无需重新加载 ### Remote/Typert - `ZoteroRuntime` 通过 wire 命名空间为 web tab 提供实时连接性 - 严格 manifest 通过 Typert 注册表声明端点 ### 设置 - 命名空间 `zotero` 在 Loader entry(composition entry 即唯一权威) - 全字段 `volatile`:设置提交免重建落地;`internal/config` 否决非法提交,`loader/volatile-update` 重建传输栈与写工具集 ## 设计边界 - **文献库**:默认只读;`writeEnabled` 显式打开后可写个人库(笔记、标签、入藏)。写路径见写入边界。 - **网络**:仅回环(127.0.0.1, localhost, ::1)。拒绝重定向。 - **无后台轮询**、无遥测、无常驻任务。 - **证据**:基于词项的 BM25,按查询词与 passage 的词频匹配度排序。 - **Sources tab**:会话快照,展示本次对话引用的条目。 - **导出**:工具以文本形式返回(模型读到的就是它);面板提供复制与文件下载。 - **PDF 阅读**:附件返回路径/URL;进一步阅读需要宿主能力。路径属于**运行 Zotero 的那台机器**——loopback 限制保证插件与 Zotero 同机,但宿主的文件读取可能跑在别的执行环境(sandbox、容器、远程主机),那时该路径不可见,工具结果会注明环境;插件不会通过开放 Zotero 无认证端口来解决远端访问。