Kanadego/dsh-heartbeat

Kanadego/dsh-heartbeat

心跳循环:默认每 20 分钟自己醒一次——维护一份关于你兴趣与偏好的本地画像,按你设的兴趣范围上网搜新东西并存下来。攒到值得分享的内容,就向你绑定的会话送一份简短的素材包。能不能开口由代码里的规则决定(静默时段、忙时窗口、每日上限、冷却),说不说由那个会话里的 agent 自己判断。仅支持 Windows。

AGI 架构探索

dsh-heartbeat

让 DeepSeek Harness 的 agent 拥有持续存在感的心跳插件:她按节律自己醒来,维护记忆与画像、感知你的忙闲、按兴趣闲逛看新东西、把没说完的话带过下一拍,然后按分寸决定开不开口——开口要有真实来处,沉默要有具体理由。

一分钟了解

全部能力都收在 DSH 设置页的心跳卡片里,日常使用零命令行:

设置卡总览 · 素材池 ·

用户画像(只读) · 节律配置 ·

展开看其余分区:会话绑定 / 兴趣范围 / 账本 · 摘抄本 · 周报 · 换机迁移

会话绑定 · 兴趣范围 ·

账本 · 摘抄本 · 周报 · 换机迁移 ·

截图为 v2.0.0。画像与会话绑定两张里的条目文字已打码。

它想解决的三件事:

你想要的 · 插件怎么给 零命令行 · 绑定会话、节律、素材池、画像、账本、迁移全在设置卡里;CLI 只留给脚本场景 不打扰、不烧 token · 静默时段 / 忙时窗口 / 每日上限 / 开口冷却 / 在场联动全是代码层判定——判「别说」时,之后的决策与表达两相根本不调用模型(闲逛相在闸门之前触发,另算) 像活人,不像定时播报 · 素材分话题与聊天两仓,反刍成一句话再投递;说不说、说哪条,由你那个会话里的 agent 按当下处境拍板;没说完的话能留在心事匣里带到下一拍,看见想记的话就抄进摘抄本

快速开始

安装(npm 包,推荐)

dsh plugin --profile web add @kanadego/dsh-heartbeat

重启 DSH 即生效——插件自动创建专用心跳会话并按节律运行,之后日常无需任何操作。

心跳预设是自动装的:插件加载时直接向宿主注册(agentPresets.register(),v1.9.2 起),不需要任何手动操作,安装清单里也不再声明宿主包。缺失就按包内模板建好,已有文件永不覆写(你手改过的预设原样保留)。无论走哪条路径,没有这个预设心跳 agent 就是个"裸 agent",连 web_search 都看不见——想手动检查/修复用 preset status / preset install(见下节);把插件 config 的 installPreset 设为 false 可同时关掉运行时注册与目录自装,预设完全由你管。

从源码安装(开发/改造用)

dsh plugin --profile web add file:D:/path/to/dsh-heartbeat

数据放在哪

数据默认住在包外:/heartbeat-data(没有 DSH_HOME 就是 ~/.dsh/heartbeat-data),重装与升级都不会碰它。老版本装在包目录里的 data/ 会在首次启动时自动搬过去(搬迁前先备份、逐文件校验通过才删原件,见下节「卸载」)。要换位置就用插件 config 的 dataDir,或环境变量 HEARTBEAT_DATA_DIR。

核心工作机制

一跳 = agent 自己醒一次(默认 60 分钟)。醒着的时候依次走七相,最后由留痕收尾:

维护 → 采集 → 闲逛 → 闸门 → Digest → 反刍备料 → 投递 →  留痕
                        │
                   判「别说」→ 本跳到此为止,决策与表达不再调模型

点此展开:七相详情与关键概念

①  维护 ── 清素材池 / 滚动日志 / 判断该不该合并画像
②  采集 ── 全屏截图(加密落盘)+ 忙闲判定 + 前台窗口类别
           ╰─ 观察:把绑定会话里你新说的话收进画像收件箱
②′ 闲逛 ── 条件触发:agent 自己按兴趣焦点用 web_search 看新东西
③  闸门 ── 纯代码判定:静默窗 / 忙时 / 在场 / 每日上限 / 冷却
           ╰─ 判「别说」→ 本跳到此为止,决策与表达不再调模型
④  Digest ── 拼出「此刻状态」:画像 + 时间 + 素材池 + 待办
⑤  反刍 ── 引擎室从素材池挑 ≤3 条,各压成一句话(备料)
⑥  投递 ── 拼成素材包,送进你指定投递的那个会话
⑦  留痕 ── 写审计日志 + 账本(真正开口了才计数)
  │
  ▼
