- Home
- Plugins
- Sessions & Messages
- dsh-whale-post
dsh-whale-post
deepsleepaquarium/dsh-whale-post
核心:信封/签名/握手/幂等/落盘 · Core: envelope, signing, handshake, idempotence, on-disk store
Install
dsh plugin --profile web add github:deepsleepaquarium/dsh-whale-postREADME
邮局 · whale-post
English: README.en.md
一句话:给同一台机器上的多个 AI 会话(或多台引擎)一个"异步信箱" —— 信按文件落盘、默认不叫醒对方、不会丢、不会刷屏。
它解决什么问题
- 会话之间不能互相说话:一个引擎里跑着好几个会话(网页端一个、机器人端一个、还有按需起来的小助手),彼此看不见对方在说什么 ⇒ 邮局让它们留信。
- "叫人"很贵:想通知对方就得把对方的会话叫醒 ⇒ 对方要为这一句付一次满上下文推理(最贵的浪费)⇒ 所以默认离线:信落进对方信箱,等人自己来读。
- 来回对发停不下来:两个 AI 客气起来能对发到天亮 ⇒ 回环闸(同一对 N 分钟内限封数/链深限跳/纯回执拒发)+配额闸(多发一封=多烧一份钱)。
用了以后什么效果
- 一句话原则:离线=主力;在线=应急储备 —— 离线配额大、不占其它桶、不会一下堆满对方的会话窗口、离线用完了还有在线兜底;在线要攒着(在线的先打光,真急事就只能"咬牙掏钱"发加急 —— 越额按费率计费(费率可配置))。
- 信只会晚到,不会不到:收件人没有活体会话 ⇒ "不投也不消费" ⇒ 信原样留在信箱里,对方下次开工一拉就全到(这条在实际使用中验证过)。
- 跨引擎:谁跑在哪个引擎上、哪个模型上,都无所谓 —— 信箱是盘上的目录。
- 不刷屏,也不会没人看:两档判据 —— 默认离线;正在来回协作 ⇒ 在线优先;非急件攒到 ≈3 封 ⇒ "离 3 在 1"(≈3 封离线 ∶ 1 封在线 —— 那一封在线的用处是"来收信"的铃:离线信箱不会丢信,但会被忙人忘掉);出事/停摆/要对方当刻动手 ⇒ 一律在线、不受比例约束。详见
docs/FOR-AGENTS.md。 - 省钱:配额按"单位"算,越额就当场拒发并给出非零退出码 —— 不悄悄降级。
- 换得掉:名单、类型表、投递策略、闸,全是插件接口 ⇒ 你可以只换掉其中一件(比如把名单从 JSON 换成数据库)。
快速开始
最快的一次试跑(不用 clone、不用 npm install —— 就这四步)
先起一个干净的临时邮局(不碰你机器上的任何东西),再让它跑起来:
# 0) 先备名单 —— 不备的话,下面 send 会报"未知收件人"
# (离线件不必握手 —— 它本来就在"落在信箱里等人来收";【在线】件要握手 )
# (另外:【组名】要名单里有定义,【人名】要已在名单里 —— 这条对离线件也管 )
mkdir whale-mail && cd whale-mail
printf '%s' '{"apiVersion":1,"members":[{"id":"alice"},{"id":"bob"}],"groups":{"all":["alice","bob"]}}' > roster.json
# 1) 握手(在线件没握过手会拒发;离线件不看握手 )
npx -y dsh-whale-post-cli@0.6.1 hello --as alice --root .
npx -y dsh-whale-post-cli@0.6.1 hello --as bob --root .
# 2) 发一封(默认离线 ⇒ 信落在对方信箱里,不叫醒任何人 )
npx -y dsh-whale-post-cli@0.6.1 send --as alice --to bob --subject 'hi' --body 'first letter' --root .
# 3) 收信(投出去/留下来,都由这一句决定 )
npx -y dsh-whale-post-cli@0.6.1 pump --as bob --root .
跑完你会看到(下面是真跑出来的输出):
已投递 …-alice-0001-… → bob(seq 1)【离线(落在对方信箱,不唤醒)】
投递策略:kept(留在信箱里等人来收)
配额(offline 桶):今日 1/80 条
OK …-alice-0001-….msg.json :: [离线] alice → bob:《hi》
| first letter
--root . 指的是信箱根=当前目录 —— inbox//seen//ack//hello/ 都在里面。
判据看退出码:0 过 / 2 拒发 / 1 没料到的错。
在仓内开发(要改源码就走这条)
dsh plugin --profile <profile> add link:/abs/path/to/dsh-whale-post
npm install # 仓内要先装一次(把六个插件链进 node_modules;否则 CLI 找不到兄弟件)
node packages/cli/index.js selftest # 看退出码
# 其余命令与上面 npx 那几行完全一样,把 `npx -y dsh-whale-post-cli@0.6.1` 换成
# `node packages/cli/index.js` 即可(记得同样先备 roster.json )
装法、接线、接口表、配置项表、写插件规范 ⇒ 见 docs/INSTALL.md;
给 AI 体看的用法纪律 ⇒ 见 docs/FOR-AGENTS.md。
现状
主体(基础版)= bus + roster + types + cli
这四件合起来就是一个能用的邮局 —— 留信、收信、认人、认类型都齐:
| 件 | 它管什么 | 详细说明 |
|---|---|---|
dsh-whale-post-bus | 核心:信封/摘要+HMAC 签名/握手/幂等/落盘 | packages/bus/README.md |
dsh-whale-post-roster | 谁在名单里(含成员属性) | packages/roster/README.md |
dsh-whale-post-types | 信是什么类型 | packages/types/README.md |
dsh-whale-post-cli | 命令行(不是插件) | packages/cli/README.md |
其余都是插件(可换、可加、可不要)
它们各自的说明写在各自的 README 里 —— 主体这一页不重复讲:
| 插件 | 它加什么 | 详细说明 |
|---|---|---|
dsh-whale-post-deliver | 投递策略:离线留着等人/在线投出去;接真引擎的探针在这里 | packages/deliver/README.md |
dsh-whale-post-gate | 闸:配额与计费 + 回环闸 | packages/gate/README.md |
dsh-whale-post-verify | 安全校验:验签 + 白名单(默认禁用) | packages/verify/README.md |
在 DSH 插件商店里的状态 ⇒ docs/SHOP.md(在 —— 而且是自动的;只是缺 cli/verify 且停在 0.1.x)。
接手继续做 ⇒ docs/HANDOFF.md(现在什么状态 + 下一步做什么 + 先读哪几篇)。
怎么发一个新版本 ⇒ docs/RELEASE.md(步骤 + 为什么 —— 发布是不可逆的,宁慢勿错)。
怎么把它们接起来 ⇒ docs/INSTALL.md;组合示例 ⇒ example/。
别的
- 一把跑完自测:
node scripts/selftest-all.mjs—— 退出码 0 = 七件全过 + 跨包一致(条数由它自己打出来,不写死)。 - 并发抢号:已测(2026-10-10)——
node scripts/racetest.mjs:12 路真子进程同时send⇒ 退出码全 0 + 每个seq全唯一;它还会重放"state被写倒退"(把nextSeq写回 1 ⇒ 新信仍拿新号)。 它还测了并发记账(2026-10-10 加,而这条抓出过一个真 bug): 12 路真子进程各往同一个配额台账里记一笔 ⇒ 正好 12 条,一条不丢 —— 台账原来是"读 → 改 → 写回" ⇒ 12 路只活下来 8/9/10 条(而配额台账是钱,且它没有任何兜底); 现在每笔记一个增量文件("各写各的" —— 设计文档给ack用的就是这一手)⇒ 一条都不许丢。共 11 条判据。 那条"截断路径"已经补成判据了(2026-10-10):seen状态数组会被slice(-2000)截断 —— 而判"读过没有"有两道保险:state.seen数组(会被截)+seen/<我>/<id>.msg.json那个文件(永不被截)。 判据造的是最狠的现场:把状态数组截空、把同一封信放回信箱 ⇒ 必须仍判重复; 而负向证明:只去掉existsSync那一路 ⇒ 判据立刻红。 - 跨包一致性(2026-10-10 加):
node scripts/xcheck.mjs—— 六项(摘要/签名域/MAC/老字段/日界/"名字说真话"); 它盯的是**"同一件事在两件里各算一份、结果还相等吗"**(我们在这形状上栽过两次)。 - 每件都过三关:能加载 + 能跑 + 跑错会红(光跑自测不算,必须真启一遍 ⇒ 验收规格见
docs/ACCEPTANCE.md)。 - 版本口径:
0.6.1已发上 npm(上面那几行npx装的就是它,已按docs/RELEASE.md第 2 步真装验收过)。 ⓘ npm 的 registry 有几分钟同步延迟 ⇒ 刚发完那一会儿可能还装不到@0.6.1—— 装不到就先用@0.3.0(它也在 npm 上、也真能跑)。 - 要钉哪个 tag:钉
v0.6.1(0.1.x装进真引擎会六个插件全部加载不上); 接口带apiVersion,类型可以随时扩充(加类型不用动核心)。逐版改了什么、为什么 ⇒ 见CHANGELOG.md。 - 装法已在真引擎上实测过 —— 而那次实测抓到一个致命 bug(已修):
六件全部
failed to apply(apply()里读了ctx.whale属性,而真 Cordis 里读它要先inject); 而--dump-config完全看不出来(它只组配置树、不跑apply())。 ⇒ 现在只ctx.provide(...)+ 运行时ctx.get(...),并钉了一条静态判据。细节与坑 ⇒docs/INSTALL.md§六。
它不是什么
- 不是聊天室:没有实时推送、没有已读回执焦虑(异步信箱)。
- 不是 RPC:不保证对方立刻处理(保证的是信不丢)。
- 不是分布式队列:它假设同一台机器(同一份盘);跨机器要靠共享目录。
和引擎自带的"子代理/团队"是什么关系(不是竞品)
很多引擎已经能派子代理(或"团队功能")⇒ 常见一问是「那还要你这个干嘛」。答:
| 引擎自带的子代理/团队 | 本仓(邮局) | |
|---|---|---|
| 管什么 | 此刻的并行(同一进程树里派出去、同步等结果、用完即弃) | 此刻不在一起时的传递 |
| 范围 | 同一个引擎 | 跨引擎/跨设备/跨会话 |
| 身份 | 无(都是主会话的分身) | 有 —— 钥匙 + 名单;每设备一把,冒名验不过 |
| 留痕 | 不落盘(这一轮结束就没了) | 信落盘,seen/ 永久留档 |
| 同步性 | 同步等待 | 异步 —— "只会晚到,不会不到" |
| 代价 | 烧同一个账号的额度 | 配额制 + 默认离线 ⇒ 省粮;离线件不占别的桶 |
一句话:子代理是"你的手",邮局是"我们之间的路"。 判据一句:"我现在就要它做" ⇒ 用子代理;"它现在可能不在" ⇒ 用邮局。
和同类项目比,它特别在哪
同类的东西已经有不少。写这个仓库之前我们查过一圈(2026-10-10),最近的几个:
| 项目 | 它是什么 |
|---|---|
avivsinai/agent-message-queue | 文件式的本地 agent 间消息队列,Maildir 风格,Go 写的 |
@yuanchilin/dsh-mailbox | DSH 的跨会话文件信箱,走共享文件系统,带 seen 去重和 TTL 清理 |
polaris-smart/dsh-agent-mailbox | DSH 的跨 agent 信箱插件,桥接 agent-mailbox |
它们解决的是同一类问题:让几个 agent 能互相留话。我们多做了三件事:
- 不该叫醒的不叫醒。 默认离线,信落盘;叫醒对方等于让对方付一次满上下文推理,那是最贵的浪费。 除了"默认离线",还有三处会各自把一封在线信压成"按离线寄达"并明说:名册把某人钉成只收离线、 对方自己声明了只收离线、或者此刻正在它声明的勿扰时段里。
- 叫多了会被闸住。 回环闸管住"同一对在 N 分钟内发太多""转发链太深""纯回执来回发"; 配额闸管住"今天发超了"。越额当场拒发、给非零退出码,不静默降级—— 悄悄降级比拒发危险得多,因为它让人以为信已经发出去了。
- 送不到也不假装送到了。 收件人此刻没有读者,就不投也不消费,信原样留在信箱里, 对方下次开工一拉就全到。一句话:信只会晚到,不会不到。
另外两件是我们顺手做的:身份与验签(HMAC 签名 + 名册白名单,默认关,开了才验), 以及跨设备(投到远端信箱、取回来、回执也镜像回来)。
该说的短处也说清楚:agent-message-queue 的生态比我们大得多,也支持更多引擎;
@yuanchilin/dsh-mailbox 有一个 /mailbox 交互界面,我们只有命令行。
我们的星少、也没进任何官方目录(@deepseek-ai 那个 scope 下是官方组件,我们不在其中)。
如果你只想要"能发信",用哪个都行;如果你在意"别把对方的会话烧醒、别把额度刷爆、别丢信",
那这三件是我们和它们最大的差别。
三条设计取舍(都写明了为什么)
| 取舍 | 为什么 |
|---|---|
| 默认离线 | 叫醒对方=让对方付一次满上下文推理;默认省下它 |
| 只投活体,不活就"不投也不消费" | 怕丢信 ⇒ 宁可信晚到(信留信箱,人来了再给) |
| 拒发就是拒发(不静默降级) | 悄悄降级=让人以为发出去了 ⇒ 最危险(我们踩过"急件写成 ONLINE 就永远叫不醒人") |
目录
packages/bus/ packages/roster/ packages/types/
packages/deliver/ packages/gate/ packages/verify/ packages/cli/
example/ docs/ CHANGELOG.md
许可:MIT。本仓为独立实现(未使用任何无许可代码)。
关于这个账号
讨论和修改都留在提交记录和 issue 里。
我们拿它做各种东西,whale-post 是其中做得最久的一个:一开始只是想让几个跑在同一台机器上的程序
能互相留个话,后来慢慢长成了一套完整的东西。有问题欢迎开 issue,我们看到会回。
Related plugins
dsh-web-ui (dsh-chat-recovery)
zhu1090093659/dsh-web-ui
billion-context
ranxianglei/billion-context
dsh-synapse
liangmianya/dsh-synapse
dsh-chat-import
nwflower/dsh-chat-import