# 0.9.0 更新说明 2026-11-05。0.9.0 是一次大版本。 这一版把四个一直只在开发副本里生效的功能,对所有人打开了:**梦**、**主观能动性**、**兴趣**、**主动搭话**。同时把「桌上有什么」并成一张桌子,把「刷 B 站」从叫醒路径上摘下来,并修掉了几个真机才暴露的问题——包括通过 QQ 桥在 40 轮整换房时会多建一条会话的那个。 原来准备单独发的 0.9.1 桥接改动,也并进这一版;不单独发 0.9.1。0.8.9 也没有单独的 GitHub Release(npm 上的 0.8.9 是改名首发),它的两件事同样并进这一版。 按「你会看到什么」排: - **她会自己开口**,但四个条件要同时满足(见第一节)。 - **她会攒劲儿、会惦记、缺工具直接跟你要**(主观能动性 / 兴趣)。 - **梦**:她做过的梦,在住所页能看到。 - **空醒**:醒来没事时,她可以自己找点事做。 - **QQ 桥**:可以自己决定开几间房、谁是外客;群房按天换新。 - **设置页四张卡**:主动搭话 / 主观能动性 / 兴趣 / 梦,可以各自关。 - **刷 B 站不再由叫醒驱动**(`bili_*` 工具仍然可用)。 - **修掉**:劲儿恒 0.00、安静时钟被别的会话清零、40 轮换房多建一条会话、「没什么要说的」被算成一次开口。 --- ## 一、她会自己开口(主动搭话) ### 你会看到什么 有时候你打开对话框,会看到她先说了话——不是回答你,而是她自己想起来要说的。那条消息是一条**默认收起的折叠条**(「收到执行请求」,展开是「这条通知触发了本轮回复。」)。这是宿主对「不是人发的消息」的默认画法,插件改不了标题与样式(0.9.0 复核过宿主前端,只认 `source.kind`,`form` / `summary` 对这条路径无效)。 ### 什么时候会开口 四个条件同时满足才开一轮: 1. **她自己攒够了一股想动的劲**(内部叫「劲儿」,0 到 1,默认按每小时 0.12 的速度攒,到 0.8 算攒满;桌上有材料时更快,四小时上下就能到;开过一次之后要重新攒,两次之间至少隔两小时)。 2. **现在在她的醒着时段里**(默认 12:00–02:00,可在 `config.json` 的 `window` 调)。 3. **你确实有一阵没跟她说话了**(`minIdleHours`,默认 6 小时,下限 1 小时)。 4. **桌上有可说的东西**(见第二节)。桌上空的,劲儿再满也不动——这条是 0.9.0 加的。 攒满了也不是每次都开口:她醒过来看一眼,发现自己没什么想说的,就什么都不说。 ### 默认是关的 `proactive.enabled` 默认 `false`。0.9.0 让这个功能公开可见,但没有替老用户把它打开——这样升级上来的机器不会突然多出一个会自己说话的鱼。想用就去设置页的「主动搭话」卡打开;关掉只是以后不再自己开口,已经写下的话一条不删。 ### 不想说就真的不写 以前她「没什么想说的」,还是会在对话里留一句「这一轮没什么要说的」。现在不会了:那一轮只留一行记录,对话里什么也不出现。提示词里把「什么都不做」改成「不想说就什么都别写:不要写任何字,也不要解释为什么不说」;真的只写了一句元话语时,按「没开口」记账——不占当天次数、不进对话流,折叠成一行。判据在 `lib/compact.js` 的 `looksLikeNothingSaid()`,超过 60 字一律不算元话语。 ### 为什么不是按表打卡 定时叫醒是「按点开一轮」,主观能动性是「攒够了才有的冲动」。两者的区别不在频率,在于**这一轮有没有由头**。所以劲儿不是一个定时器:它看的是「距上次动过了多久」「桌上是不是多了东西」「你回来过没有」,以及「上次她开口有没有人接」——上次没人接,这次就攒得慢一点。 ### 花多少 开一次约 1.5 分钱(实测 `¥0.0146`)。想省就把「一天最多几次」调到 1,或者把「你多久没说话」调大。 --- ## 二、主观能动性:劲儿、兴趣、惦记 ### 她自己攒劲儿 距离上一次自己动过多久、桌上有没有新料,合起来算一个「劲儿」: - 时间底噪:每小时 0.12; - 桌上有新料会加快; - 满 1.0 才开一轮,动完按 0.8 记账; - 两次之间至少 2 小时。 效果是:桌上有东西时更早醒,一直没什么可说时会拖得很久,而不是每天固定几次。 ### 兴趣:桌上摆什么 她醒来时,处境里会有一句「桌上摊着这几样东西」或「桌上还有一件没合上的事」,下面最多五条。来源有四个: - **她自己问过、还没答案的问题**(最多 2 条,7 天半衰;重复问同一件事会合并成一条); - **搁了很久的旧句子**(7–30 天前说过的,最多 3 条,只在「没有派活的醒来」里摆); - **她最近总说到的那件事**(最多 1 条,旁注「最近你总说到它」); - **她给你留过话、你有没有来过**(单独一句,72 小时内有效)。 答应过还没做的事(待办)不在这张桌子上面,它固定在处境最前面——她的原话是「摆在我最前面」。 原来「旧句子的桌子」和「好奇的桌子」各占一段,同时出现时提示词里会连着两段「桌上有……」,像两份清单。0.9.0 并成一张桌子、一个总配额,条目之间还会去重。 ### 缺工具,她会直接开口要 她想到要做一件事、但手上没有那件工具时,会直接说「我需要一个能读网页的东西,你能给我装上吗」,或者开一张 ask 卡问你——而不是绕着走,或者假装这件事做不到。 插件只给她最基本的一组工具(说话、记录、看 B 站、记梦)。0.9.0 在处境里补了一句:缺工具不是失败,直接说你要什么。主人要不要装、装哪个,仍然是主人的决定;插件不会自己扩工具。 ### 这套机制的灵感 「劲儿」和「兴趣」的机制灵感,来自交流群 2 群的群友 **「无」**:主动性不该是定时器,而应该是攒够了的冲动;桌上有什么,决定这一轮有没有由头。落进这个插件时全部重新实现,没有代码或文本的直接搬运。 --- ## 三、梦 她偶尔会把真实发生过的事重新拼成一句梦。梦不算成长,也不会被当成新的记忆。 0.9.0 起: - `her_dream` 与 `/dream` 对所有人开放,不再需要 `.dev`; - 「她做过的梦」卡搬到**住所页**,和日记、她写的小纸条放在一起——这一页回答的是「东西都在哪」; - 开关在**成长页的「梦」卡**里,不在住所页放两份; - 关掉只停止记新的,旧的一条不删。 以前这张卡按 `.dev` 藏起来,文案还写着「只在这台机器的开发副本里显示」;现在文案改成「她偶尔会把真实发生过的事重新拼成一句梦;不算成长,也不会被当成新的记忆」。 --- ## 四、空醒:醒来没事时,她自己找点事做 醒来时没有待办、桌上也没有东西,她可以自己翻翻旧句子、写点什么,也可以什么都不做。 - 开关:`memory.selfWake`,默认 `true`; - 设置页在「兴趣」卡里,叫「醒着没事时,自己找点事做」; - 关掉只影响这一种醒来,摆料那种照旧。 --- ## 五、QQ 桥:开几间房、谁是外客 这一节写给用桥的人;不用桥可以跳过。 桥现在可以自己决定「开几间房、每间是谁」,插件只提供机制。三个可选字段: - `room`:`house`(并进书房)或 `channel`(另开一间)。不传时私聊回书房、群聊另开。 - `title`:侧栏里那间房叫什么(群名、昵称)。不传才回落到 channel 键。 - `guest: true`:标记「外面的人」(群友私聊这类)。标了 `guest` 的消息不写 `seen:`、不涨轮数、不触发轮换、不进「上次我们说到这」,正文写「有个不是他的人跟你说话」。 `speaker` 现在对所有场次生效:以前只有群聊拼「某某在群里说:」,现在私聊(尤其是群友私聊)也会带上是谁说的,免得三个人被当成一个人。 **群房按天轮换。** 默认一间群房用满 **7 天**换新的(`config.rooms.groupRotateDays`,`0` = 不换)。旧房改名成「… YYYY-MM-DD 之前」留在侧栏,新房从当天重新算。热闹的群 200 条上下文一会儿就满,按轮数不好估,所以按天。 **房间收纳改成按「最近说话」。** `channels.json` 新增 `bornAt` / `lastAt`,超过 40 间时先丢最久没说话的,不再丢最早建的(旧的「最早建的先被忘掉」会让被丢的群下次说话时再建一间同名房,旧房成孤儿)。老档没有这两个字段时按 `at` 兼容。 常见布局都由桥表达,插件不写死: - 全部并进书房:不传 `channel`,或 `room:'house'`; - 每群一间:`channel:'qq-group:<群号>'` + `scene:'group'`; - 群友私聊每人一间:`channel:'qq:dm:'` + `scene:'private'` + `room:'channel'` + `guest:true`; - 群友私聊进书房但标身份:`scene:'private'` + `guest:true` + `speaker`; - 只有 @ 她才进:桥侧过滤,不投递就不建房。 ### 40 轮整换房,不再多建一条会话 这是 0.8.8 留下的问题,0.9.0 修掉。 桥接从 QQ 往屋里递话(`POST /dsh-fish/say`)时,满 `chat.rotateAfter` 的那一轮会有两条路同时结账:`lib/say.js` 的投递收尾与 `lib/turns.js` 的轮次收尾,两边都调 `rotateTalkSession`,中间没有互斥——于是 115ms 内各 `sc.create` 一条:先建的收到唤醒、在里面跑了一轮,之后成了侧栏里看不到的孤儿;后建的被写进 `home.json`。长期记忆不丢,但侧栏多一间同名空房,孤儿里那一轮再也翻不到,轮数也被多算。 现在换房间同一时刻只有一次在飞:同一数据目录内合并成一次,跨进程由 `withFileLock` 的 `.talk-session.lock` 兜底;并发进来的第二声直接等第一声的结果,不再建第二条。两条入口再各传一个 `from`,`home.json` 已经指着别的会话时就返回 `skipped`,日志写「换会话跳过」,既不建会话也不写重复的 `rotate:` 记录。 回归:`test/rotate-race.test.mjs` 3 条(同一刻两条入口只建一条、换完后迟到的那次跳过、`from` 不是当前屋子时不换)。 --- ## 六、设置页四张卡 设置 → 大肥鱼,现在分成四张独立卡: - **主动搭话**:开 / 关;一天最多几次(0–6);你多久没说话她才可能开口(1–24 小时)。 - **主观能动性**:她要不要自己攒那股劲。(关掉 = 只按日程叫醒,不会自己开。) - **兴趣**:要不要把「最近总说到的那件事」摆到桌上;以及「醒着没事时,自己找点事做」(空醒)。 - **梦**:梦里记不记事。 默认值: - `proactive.enabled`:**关**; - `drive.enabled`、`interest.enabled`、`dream.enabled`、`memory.selfWake`:**开**。 关掉只是以后不做,已经写下的梦、日记、事件一条都不删。 --- ## 七、刷 B 站不再挂在叫醒上 醒来时处境里不再有「B 站此刻在推什么」那一大段。`bili_look` / `bili_watch` / `bili_speak` 三个工具仍然可用,她想看的时候可以自己看。 刷站的初衷是「给她一个外部世界的接触面」,但把它挂在唤醒上有两个副作用:一是每次醒来都要先读十几个视频的标题简介热评,上下文开销大;二是它会让「醒来」变成「刷站」,把别的材料挤掉。0.9.0 把它从唤醒路径上摘下来,改成她想看的时候再调工具。 配置上 `browse.enabled` 默认改为 `false`;`bili.enabled` 默认 `true`(工具本身不受影响)。 --- ## 八、修掉的 bug ### 劲儿永远是 0.00 `drive.js` 里把事件的 `ts` 当毫秒数读(`Number(...)`),而它其实是 ISO 字符串,于是「出生时刻」和「上次自己动过」都被算成 0,日志里一直是 `drive 0.00 · 还没有任何记录,不急着动`——就算她 11 天没动过也一样。改成先按数字、再按日期解析。 ### 她永远等不到「安静够久」 安静时长(`minIdleHours`)原本把 `meta seen:` 也算作「他来过」,而这条记录会被**别的会话**的用户活动误写:他在这台机器上跟别的 agent 说话,她的安静时钟就被清零,于是 `proactive skip 刚说过话,还不到时候` 一直挂着,主动搭话一次都开不出来。现在只有真的有话落进她的房间(`heard` 等)才算,记账行一律不算。 ### 「没什么要说的」不再算一次开口 真机第一次自动开口,她回的是一整句元话语:「这一轮没什么要说的。今天想说的话,一小时前已经说完了。」她的判断没错,错在我们把这句话记成了一次开口:占掉当天额度、进了对话流、还挡住了静默折叠。 根因是「什么都不做」在文本界面上不成立。现在提示改成明确的出口:不想说就**不要写任何字**,也不要解释为什么不说;同时记账侧兜底——一轮里只有一句这样的元话语时,按静默记、把整轮折成一行,不占额度、不留噪音。判据做得窄(短、且开头就交代「这一轮 / 今天没什么要说的」),真话不会被吞。 ### 空桌不醒 劲儿只回答「攒够了没有」,不回答「攒够了有没有事可说」。桌上没有任何材料时,即使劲儿满也不起——否则醒来只能回一句「没什么要说」。 ### 群友私聊不再被当成主人 以前私聊不论谁发的都落进书房、写成「他跟你说话了」,群友会被当成主人本人。现在桥给 `channel + room:'channel' + guest:true` 就另开一间;标了 `guest` 的消息不写 `seen:`、不涨轮数、不触发轮换、不进「上次我们说到这」。 ### 0.8.9 的两件事(未单独发版,已并入本版) - **递话、叫醒不再堆空白会话。** `lib/deliver.js` 新增 `ensureSessionLive(sc, sessionId)`:先 `resolveAgent()` 探活,探不通才 `create`。`sayToHer`、主动开口、叫醒三处都改走它,会话被别的原因关掉时不会再新建一条空房。 - **回忆显示的两处修复(社区 PR #26)。** `brief` 档里长聊天的原话保留「|聊天里说的」;改口引用标「他说 / 读到别人说 / 回复」,先截原话再加标记。删掉不再使用的 `UNCLAIMED_PENALTY`,`latestRevisions` 不再导出;没有动 `+4` 认领加分与 voice / heard / answer 的排序。 ### 社区 PR #27–#31(已并入本版) - **#27 宿主拼的上下文不算他来过。** 宿主前端的 `snapshot` / `notice` / `catalog` / `instructions` / `recall` 是保留词表(`MACHINE_FORMS`),桥转述人话时不要带 `form`,或者用 `relay`。 - **#28 假宿主探活时机。** 测试里的探活只发一次,不再因为时机不同而误红。 - **#29 `her_note` 按她自己写过的话划掉。** 她可以用自己当时那句原话来销掉一张纸条,不必记住内部 id。 - **#30 没认领的聊天行。** 没被认领的聊天行不再被当成她认领的话。 - **#31 导出事件流只留元数据。** `her_log` 导出不再带正文(`meta` 行除外)。 --- ## 九、从 0.8.x 升上来 ### 升级方式 推荐用一条命令(不用先关 DSH): ```bash "/resources/runtime/cli/bin/dsh.cmd" plugin --profile add "@ssamurias/dsh-fish@0.9.0" ``` 也可以走设置页的「检查更新」——但 **0.8.9 从 npm 装的人**要注意:0.8.9 的升级代码只认裸名 `dsh-fish`,带 scope 的安装会被它判成「不归我管 / 开发版」,自动检查更新用不了;而且 0.8.9 的客户端半边还是短 id,设置页可能空着。这批人请直接用上面的命令装 0.9.0。 ### 0.9.0 里已经带了原本准备在 0.8.10 发的升级修复 - 升级改走 npm,不再把依赖记成 `file:updates/xxx.tgz`; - Windows 升级不再弹黑窗口(VBS `wscript //B` 隐藏); - 装完先清旧裸名残留(旧依赖键、旧 `bundles` 条目、旧 `node_modules/dsh-fish` 改名收起来),改 `package.json` 前先备份; - 客户端注册名跟着包名走,设置页那半边补回来; - `link:` 装的用户先跑一次 `node scripts/fix-legacy-link.mjs`,加 `--write` 真改,再启动。 ### 配置迁移 1. **`.dev` 文件不再需要**:梦、主动搭话、空醒、桌子 / 好奇 / 兴趣,0.9.0 起对所有人可见。以前为了看这些功能在 `~/.dsh-fish/` 下建的 `.dev` 可以删掉(留着也不影响)。 2. **新增配置键**:`memory.selfWake`(空醒开关,默认 `true`)、`drive.enabled`(主观能动性,默认 `true`)、`interest.enabled`(兴趣,默认 `true`)、`dream.enabled`(梦,默认 `true`)、`bili.enabled`(默认 `true`)、`rooms.groupRotateDays`(群房几天换新,默认 `7`,`0` = 不换)。 3. **默认关掉了自动刷站**:`browse.enabled` 从 `true` 改为 `false`。想恢复在 `config.json` 里手动设回 `true`。 4. **主动搭话默认仍是关的**:`proactive.enabled` 默认 `false`,去设置页打开。老配置升级不会因为这个版本突然变得吵。 5. **本机若把 `proactive.minIdleHours` 调得很小**(比如 1),建议调到 3:0.9.0 之前「刚说过话」这个门几乎没生效,调小会显得很吵。 --- ## 十、测试与鸣谢 全量 `node --test` = **1441 pass / 0 fail**。零运行时依赖。 感谢 **@BBleae(晴猫)**:从 0.8.6 起的五个 PR——#10 匿名 buvid3、#11 叫醒间隔、#15 叫醒那一轮不记成「他来过」、#23 日报 / 回忆分三种话、#26 回忆 `brief` 档的两处显示。0.9.0 期间还收到 #27–#31 五个 PR(#27 宿主拼的上下文不算他来过、#28 假宿主探活时机、#29 `her_note` 按她自己写过的话划掉、#30 未认领聊天行、#31 导出事件流只留元数据),已全部并入本版。 感谢交流群 2 群的群友 **「无」**:主观能动性的机制灵感来自他讲的「主动性不该是定时器,而是攒够了的冲动」。 --- ## 附:这一版没有做的事 - 没有加任何新工具。她的工具面仍然是那十只。 - 没有改人格设置界面。仍然没有「性格参数」。 - 没有把「主动搭话」默认打开。功能公开可见,默认关着,由用户自己开。