你读的那个会话 ── 那里的 agent 按当下处境,决定说不说、说哪条

文档里反复出现几个词,在这里一次说清:

词 · 意思 心跳 · 本插件的核心动作——不用你开口,agent 按固定节律自己「醒一次」:做维护、感知环境、决定要不要说话。醒一次叫一跳,默认 60 分钟一跳。 宿主 · 运行插件的那个程序,即 DSH 本体。心跳是挂在宿主里的插件——模型通道、会话、工具这些能力都由宿主提供。 客户端 · 宿主里负责界面的那一侧(Web 界面或者 DSH desktop)。设置页的心跳卡片属于客户端;卡片显示不出来,通常是客户端插件没加载成功,与心跳本体无关。 相 · 一跳内部的一个阶段。主循环共七相——维护 → 采集 → 闲逛 → 闸门 → Digest → 反刍备料 → 投递,最后统一由留痕收尾。每相结束都会在审计日志留一条 phase_done,所以「这一跳停在哪」可以直接查。 引擎室 · 跑心跳内部轮次的那个 agent,和你在会话里对话的 agent 是分开的。它只负责采集、反刍、备料,不直接跟你说话;真正开口的是你读的那个会话里的 agent。 心跳正身 · 心跳自己专用的一个会话,同时也是它的决策现场——每跳的推理轮次都在这里发生。它在会话列表里和普通会话长得一样,日常不用去动它(CLI 的 sessions list 会把它单独标出来)。 闸门 · 决定「这一跳能不能开口」的纯代码判定层,依次看:静默时段 → 你是不是在忙 → 你在不在场 → 今天说够没有 → 距上次开口够久没。全不通过就安静,并在日志里写下具体原因。它也是省 token 的关键——判「别说」时,之后的决策与表达两相根本不调用模型(已经跑过的维护、采集、闲逛不再重来,也不因为沉默而多花)。 观察 · 投递的反向动作——把绑定的会话里你新说的话收进画像收件箱,作为了解你的证据。它发生在采集相:只取当时有活 agent 的绑定会话、每跳最多 10 条、每条只留第一句(≤80 字),插件自己注入的消息会被跳过。 反刍 · 投递之前的备料步骤:引擎室从素材池挑出最值得说的几条,各压缩成一句话(不带理由、不排序)。名字取自反刍动物把食物嚼细再咽。 投递 · 把备好的素材包送进你某个会话的动作。把心跳绑定到常用会话,agent 就会「到你那个房间里说话」。

核心功能

心跳节律与分寸闸门

  • 心跳节律:定时唤醒(默认 60 分钟一跳,卡片可调),按七相循环运行——维护 → 采集 → 闲逛 → 闸门 → Digest → 反刍备料 → 投递,末了由留痕收尾。每跳都有审计留痕,沉默必带原因。
  • 分寸闸门:静默时段、忙时窗口、每日表达上限、开口冷却、在场联动,全部是代码层的独立判定,不靠模型自觉。默认倾向开口,但你正忙或已到深夜时绝不打扰。
  • 状态栏与时间感知:心跳把"此刻在干什么"(在闲逛 / 看到你在忙 / 在场待着…)注入日常会话——支持动态系统提示词的模型常驻系统提示词(KV-cache 安全追加),其余模型只在用户发起轮次时带一行。精确时间按 20–30 分钟节流注入,任务进行中绝不中途插话。

视觉与兴趣闲逛

  • 视觉感知(可选):每跳对全屏截图做一次视觉识别(如果模型不支持多模态,支持经 ModLens 此类视觉辅助插件外接多模态模型),投递的素材包会带一句「(他此刻大概在:…)」;识别失败时画面与窗口标题一概不进任何提示词——隐私优先,宁可不说。
  • 兴趣闲逛:按你定义的兴趣范围轮换挑焦点(同一条 3 天冷却),用 web_search 看新东西(每次 3~9 轮搜索),结果由代码登记入素材池(每焦点至多 2 条,config/interests.json 的 _schedule 可调)——模型只负责搜索筛选,不做任何写盘动作。话题库存见底(≤4 条)时自动触发补货闲逛(每天至多 2 次)。

