Files
MailUI4Agents/docs/PHASE7-REMAINING.md
JianFeeeee 7c9be9fd58 docs: 插件适配指南 + 共用模块提取(为接入更多平台做准备)
两次适配(opencode、DeepSeek Harness)里的方法与坑此前散落在提交信息和
代码注释里,接第三个平台时要重新翻。这次固化成文档,并把与平台 SDK 无关的
逻辑提到共用模块。

## docs/PLUGIN-GUIDE.md

八节:职责边界、必须实现的六件事、会话命名回写、平台会话快照上报、
平台差异对照表、踩过的坑(按排查成本降序)、新平台适配清单、共用模块清单。

三条设计原则贯穿全文,后面每一节都是它们的推论:

1. **平台原生信号才是真相来源**,不要求模型「记得」调工具 —— 因此不提供
   request_permission(改挂权限钩子)、不要求模型主动回信(改在「一轮结束」
   的平台信号上自动转发)
2. **插件代劳的转发不消耗配额** —— 因此这两类转发带 relay + relay_key
3. **平台命名优先** —— 因此创建会话时不传占位标题(那会掐掉平台自己的命名机制)

「踩过的坑」一节按排查成本排序,头一条是花了一下午的 followup() 参数形状。

## 共用模块提取

`lib/inbox-format.js`(新):收件箱渲染与已读策略。三条规则各对应一次错误行为,
而它们与平台 SDK 无关:

- 附件必须带 attachment_id(只说「有附件」模型无从下载)
- 抄送人要显示(不显示模型以为是私信,回信时漏掉其他参与方)
- 只标本次列出的、status=all 时不标(limit 之外的还没看过;把历史邮件标成已读
  会让下一轮的新邮件混在里面认不出来)

顺带修好两处不一致:DSH 的 read_inbox 此前**完全没有标记已读**(每轮重复捞同一批),
且默认 status=all(同上);附件大小两边一个显示字节数一个显示 KB/MB。

`lib/workspace.js`:提到两侧共用。签名从 (workspace, fallbackKey) 改为
(workspace, fallback) —— 各平台的兜底不同:opencode 有插件启动时的 directory,
DSH 只能落到 ~/.dsh/mail-sessions/<会话>(mailSessionFallback)。
opencode 侧此前是内联的三行判断,没有「目录不存在时不创建」与「拒绝相对路径」
这两条保护。

## deploy/check-shared-libs.sh

`lib/` 与 `test/` 下的共用文件必须逐字节相同,纳入 install.sh 门禁。

一侧改了另一侧没改,两个平台的行为就会悄悄分叉:同一封邮件在 opencode 那边
标了已读、在 DSH 那边没标,而两处代码看起来都「对」。这类分叉没有测试能发现,
只能靠 diff。

## 文档同步

- PLAN.md §7.7 从「待做」改为已完成,补 7.7.1(工作目录归属)与
  7.7.2(平台会话快照)两节,记录根因而非只记改法
- API.md 加「心跳与平台会话快照」章节;SSE 章节补 new_mail 与
  permission_decision 的 payload 说明(to_workspace 的语义、relay_key 的用途)
- PHASE7-REMAINING.md 移除已完成的 7.7,新增「每平台可用模型范围」的进展
  (repo 层已就绪,handler/插件/前端待做)
- README 文档索引与项目结构

验证:两插件共 136 个测试通过,同源校验通过,Go/前端全绿;
端到端发信 → DSH 用新的 read_inbox 渲染读取 → 自动回信 213 字节。
2026-09-02 20:28:19 +08:00

65 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 7 剩余项与已知生产缺陷追踪
7.7 DSH 插件已完成(见 `docs/PLUGIN-GUIDE.md` 与 PLAN.md §7.7)。
## 无法立即推进(缺基础设施)
### 7.8 跨主机 Agent 发现
- Gateway + Registry 拆分为独立服务
- etcd / Consul 服务注册与发现
- Agent 跨主机路由
## 可以立即推进的生产缺陷
### P0 — SSE Last-Event-ID 补投
**根因**EventSource 断线重连时自带 Last-Event-ID 头,但服务端直接忽略了——
所有断线期间的邮件通知都丢失。用户刷新页面也会错过已推的事件。
**影响**:重连后永远看不到断线期间收到的邮件(除非手动刷新)。
**修法**服务端维护一个有界循环缓冲区ring buffer每次 Broadcast 同时写入,
SSE 连接的 handler 在首次连接时从缓冲区头部开始(客户端传了 Last-Event-ID 就从那里),
没有则从头(只带最近 N 条)。缓冲区大小设 500内存 < 2MB
### P0 — 连接状态指示器
**根因**SSE 断线后前端无任何可见反馈——用户以为系统正常实际通知已停
**影响**实时性是 Agent 协作的核心体验断线无提示会让人以为Agent 没在动」。
**修法**header 旁加一个连接状态点绿//SSE onopen/onerror 事件驱动
### P1 — 登录限速跨进程问题 ✅
**根因**LoginLimiter 是进程内内存计数器多实例部署时每个实例独立计数
**修法**改为 DB 事务rate_limits + IMMEDIATE 事务多实例共享同一份计数
### P1 — 新建会话限速同理 ✅
**根因**sessionRateLimiter 也是进程内计数器
**修法**同上sessionrate.go 重写为调用 RateLimitCheckAndRecord
### P2 — 组件级测试
**现状**前端无任何组件测试前端回归只靠 lint 与构建
**范围**关键组件AddressInput 补全PermissionPanel 决策WorkCard 预算渲染)。
### P2 — 深色主题
**现状**只有浅色主题深夜使用刺眼
**范围**tailwind dark: 前缀覆盖主要组件
### P1 — 每平台可用模型范围(进行中)
**需求**配置页面为每个 Agent 平台划定邮箱调用场景下可用的模型范围」,
端侧插件按范围**逐个降级尝试**全部失败时把失败原因封装成邮件回复
选择而非手打模型名 —— 平台上报目录管理员勾选
**已完成**
- `agent_model_catalog`平台上报的目录+ `agent_allowed_models`管理员的选择
两张表两份 schema
- `repo/models_scope.go``ReplaceModelCatalog` / `ListModelCatalog` /
`ListAllowedModels` / `SetAllowedModels`
**为什么分两张表**模型会从平台目录里消失换了 provider 配置上游临时下线
整行删掉会连带把管理员的选择也删了模型回来还得重配一遍分开存之后
选了什么是持久的目录只决定这一项现在是否可用」。
**待做**
- [ ] handler + 路由注册时接收目录管理员读写选择
- [ ] 插件在注册时上报目录opencode `/config/providers`DSH `llm.listModels`
- [ ] 插件按 rank 顺序尝试记录每次失败的原因
- [ ] 全部失败 发一封说明失败原因的邮件走免配额通道
- [ ] 前端配置页复选框 + 拖拽排序rank 即优先级