mirror of
https://git.openapi.site/https://github.com/desirecore/market.git
synced 2026-10-21 06:04:03 +08:00
## 背景 / Background
发票整理 Agent 在隔离开发实例里真机整理 QQ 邮箱时,按内置技能 `mail-operations` 的写法调用 IMAP
附件下载,拿到 400 `Missing required parameters`:技能写的请求体是 `{email, uid, folder,
partId}`,而 `POST /imap/attachment` 从 2026-03 创建起就只认 `{email, messageId,
attachmentId, folder?}`。顺着这一处,对照 desirecore origin/dev(`c1e2c5ac0`)的
`lib/mail-service/` 与 `MailOperations` 工具把整份技能逐条核对了一遍。
While a real-mailbox run of the invoice agent was downloading QQ Mail
attachments, the builtin `mail-operations` skill's IMAP attachment body
(`{email, uid, folder, partId}`) returned 400; the route has always
taken `{email, messageId, attachmentId, folder?}`. This PR re-audits the
whole skill against the current mail service routes.
## 改动 / Changes
共修正 27 处不一致:会直接导致调用失败 9 处、会误导能力判断 10 处、措辞 8 处。主要有:
- **调用入口**:改为 `MailOperations`(path 带 `/api`,capability
由工具注入);原文的固定端口、「无需认证」、`curl -k` 都不成立
- **附件**:body 字段更正;必须带 `save_to` 落盘(不带会被工具拒绝返回),回执给出路径、字节数、SHA-256
- **参数位置**:`messages/fetch`、`/sync`、IMAP 草稿发送的 `email`(以及 `/sync` 的
`provider`)放查询串;IMAP 草稿收件人是逗号分隔的 `to` / `cc`,更新草稿会换成新 uid
- **folder**:IMAP 单封操作要用 `GET /imap/folders` 返回的服务器路径,列表里的归一化值会 500
- **规则**:operator 是 `matches_regex`(未知 operator 恒为 false
且创建时不校验);`archive` / `move_to_folder` / `forward_to` / `star` 是空操作
- **搜索**:三个 provider 都支持,只查本地缓存、`q` 只匹配主题;Gmail 全文检索改用 `messages/fetch`
的 `query`
- **IMAP 仅收信账户**:`allowUnverifiedSmtp`、`smtp_verification_failed`、409
`smtp_unverified`、`verify-smtp`(失败也返回 200)
- **离线队列**:不会自动入队或处理,只改本地,`processed` 计数不代表执行
- 响应字段名(`toRecipients`、`bodyPreview` 等)、同步状态文件、`/imap/test` 返回形态等措辞修正
- 版本 1.0.6;新增 `market.required_client_version: 10.0.148` 与 sidecar
`compatibility.requiredClientVersion`——`MailOperations`(10.0.95)、`save_to`
与 Outlook/IMAP search(10.0.146)、`imap:<uid>` / fetch `offset` / folder
归一化(10.0.148)分版本上线,旧客户端按新文档操作会静默失败,门控让它们保留旧版
## 验证 / Verification
- 写补丁与审查由两个独立子代理完成:审查方对 9 处致命项全部、另外 13 处抽查逐条对照代码行,均成立;审查意见(最低客户端版本、IMAP
更新草稿换 uid、`/sync` 参数、Gmail 远程检索、`verify-smtp` 返回形态、离线队列计数、响应示例矛盾)已全部采纳
- 各项最低版本用 `git tag --contains` 对照发布 tag 复核
- `translate.py --check`:en-US human-locked 且 hash 新鲜(`source_hash` 按
`compute_source_hash` 重算)
- `validate-i18n`:0 error,123 warning(与 main 基线相同)
- `validate_catalog_metadata --require-complete`:0 error
- `git diff --check` 通过;新增行只有 `example.com` 占位地址,无真实邮箱、姓名、公司名或长数字编号
🤖 Generated with [Claude Code](https://claude.com/claude-code)
1.6 KiB
1.6 KiB
离线队列 API
离线队列目前只能通过下列接口手动登记和处理:写操作失败时不会自动入队,网络恢复后也不会自动处理。POST /offline/process 执行时,mark_as_read、mark_as_unread、delete、add_label、remove_label 只修改本地缓存,不同步到邮件服务器;send_email、archive、move_to_folder 尚未实现。这些未实现的类型、以及缺少 params.labelId 的加/去标签操作,处理时什么都不做却照样出队并计入 processed——processed 的计数不代表操作真的执行了。不要把离线队列当作发信或同步远程的手段。
下表端点与主文档一样省略 /api 前缀,经 MailOperations 调用时需补上(/ping 除外)。
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取队列状态 | GET | /offline/status |
| 获取队列操作 | GET | /offline/queue |
| 添加操作到队列 | POST | /offline/queue — body: {type, provider, email, mailId, params},type ∈ mark_as_read, mark_as_unread, delete, move_to_folder, add_label, remove_label, send_email, archive |
| 移除单个操作 | DELETE | /offline/queue/{operationId} |
| 清空队列 | DELETE | /offline/queue |
| 清除失败操作 | DELETE | /offline/failed |
| 手动处理队列 | POST | /offline/process |
同步状态
| 操作 | 方法 | 端点 |
|---|---|---|
| 获取同步状态 | GET | /sync-status?provider=&email= — 返回 idle/syncing/error |
| 获取轮询引擎状态 | GET | /polling/status — 所有账户轮询状态 |
| 健康检查 | GET | /ping(注意:路径不含 /api 前缀) |