素材池与投递闭环

  • 素材池(话题 / 聊天双仓):话题库存 16 条 + 聊天素材 14 条,四条确定性淘汰(TTL / 消费退休 / 冷板凳 / 容量挤出);聊天种子来自画像合并时从对话里挑出的"值得聊的话题",有时效性——被说出口后至少活到下一次回收,有新证据还会继续留池(v1.9.1 之前是"投递过 1 次即退休",常常话刚出口上下文就断了)。归档区也有上限(默认 50 条),超出按最老优先裁掉;新增 / 合并 / 淘汰 / 裁剪 / 恢复 / 删除都会写进审计日志(只记编号与元数据,不记素材正文)。是缓存不是记忆,与画像单向隔离。
  • 反刍投递(目标会话拍板):代码先凑好候选(话题随机 4 + 聊天最新 2,互补至多 6 条),引擎室挑 ≤3 条各压缩成一句,拼成素材包注入你读的会话——附一句「他此刻大概在:…」(视觉识别成功时)+声明「这是心跳插件素材投递」+素材清单(必要时附「也可以说一句真心话」)。说不说、说哪条,由目标会话里的 agent 按当下处境自己判断——决定不说就把正文留空(v1.9.3 起,但是受模型指令遵循能力限制,如想要更好的效果,建议在系统提示词/长期记忆中补充一条相应规则);话落到你眼前的会话后,agent 会按本次投递编号报账——哪几条被用上、是引用素材还是顺着自己发挥,都如实记下。
  • 心事匣(v2.0.0 新增):给心跳一格便签,用来把没说完的话留给下一跳的自己。投递的素材包里会带上「你上跳留下的心事:…」,以及它留于第几跳、已搁多久、这期间被叫醒过几次;想留住就照原样再写一遍(字样一致算保留,年龄不重算),想换就直接写新的,什么都不做它下一跳自动清掉。不强制每跳留话——没话说就空着。生命周期由两个序号判定,只认真正的拍(启动那一拍不计入),所以「搁了几跳」永远是真的。
  • 摘抄本(v2.0.0 新增):心跳自己的本子,用来留句子和想记住的小事。注册成模型工具 excerpt(add / list / remove),日常会话里的 agent 想到什么就当场抄下,不用谁下命令;数据落 data/excerpts.md,明文、可直接手编——一本谁也翻不开的笔记本不叫笔记本,认不出的行在改写时会原样留着。它和另两本分工明确:账本记待办(会勾掉),心事匣是留给下一跳的一句引子(一格、会被盖掉),摘抄本只增不减,除非主动抹掉。
  • 会话绑定:把心跳消息投递到你常用的会话(agent 会"到你房间里说话"),或观察会话内容喂养画像——投递/观察是两个独立开关,可双开。

记忆 · 账本 · 周报

  • 用户画像:本地结构化档案(兴趣 / 项目 / 沟通偏好 / 心理基线),带来源与置信度,稳定特质不因时间遗忘;journal 单一权威,可校验、可重建、可解密导出。
  • 周报:每 7 天一份,只报道这周干了些什么——表达与静默、新认识、账本、素材池、活跃高峰。由后台「心跳」署名写成平实中性的一句话档案,加密落盘,卡片可翻,默认只留最近 3 期(policy.weekly.keepReports)。
  • 账本工具:账本注册成模型工具,日常会话里的 agent 听到你提到待办/承诺会自己记账、完成后自己勾掉,不用你下命令——和心跳、CLI 记的是同一本账。
  • journal 快照基点:画像 journal 超 5000 条自动折叠成快照 + 归档分片,重放成本有界;verify/rebuild 跨快照依然正确。

数据 · 迁移 · 焚毁

  • 换机迁移:一键打包画像/账本/素材池/周报为口令加密容器(卡片或 CLI),新机器导入自动用本机主密钥重加密。
  • 加密与焚毁:敏感文件 AES-256-GCM 整文件加密,数据密钥由 Windows DPAPI(CurrentUser) 保管在 data/vault.key,只在进程启动解一次;旧版(1.x)留下的 DPAPI 容器照样能读,且在写入与每跳维护时自动改写成新格式(vault upgrade 一次全换);一键焚毁运行时数据;模型出库仅限合并裁决的最小必要摘要。

常见故障与诊断

第一现场永远是 data/logs/heartbeat.jsonl(每跳留痕,silent 必带原因)。

点此展开:高频报错与排错速查

