mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-12 00:03:26 +08:00
feat: add bounded history previews across nine channels
Add shared /history parsing, read-only session access, message filtering, and bounded replies. Default to three messages, cap at five, and exclude saved history commands. Include channel integration tests, translations, command help, and the Issue #62 implementation plan.
This commit is contained in:
parent
bf0e157cd4
commit
8c6c31a1b6
23 changed files with 1965 additions and 221 deletions
201
docs/方案/Issue-62-九渠道会话历史预览方案.md
Normal file
201
docs/方案/Issue-62-九渠道会话历史预览方案.md
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
# Issue #62:九渠道会话历史预览方案
|
||||
|
||||
日期:2026-08-28。代码基线:v3.0.8 / `bf0e157`。状态:已实施。
|
||||
|
||||
需求来源:[Issue #62](https://github.com/xmanrui/dsh-im/issues/62)。本方案仅描述实现,不代表功能已经上线。
|
||||
|
||||
## 1. 最终命令约定
|
||||
|
||||
新增一个共享命令:`/history [数量]`。
|
||||
|
||||
| 输入 | 行为 |
|
||||
| --- | --- |
|
||||
| `/history` | 返回最近最多 3 条历史消息 |
|
||||
| `/history 1` | 返回最近最多 1 条 |
|
||||
| `/history 4` | 返回最近最多 4 条 |
|
||||
| `/history 5` | 返回最近最多 5 条 |
|
||||
| `/history 6`、`/history 100` | 均按 5 条处理,不报超限错误 |
|
||||
| `/history 0`、负数、小数、非数字、多个参数 | 返回用法,不访问模型 |
|
||||
|
||||
这里的默认值是 **3 条,不是 3 天**,不提供时间范围查询。
|
||||
|
||||
“一条历史消息”指一条用户消息,或一条助手最终回复;不是一轮对话,也不是一个工具事件。例如两次完整问答共有 4 条。数量不足时按实际数量返回,不补齐、不生成摘要。
|
||||
|
||||
先取最新 N 条,再按从旧到新的顺序展示。奇数条可能从助手回复开始,这是按消息计数的正常结果,不额外补入第 N+1 条。
|
||||
|
||||
## 2. 范围与体验
|
||||
|
||||
九渠道统一提供文字命令和文字预览,不新增卡片、按钮、设置项、数据库或历史缓存,不为 QQ、企业微信添加专门的发送逻辑。
|
||||
|
||||
本期沿用前一轮建议的私聊范围:微信、飞书、钉钉、企业微信、QQ、Slack、Telegram、Discord、WhatsApp 的私聊均支持;群聊、频道和群内线程只回复“请在与机器人的私聊中使用 /history”。它们不读取历史,也不自动转发到另一个私聊。渠道现有的入站路由行为保持不变。
|
||||
|
||||
只查看当前聊天已绑定的 Harness Session,不接受 Session ID 参数。切换成功后只增加一句“发送 /history 查看最近对话”,不自动发送历史。AI Office Connector 不属于本次九个聊天渠道。
|
||||
|
||||
预览示意:
|
||||
|
||||
```text
|
||||
会话历史|会话 abc123|最近 3 条
|
||||
|
||||
1. 助手
|
||||
上一次已经完成登录接口,下一步是补充测试。
|
||||
|
||||
2. 用户
|
||||
先补充登录失败场景的测试。
|
||||
|
||||
3. 助手
|
||||
已补充三个失败场景,测试全部通过。
|
||||
|
||||
以上为历史记录,不是本次新回复。
|
||||
```
|
||||
|
||||
这是历史文字摘录,不是让模型重新回答或概括。
|
||||
|
||||
## 3. 历史读取与筛选
|
||||
|
||||
### 3.1 读取流程
|
||||
|
||||
1. 渠道先执行现有访问策略、去重和命令识别。
|
||||
2. 共享命令解析数量:省略为 3,正整数超过 5 时取 5。
|
||||
3. 确认是私聊、没有图片或文件,并读取当前聊天绑定的 Session ID;未绑定直接提示,不创建会话。
|
||||
4. 通过共享 HarnessClient 调用现有 `session.history`。本机沿用 v3.0.8 的进程内 API,显式配置远程 Host 时沿用 HTTP,不另建访问链路。
|
||||
5. 筛选可显示消息,选取最新 N 条,按原顺序排版。
|
||||
6. 读取结束后再次检查当前绑定和工作区作用域;读取期间切换了会话、工作区或机器人已失效,则丢弃结果并提示重试。
|
||||
7. 返回现有的 `{ handled, message, messages }` 命令结果,由各桥接器现有发送函数投递到本次请求的原聊天。
|
||||
|
||||
发送一旦开始,整份回复始终使用同一份已读取快照和原回复目标,不在分段之间改读新会话。标题或短 ID 用于标明这份历史属于哪个会话。
|
||||
|
||||
### 3.2 什么可以显示
|
||||
|
||||
| 内容 | 处理 |
|
||||
| --- | --- |
|
||||
| 原始用户消息 | 只接受能确认是人类输入的消息来源,提取正文文字 |
|
||||
| 用户历史中的 `/history` 命令记录 | 排除被 `isHistoryCommand` 识别的命令(含参数和首尾空白),不显示、不计数;普通正文或助手回复中提到 `/history` 的内容保留,不推断关联 Turn |
|
||||
| 助手最终回复 | 每个成功结束的 Turn 只取最后一条定稿助手消息中的文字 |
|
||||
| 当前运行中的用户输入 | 已进入历史时可以显示;未提交的排队输入不读取 |
|
||||
| 正在生成的助手回复 | 不显示 token 分片或过程消息,可附“当前任务仍在进行中” |
|
||||
| 图片、文件等非文字内容 | 不下载、不重发;有可靠结构化信息时显示类型占位说明 |
|
||||
| 工具调用、工具结果、推理内容、系统指令、注入上下文、审批内容 | 不展示 |
|
||||
| 压缩产生的替换副本 | 不当成新对话,不重复计数;保留原始人类对话的含义 |
|
||||
| 无可显示文字的助手最终消息 | 显示“本条没有可预览的文字”,不拿更早的过程消息冒充最终回复 |
|
||||
|
||||
实现时不能简单地过滤 `user/message`、`assistant/message` 后取最后 N 个事件:
|
||||
|
||||
- `user/message` 也可能是内部注入内容,必须检查 `data.source.kind === 'user'`。
|
||||
- 当前协议中,原始对话使用 `surfaceOp: 'append'`;`replace` 是模型侧替换内容,不重复展示。缺少关键字段时不猜测为普通对话。
|
||||
- 助手消息需要结合 `turn/end` 确认最终状态;忽略 `assistant/chunk`、中断片段以及中间工具步骤的助手消息。
|
||||
- 用户正文在 `event.data.content`,助手正文在 `event.data.message.content`,两者不能用同一个未经区分的字段路径读取。
|
||||
|
||||
这些规则只限制显示哪些事件、哪些内容块,不承诺自动识别并清除用户正文里原本就包含的密码、路径等敏感文字。权限仍依赖机器人已有的可信访问范围,不新增一套管理员或 Session 所有者体系。
|
||||
|
||||
### 3.3 有限读取即可,不做历史浏览器
|
||||
|
||||
首次读取 `maxMessages: 50`;若筛选后不足 N 条且响应 `hasMore` 为真,使用 `beforeSeq` 向前补读,最多总共 3 次。整次读取设置 10 秒截止时间,不订阅实时事件。
|
||||
|
||||
`maxMessages` 是 Harness 的分页计数,不是本命令的返回条数。每页按 `seq` 校验、排序和去重,向前游标必须严格推进。固定首次尾页的快照边界,不在补读期间追赶新消息。
|
||||
|
||||
达到上限仍不足时,返回已确认的记录并说明不足;没有可用记录则给出对应提示。字段不合法、游标不推进或记录冲突时返回安全错误,不把原始响应作为文字发出去。
|
||||
|
||||
## 4. 防刷屏统一规则
|
||||
|
||||
防刷屏只在共享命令层处理,不按渠道另写策略。
|
||||
|
||||
- 最多选择 5 条历史消息。
|
||||
- 每条正文最多展示 500 个字符,超出注明“已截断”;切分不得拆开 Unicode 代理对。
|
||||
- 合并成一份带角色标签的文字回复,总长度控制在 3,000 个字符以内,标题、标签和截断提示都计入预算。
|
||||
- 复用现有 `splitWorkspaceCommandMessage()` 按 1,800 字符分段;最多发送 3 段,超出先缩短正文并标注截断。
|
||||
- 逻辑历史消息数与 IM 分段数分开计算:`/history 5` 最多包含 5 条历史记录,不是固定发送 5 个气泡。
|
||||
- 命令结果一次生成完再发送,不流式推送历史,不引导用户发送“继续”,不自动翻页。
|
||||
|
||||
上述 500 / 3,000 / 3 段是建议的统一显示预算,可在共享常量中调整;默认 3 条、上限 5 条则按本次需求固定。
|
||||
|
||||
## 5. 九渠道接入
|
||||
|
||||
| 渠道 | 接入位置 | 回复方式 |
|
||||
| --- | --- | --- |
|
||||
| 微信 | `src/channels/weixin/weixin-bridge.mjs` | 现有命令回复流程 |
|
||||
| 飞书 | `src/channels/feishu/bridge.mjs` | 现有命令文字回复流程,不新增卡片 |
|
||||
| 钉钉 | `src/channels/dingtalk/dingtalk-bridge.mjs` | 现有命令回复流程 |
|
||||
| 企业微信 | `src/channels/wecom/wecom-bridge.mjs` | 现有命令回复流程,不单独处理 |
|
||||
| QQ | `src/channels/qq/qq-bridge.mjs` | 现有命令回复流程,不单独处理 |
|
||||
| Slack | `src/channels/shared/text-harness-bridge.mjs` | 继承共享桥接器,复用现有发送函数 |
|
||||
| Telegram | `src/channels/shared/text-harness-bridge.mjs` | 同上 |
|
||||
| Discord | `src/channels/shared/text-harness-bridge.mjs` | 同上 |
|
||||
| WhatsApp | `src/channels/shared/text-harness-bridge.mjs` | 同上 |
|
||||
|
||||
因此实际只需要接入六处桥接入口,不复制九份查询或格式化代码。各渠道现有回复目标、鉴权、入站去重、发送失败处理和机器人回声过滤都保留。
|
||||
|
||||
不修改 QQ Markdown 回复机制、企业微信即时回复机制、Discord Thread 路由、Telegram 富消息机制或任何平台 SDK。这里承诺的是复用现有行为,不额外承诺本次解决底层发送链路已有的重试或重复投递问题。
|
||||
|
||||
## 6. 状态和异常
|
||||
|
||||
| 情况 | 结果 |
|
||||
| --- | --- |
|
||||
| 没有绑定 Session | 提示先开始或绑定会话,不自动创建 |
|
||||
| Session 为空 | “当前会话暂无可预览的历史消息” |
|
||||
| 请求 N 条但只有更少 | 返回实际数量 |
|
||||
| 最近记录包含失败或中断的 Turn | 用户输入仍可显示,不把未完成的助手片段当成最终回复 |
|
||||
| 任务正在运行 | 可查历史,不停止、不等待任务结束 |
|
||||
| 正在等待提问或审批 | 命令不被当作交互答案,不提交或取消原交互 |
|
||||
| 批量输入正在收集 | 沿用现有规则,提示先 `/send` 或 `/cancel`;不收录、不查询 |
|
||||
| `/history` 带图片或文件 | 提示仅支持文字命令,不转给模型 |
|
||||
| 数量格式错误 | 返回用法;大于 5 的合法正整数不是错误 |
|
||||
| Session 不存在 | 提示重新绑定,不静默新建或切换 |
|
||||
| 读取期间发生切换 | 丢弃旧结果,提示重新执行 |
|
||||
| Harness 不支持、超时或返回异常 | 返回简短安全提示,不泄露原始异常和历史数据 |
|
||||
| 平台发送失败 | 走该渠道现有错误路径,不新增历史专用重试 |
|
||||
|
||||
`/history` 应接到现有快速命令分支:在批量输入规则之后、待回答问题和审批识别之前处理。无效参数同样在本地消费,不能落入普通消息流程。新命令的识别不能因为携带附件而绕过校验、转发给模型。
|
||||
|
||||
## 7. 最小改动清单
|
||||
|
||||
1. 新增 `src/channels/shared/history-command.mjs`:命令解析、数量上限、历史筛选、输出预算、提示文案;返回现有命令结果结构。
|
||||
2. 修改 `src/channels/shared/harness-client.mjs`:增加 `readSessionHistory(sessionId, options)`,复用已有 RPC 和错误类型。
|
||||
3. 修改 `src/channels/shared/bot-workspace-store.mjs`:在 `workspaceSession()` 句柄增加历史读取方法,复用工作区代际校验;命令另检查当前聊天绑定是否仍相同。
|
||||
4. 六处桥接器接入共享命令,并传递私聊类型及文字/附件信息。
|
||||
5. 更新九渠道帮助文案、共享 `/session` 成功提示及飞书自己的绑定成功提示。只增加命令提示,不重放历史或新增按钮。
|
||||
6. 更新现有中英文文案、`README.md`、`README.en.md` 和 `CHANGELOG.md`。
|
||||
7. 增加共享测试及九渠道接入测试。不新增持久化状态、依赖包或配置迁移。
|
||||
|
||||
读取链路不得调用 `session.create`、`session.prompt`、`session.cancel`、`executeCommand` 或会话恢复/接管方法;`session.history` 本身能够读取未激活会话,不需要先创建 Agent。
|
||||
|
||||
## 8. 验收与实施顺序
|
||||
|
||||
先完成共享命令和历史读取测试,再一次性接入六处入口覆盖九渠道,最后补帮助文案并执行现有 `npm run check`。
|
||||
|
||||
共享验收:
|
||||
|
||||
- 默认 3 条;参数 1、3、5 正确;6、100 和很大的正整数均按 5 条;0、负数、小数及多个参数返回用法。
|
||||
- 最新 N 条、旧到新显示、数量不足及空会话正确;不能把“一轮”误当“一条”。
|
||||
- 用户历史中的 `/history` 命令记录在计数和截取前排除,数量不足时沿用有限分页补取;普通正文和助手回复中的提及不删。
|
||||
- 多工具步骤、内部注入、推理内容、压缩替换、运行中回复、失败/中断及重复事件的筛选正确。
|
||||
- 单条超长、中文、emoji、代码文字均遵守预算,最多 5 条记录和 3 段回复。
|
||||
- 补读有上限且游标推进;API 不支持、超时、坏数据和读取期间切换均安全退出。
|
||||
- 进程内 API 与显式 HTTP 模式都覆盖;查询全程不触发模型、会话创建、恢复或交互响应。
|
||||
|
||||
九渠道都执行同一组接入验收,不以“继承共享类”代替覆盖:
|
||||
|
||||
- 私聊发送 `/history` 和 `/history 10`,分别得到最多 3 条和 5 条,且回到原聊天。
|
||||
- 未授权来源按原策略拒绝;已接收的群聊命令不读历史,提示去私聊。
|
||||
- 正在运行、待回答/审批、批量输入三种状态都符合上表。
|
||||
- 重复平台事件不重复处理;发送失败按原渠道处理;历史回声不触发新模型请求。
|
||||
- `/help`、绑定成功提示和英文提示包含正确用法。
|
||||
|
||||
发布前使用可用的真实机器人做九渠道私聊冒烟。未完成的实机项明确记录,不能将 mock 测试通过写成九渠道已经实测通过。发布回退可撤回命令入口和帮助提示,无需回滚会话数据。
|
||||
|
||||
## 9. 核对依据
|
||||
|
||||
- 本仓库 `workspace-command.mjs` 的命令结果与 1,800 字符分段器,以及六处桥接器现有的 `result.messages` 发送循环。
|
||||
- 本仓库 `harness-client.mjs`、`bot-workspace-store.mjs` 和 v3.0.8 的 `harness-connection.mjs`。
|
||||
- [Harness 历史 API 契约](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/apiproxy/src/api/sessions.ts):`session.history`、反向分页及只读行为。
|
||||
- [Harness 事件定义](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts):用户来源、Turn 状态与定稿助手消息。
|
||||
- [Harness 原始对话与替换内容的区别](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/surface.ts):人类对话预览不能照搬压缩后的模型上下文。
|
||||
|
||||
上游仍在演进,实施时以实际支持的 Host 协议和测试样本为准,不额外假设新的 RPC 或字段。
|
||||
|
||||
## 10. 验收记录
|
||||
|
||||
2026-08-28:
|
||||
|
||||
- 用户确认:九个渠道实测均 OK,并要求停止进一步客户端测试。此项为用户确认,不代表我们独立完成了全部原生客户端实测。
|
||||
- 自动验证:`npm run check` 的构建、1,554 条全量测试及包产物校验通过;随后新增的 Slack 前导空格联合回归通过,`history-bridge` 测试文件 112/112 通过。
|
||||
- 追加优化:在计数前排除 `/history` 命令记录,普通正文中的命令引用不受影响;`history-command` 34/34、重新构建及包产物校验通过。重启加载后,仅向飞书机器人“今天是牢梁”发送一次 `/history`,返回 3 条正常历史消息,不包含查询命令;本轮未复测其他渠道。
|
||||
Loading…
Add table
Add a link
Reference in a new issue