Skip to content
dsh.fish
Bundle

dsh-send-debounce

把用户在聊天框连发的几条短消息合并成一轮后再唤醒模型(消息级防抖 / 缓冲合并)。

Source
praystring
License
MIT
Updated
Updated 7 days ago

Readme

# dsh-send-debounce

给 DSH 的「连发消息」加一层缓冲:用户在聊天框里一句接一句地发,中间**不产生 N 次唤醒/回复**;
停手若干秒后,这几条**合并成一轮**送进模型,只回一次。

> 英文说明见 [README.en.md](./README.en.md)。 / English: see [README.en.md](./README.en.md).

## 它做什么

- 拦截点:服务端每个 agent 的 `followup()`(`@deepseek-ai/dsh-agent-loop`)。
- 用户消息**立刻进排队区**(网页上看得到),但**先不唤醒**模型。
- 默认静默 **5 秒**;期间每来一条短消息就重置计时。
- 到点后把这一批合并成一条消息,再唤醒一次。
- 长消息(默认 ≥120 字)或带图片/附件的消息**立即发出**,不延迟。
- `steer()`(插话)和 `agent.followup` 的插件来源(如 `dsh-proactive`、`dsh-tick`)不受影响。

## 配置(环境变量,改完重启 dsh 生效)

| 变量 | 默认 | 含义 |
| --- | --- | --- |
| `DSH_SEND_DEBOUNCE` | 开 | `off` / `0` / `false` / `no` 一键关闭 |
| `DSH_SEND_DEBOUNCE_MS` | `5000` | 静默时长(毫秒);`0` 等于关闭延迟;非法值退回默认 |
| `DSH_SEND_DEBOUNCE_MAX_CHARS` | `120` | 「短话」上限;`0` = 一律延迟;非法值退回默认 |

## 安装

从 npm(公开包):

```sh
dsh plugin --profile web add dsh-send-debounce
```

从本地目录(自用/开发):

```sh
dsh plugin --profile web add file:/path/to/dsh-send-debounce
```

装完把 `dsh-send-debounce` 加进该 profile 的 `dsh.profile.bundles`(`cordis.patch.yml` 就是这一层),
然后重启并确认网页还在:

```sh
dsh --profile web --dump-config | grep -n dsh-send-debounce
sudo systemctl restart dsh
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3080/
```

## 安全边界(很重要)

这个插件的原则是**只做缓冲,别的什么都不碰**:

- **只处理网页用户自己发的消息**(`message.source.kind === "user"`)。插件来源的消息
  (`dsh-proactive`、`dsh-tick` 等)原样放行,否则会卡住它们的 `whenIdle()`。
- **不碰 `steer()`(插话)**,也不主动修改会话历史;只把自己入队的那几条消息在到点后
  合并成一条,交给原生 `followup()`。
- **长消息和带附件/图片的消息立即发出**,绝不延迟,避免大段内容被拖着。
- **原文不改写**:合并只是在两条消息之间插入空行,保留各自原文与顺序。
- **任何异常都退回原生行为**:读队列失败、合并失败、发送失败都会被 `try/catch` 兜住,
  逐条补发或直接放行,不让聊天框卡住。
- **不联网、不读工作区、不写文件、不读环境里的密钥**:只读三个 `DSH_SEND_DEBOUNCE*` 配置项。
  源码全部在 `index.mjs`,可自行核对。

## 已知限制

- **静默期是进程内定时器**:dsh 在合并触发前重启,这批消息仍持久化在会话里,但**不会自动
  被唤醒**,要等下一条消息进来(或手动触发)才会继续。重启前请等几秒让缓冲落地。
- **环境变量改动需重启 dsh**,不支持热更新。
- **长短按字符数判断**,不看语义;一句很短但很急的话也会被缓 5 秒。
- **合并后模型看到的是合并文本**,不再区分原来是几轮输入;原始入队记录仍在会话的
  inbox 事件里,但这只对排查有用。
- 只在服务端生效(手机浏览器同样受益),不改变前端界面。

## 回滚

按 profile 备份还原:

```sh
cp ~/.dsh/profiles/web/package.json.bak-<日期> ~/.dsh/profiles/web/package.json
sudo systemctl restart dsh
```

或只把 `dsh.profile.bundles` 里的 `dsh-send-debounce` 删掉再重启即可完全卸载
(卸载会清掉定时器并恢复原生 `followup()`)。

## 自测

不需要 dsh 环境,直接用 Node 跑:

```sh
npm test            # 等价于 node test.mjs
```

覆盖:连发合并、长消息直发、插件来源直通、图片直发、间隔超时各成一轮、卸载恢复、
关闭开关、配置解析与非法值兜底、重复安装/卸载、agent 销毁清定时器、纯函数。

## 许可证

MIT,见 [LICENSE](./LICENSE)。

Install

dsh plugin --profile web add github:praystring/dsh-send-debounce

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source