症状 · 原因与处理 完全没有心跳(无任何日志行) · 插件没装入:确认 node_modules 里插件存在、启动无 "Failed to load plugins" 横幅;plugin_init 缺失 = apply 没跑 一直沉默 · 先看 silent 行的 reason:夜间静默窗 = 正常;白天 = cap 满 / 冷却未过 / 忙时窗口 / token-saver(见下条) 审计出现 silent reason=token-saver、心跳整跳不动 · 节省 token 模式开着,且你已离开(闲置 ≥30 分钟)或锁屏——这是设计行为,不是坏了:暂停期间每 3 分钟只探一次环境(不花 token),你一回来就会恢复;绑定会话里出现新消息也算你在。不想要就关掉那个开关 psy 分区一直空、画像只在其他分区增长 · psy 开关默认关闭:开着时画像合并才收 psy 条目。在设置卡里打开即可 闲逛永远秒结束、tool_policy 报 unknown global tool "web_search" · 预设没挂上(裸 agent):preset status → preset install,装好后 tool_policy 行应是 preset=mounted(heartbeat) restrict=ok 设置页整块没有心跳卡片(数据照常写) · client 注册 id 与包名不一致被宿主静默剔除:三处必须严格等于包名,改完重启。若确认 id 没问题,看下一条 卡片整块消失 / 节律配置保存不了(0.1.7 宿主) · 旧版插件撞上 0.1.7 的接口换代(设置接口变更 + 客户端服务被删):升级到 v1.7.0 并重启;v1.7.0 已按三代接口自动适配 卡片分区报 加载失败: … HTTP 405 · RPC 路由没注册成功:审计里应出现 rpc_registered route=/api/heartbeat,没有 = dist 未同步,重装/同步后重启 节律配置保存不生效、重启后回默认(0.1.5 宿主) · v1.5.x 的已知问题(dsh-settings 包缺失 + 0.1.5 API 变更):升级到 v1.6.0 并重启;0.1.7 宿主的同类症状见上面「卡片整块消失」那条 投递没带「他此刻大概在:…」、审计有 screen_vision ok:false · 视觉识别失败:error 字段带 ModLens 具体报错;常见为 provider 未配置或网络超时。识别失败时画面/标题按隐私设计不进提示词,心跳其余功能不受影响 结果显示「心跳异常(decision: whenIdle timeout)」 · 反刍轮超时(240s 内没等到模型回话)。v1.6.0 起不再整跳报错:记 decision_deferred、本跳按沉默处理、素材自动留到下一跳。若反复出现,看该行 reason 与 ModLens 画面描述是否诱发跑题 每跳 beat_error: … reading 'length' · 宿主移除了 Session.events——插件版本与宿主不匹配,对照〈版本兼容〉换版本 引擎室轮次整轮失败、报 format v4 message requires a producer-owned source kind · 0.1.7 的会话日志(V4)拒绝旧版通用的消息来源标记——同样是版本不匹配:升级到 v1.7.0(改用自有来源标记) 每轮报 prompt variable "{{model}}" has no value · agent 没有模型路由(审计 model 字段为 (none))——同样是版本不匹配症状 素材投递偶尔不成功、spoke_failed: non-Chinese output discarded · 目标会话 agent 收到素材包后回合以工具调用收尾,末行是 `(纯英文)被旧判定误拦。v1.5 起已修:跳过工具收尾标签、取最后一个含中文的行;整段无中文才拒。升级后重启即可 有 spoke 但会话里没出现这句话 · 投递目标当时没活 agent 且拉不起来:查 deliver_target_* 系列行;再查绑定 deliver 是否为 true 素材包发了但目标没说话,想知道为什么 · 查 expression_dropped(v1.9.1 起记录,带丢弃原因);连续三次会在日志里补一条 expression_dropped_streak。v1.9.3 起「决定不说」是正常路径,不再算异常 日志出现 cursor_format_discarded / rpc_host_gate_missing / beat_watchdog / weekly_pruned · 都是 v1.9.1 起记录的**正常自愈痕迹**(weekly_pruned 为 v1.9.3 新增):分别为「旧游标格式升级丢弃、本跳全量重扫」「宿主未提供 RPC 闸门、危险端点已拒绝」「某跳超时被强制收尾」「周报超期被裁」。各出现一次不必管,反复出现再看同跳前后的其他行 **侧栏某个会话行消失了** · 心跳刚往那个"当时没打开"的会话投递过,投完释放临时 agent 的正常副作用——**刷新页面即回**,内容零损失 升级 0.1.5 后旧会话打不开(unexpected member … / header version must be 3) · 会话格式 v3 迁移问题:前者用 scripts/repair-v0-members.mjs(预检→修复,自动备份);后者首次访问会自动迁移,属正常 升级 0.1.7 后会话目录里多出 .v4 文件 · 会话格式 V4 迁移的**正常**结果:首次访问该会话时转换,原 .v3 文件保留不删。注意这是**单向**的,降级回旧宿主可能读不了——升级前备份 ~/.dsh/sessions 画像疑似损坏 · profile verify(只报不修)→ profile rebuild --check(看 diff)→ profile rebuild`(真重建)

完整事件字典、宿主契约备忘与更多症状见 DESIGN.md §7。

CLI 命令

设置页卡片覆盖日常操作;CLI 面向高级用法与脚本场景:

node <插件目录>/dist/cli/index.js <命令>

点此展开:CLI 命令速查

分组 · 命令 · 说明 总览 · status · 工作区路径 + 策略摘要(今日 cap / 冷却 / 静默窗) 素材池 · seeds add [--tag t] [--topic x] [--confidence n] · 手写一条种子 · seeds list [--archived] / seeds surface / seeds archive · 列表 / 计一次曝光 / 归档 · seeds gc / seeds stats · 跑确定性淘汰 / 池子状态 JSON 账本 · ledger add / ledger list [--pending] / ledger done / ledger open · 待办登记 / 查询 / 勾掉 / 编辑器打开 摘抄本 · excerpt add / excerpt list [n] / excerpt remove / excerpt open · 抄一条 / 翻最近十条(可指定条数)/ 抹掉一条 / 编辑器打开 闲逛 · browse status / browse dry / browse done · 状态 / 强制裁决预演 / 手动登记一次闲逛 绑定 · sessions list · 枚举会话 id · bind list / bind add [--observe] / bind remove · 绑定详情(正身也会列出)/ 绑定 / 解绑;--observe-only 仅观察、--no-deliver 关投递 通知 · notify check / notify register / notify send · toast 通道体检 / 注册 / 测试发送(只提示新消息,不承载正文) 画像 · profile list [--all] / profile export · 当前有效(含过期)/ 解密导出 Markdown · profile verify / profile rebuild [--check] / profile wipe · journal 重放比对(只报不修)/ 重建(可先干跑)/ 清空(要 --yes;连快照、归档分片、迁移备份一起删,设定不动) · profile snapshot [--force] · 折叠 journal 为快照 + 归档分片(维护相到阈值也会自动做) 周报 · weekly list / weekly show [file] · 列出已生成的周报 / 打印某期(默认最新一期) 迁移 · migrate export [file] / migrate import · 打包记忆文件为口令加密容器(口令走 stdin 两行)/ 在新机器恢复(stdin 一行);卡片「换机迁移」分区同功能 加密 · vault status / vault upgrade · 盘上各格式容器计数 + 主密钥位置 / 把 1.x 的 DPAPI 容器就地改写成 AES-GCM(平时写入 / 每跳维护自动换代,这条是一次全换) 日志 · logs cleanup [--dry-run] · 立即执行日志保留策略 预设 · preset status / preset install [--force] · 装没装、与模板是否一致 / 补装(--force 还原成模板) 焚毁 · burn [--yes] [--all] · 预演(默认)→ 执行;运行时数据覆写 x3 后删除,设置保留(--all 连设置归零)

数据与安全

信息存储

所有运行数据都在心跳数据目录(唯一可写位置,路径守卫强制),卸载或重装都不会丢:

文件 · 内容 · 状态 data/settings/ · 绑定、策略覆盖、节律配置(ui.json)、画像白名单、心跳状态(场景 + ≤30 字发言摘要) · 明文(用户设定要可手编) data/vault.key · 主密钥(AES 数据密钥,由 DPAPI 保护) · 🔒 本机本账户可解;不随迁移包移动 data/seeds.jsonl · 素材池 · 🔒 加密 data/profile.* · 画像三件套(journal / 物化视图 / 收件箱) · 🔒 加密 data/sent.json / data/browse.json / data/screen.* · 表达记录 / 浏览流状态 / 屏幕快照 · 🔒 加密 data/notepad.json · 心事匣:上一拍留给下一拍的一句引子 + 两个序号计数 · 🔒 加密 data/ledger.md · 账本(agent 的待办与话题来源,可直接手编) · 明文 data/excerpts.md · 摘抄本(留句子和小事,可直接手编) · 明文 | data/profile_snapshot.json / data/profile_journal.archive-*.jsonl