用 Markdown 定义伙伴人格,自动写日记并更新长期记忆
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:npm 同名包「dsh-companion」归属 gjnzsu/dsh-companion,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add s867968286/dsh-companion该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · skill
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 35 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意npm 同名包「dsh-companion」归属 gjnzsu/dsh-companion,装到的可能不是本插件
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-companion @ 0.1.1
✓Node 引擎要求 >=22.5 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/8 08:44:01
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 57 处,展示前 32 条)
- 读取本地文件src/index.js:189
if (!existsSync(file)) { - 读取本地文件src/index.js:214
if (!existsSync(legacy)) return undefined - 读取本地文件src/index.js:292
if (existsSync(target) || !existsSync(legacy)) return { migrated: false } - 读取本地文件src/index.js:326
if (!existsSync(paths.companionsRoot)) return 0 - 读取本地文件src/index.js:328
for (const entry of readdirSync(paths.companionsRoot, { withFileTypes: true })) { - 读取本地文件src/index.js:338
if (!existsSync(paths.companionsRoot)) return [] - 写入本地文件src/index.js:447
mkdirSync(dir, { recursive: true }) - 写入本地文件src/index.js:454
mkdirSync(join(dir, 'memory'), { recursive: true }) - 写入本地文件src/index.js:480
mkdirSync(dir, { recursive: true }) - 写入本地文件src/index.js:503
mkdirSync(join(dir, 'memory'), { recursive: true }) - 写入本地文件src/index.js:525
mkdirSync(dirname(to), { recursive: true }) - 写入本地文件src/index.js:527
renameSync(from, to) - 删除本地文件递归src/index.js:531
rmSync(from, { recursive: true, force: true }) - 删除本地文件递归src/index.js:577
rmSync(dir, { recursive: true, force: true }) - 写入本地文件src/preset.js:106
mkdirSync(dirname(file), { recursive: true }) - 读取本地文件src/preset.js:108
if (statSync(file).size > LOG_MAX_BYTES) { - 读取本地文件src/preset.js:109
const prev = readFileSync(file, 'utf8') - 写入本地文件src/preset.js:110
writeFileSync(file, prev.slice(Math.floor(prev.length / 2)), 'utf8') - 写入本地文件src/preset.js:118
appendFileSync(file, `${localTimestamp()} [${level}] ${line}\n`, 'utf8') - 读取本地文件src/preset.js:250
return existsSync(dir) ? dir : '' - 读取本地文件src/core.js:204
body = readFileSync(filePath, 'utf8') - 读取本地文件src/core.js:509
return { file, filePath, exists: filePath ? existsSync(filePath) : false } - 发起网络请求client/client.js:346
const response = await fetch(`${API}${path}`, options) - 写入本地文件src/memory-store.mjs:36
mkdirSync(dirname(file), { recursive: true }) - 写入本地文件src/memory-store.mjs:38
writeFileSync(tmp, text, 'utf8') - 写入本地文件src/memory-store.mjs:40
renameSync(tmp, file) - 删除本地文件src/memory-store.mjs:43
rmSync(tmp, { force: true }) - 读取本地文件src/memory-store.mjs:54
return readFileSync(file, 'utf8') - 读取本地文件src/memory-store.mjs:111
names = readdirSync(memoryDir) - 写入本地文件src/settings.mjs:120
mkdirSync(dirname(paths.settingsFile), { recursive: true }) - 写入本地文件src/settings.mjs:166
mkdirSync(dirname(paths.bindingsFile), { recursive: true }) - 读取本地文件src/templates.mjs:25
return readFileSync(join(TEMPLATE_DIR, `${name}.tpl`), 'utf8')
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-session-format-v3-to-v4给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- Markdown定义人格
- 自动写日记
- 自动更新长期记忆
给 DSH 助手赋予人格、灵魂与长期记忆:用 Markdown 定义伙伴的身份、性格、准则与记忆,自动写日记、自动更新记忆。
README
由 DeepSeek 最新模型翻译生成dsh-preset-md
给 DSH 助手赋予人格、灵魂与长期记忆——用 Markdown 定义伙伴的身份、性格、准则与记忆,自动写日记、自动更新记忆,并在官方设置页里可视化管理。
Give your DSH assistant a soul, personality, and long-term memory — define a companion's identity, character, and memory in Markdown, with automatic journals and memory updates.
本项目由 AI 生成:代码与文档均由 AI 编码代理产出并迭代,人类负责需求、设计与实机验证。
伙伴是插件自己管理的数据,不依赖官方的 agent preset 机制。
每个伙伴 = 一个目录,里面是几个约定好的 Markdown 文件;选中的伙伴会拼成该会话唯一的系统提示词,同时在后台按天写日志、按条目更新记忆文件。
为什么要脱离官方 preset:dsh 0.1.7-rc.2 起预设只能由已安装的 bundle 声明(.agent-presets// 目录格式官方已完全不再读取),而"装一个 bundle"意味着新建伙伴要跑 pnpm 并重启 dsh。本插件选择保持"即插即用":新建伙伴只是写几个文件,刷新页面就能选。
展开完整文档(README 剩余 1 节)
dsh-preset-md
给 DSH 助手赋予人格、灵魂与长期记忆——用 Markdown 定义伙伴的身份、性格、准则与记忆,自动写日记、自动更新记忆,并在官方设置页里可视化管理。
Give your DSH assistant a soul, personality, and long-term memory — define a companion's identity, character, and memory in Markdown, with automatic journals and memory updates.
本项目由 AI 生成:代码与文档均由 AI 编码代理产出并迭代,人类负责需求、设计与实机验证。
伙伴是插件自己管理的数据,不依赖官方的 agent preset 机制。
每个伙伴 = 一个目录,里面是几个约定好的 Markdown 文件;选中的伙伴会拼成该会话唯一的系统提示词,同时在后台按天写日志、按条目更新记忆文件。
为什么要脱离官方 preset:dsh 0.1.7-rc.2 起预设只能由已安装的 bundle 声明(.agent-presets// 目录格式官方已完全不再读取),而"装一个 bundle"意味着新建伙伴要跑 pnpm 并重启 dsh。本插件选择保持"即插即用":新建伙伴只是写几个文件,刷新页面就能选。代价是伙伴不会出现在官方的预设选择器里,选伙伴在对话输入框的工具栏。
提示词按会话冻结:改文件后新开一个对话即可生效,运行中的会话不受影响。
怎么用
| 动作 | 在哪 |
| 选伙伴 | 对话输入框工具栏左侧的下拉(新建对话时可选) |
| 改伙伴 | 设置 → 伙伴设置 |
| 不用伙伴 | 下拉里选「无伙伴(用官方提示词)」 |
三条行为规则:
1. 开对话前可选:会话还没开始(blank)时,下拉可切换
2. 开对话后锁定:首轮发出后绑定不可改,只显示当前伙伴;要换伙伴就新开一个对话
3. 选「无伙伴」= 官方提示词原样生效:此时插件完全不注册任何提示词段,官方预设(standard 等)完全接管
预览
| 伙伴列表 | 参数设置 | 提示词编辑 |
| 伙伴列表 | 参数设置 | 提示词编辑 |
文件约定
/preset-md/companions//
├── preset.yml ← 昵称与个性签名 ├── SYSTEM.md ┐ ├── SOUL.md │ ├── IDENTITY.md ├─ 按此顺序拼成唯一系统提示词 ├── USER.md │ ├── AGENTS.md │ ├── MEMORY.md ┘ ├── memory/ ← 按天日志(YYYY-MM-DD.md) └── changelog/ ← 记忆文件的改动留痕
从旧版本升级:伙伴原先在 /.agent-presets//,用
node scripts/migrate-presets.mjs --apply 搬迁(只移动、不改内容)。
迁移前建议先整份备份。
| 文件 | 用途 | 后台回顾可改 |
| SYSTEM.md | 系统级指令 | ❌ |
| SOUL.md | 人格 | ✅ |
| IDENTITY.md | 自我认知 | ✅ |
| USER.md | 用户上下文 | ✅ |
| AGENTS.md | 工作方式 | ❌ |
| MEMORY.md | 持久记忆 | ✅ |
文件不存在或内容为空 → 该段跳过,不会留下空标题。
标题由文件自己写,插件不额外加:最终提示词就是各文件正文按顺序用空行连接。
占位符
正文里可以写下面四个占位符,在会话冻结时替换一次(同一会话内恒定):
| 占位符 | 替换为 |
| {{cwd}} | 当前会话的工作目录 |
| {{preset}} | 当前 preset id(如 agent-1bd5) |
| {{presetDir}} | 预设目录的绝对路径(六个 MD 与 memory/ 所在目录) |
| {{session}} | 当前会话 id |
其余 {{…}} 原样保留,便于看出没生效。取不到值(例如会话没有 cwd)时同样原样保留。
安装
尚未发布到 npm,请从 GitHub 安装:
装进某个 profile(推荐:可用完整的「伙伴设置」页面)
dsh plugin --profile add github:s867968286/dsh-preset-md
装完重启 dsh:bundle 不热重载,已挂载的组合不会热替换模块。
本地开发时改用 link:
dsh plugin --profile add link:/绝对路径/dsh-preset-md
也可以不安装,直接在 preset 里用绝对路径引用 preset 行入口,此时只有提示词注入与自动记忆,没有设置页。
在目标 preset 的 agent.cordis.yml 里加一行:
- id: preset-md
name: dsh-preset-md/preset
注意(0.1.7-rc.2 起):这条路只在"伙伴即 preset 目录"的老用法下有意义。
正常的伙伴选择走下拉,伙伴数据在 /preset-md/companions/,与 preset 组合无关。上面这一行是回落路径:取不到会话绑定、也没有下拉可用时,插件才回落到 ctx.baseUrl(即 agent.cordis.yml 所在目录)读 MD。
两者都取不到时注入为空并打一条 warn。
人格类预设只需基础工具。 内置模板(templates/agent.cordis.yml.tpl)给的是一套精简清单:shell / 文件系统 / 技能 / ask-user / todo / web / present,不含官方 standard 里那套编码 agent 的重型机械(plan mode、compaction、委派与工作流、goal、jobs)。理由:陪伴场景不需要工程流程,这些行会把工具目录撑大、并诱导模型走「先规划再实现」的套路;另外模板不挂官方 persona 行——它的 You are a coding agent ... 会盖掉你的人设。
想拿它当编码 agent 用时,从官方 standard preset 拷回所需的行即可。
本插件不带构建步骤(无 prepare 脚本),从 GitHub 装不需要 allowBuilds 放行。
若日后加了构建脚本,pnpm 会拦截它并打印所需 key,按提示加进 profile 目录的 pnpm-workspace.yaml 的 allowBuilds 再重跑即可。
收窄工具
agent 能看到的工具 = 全局层(profile 里装的插件)+ preset 层(agent.cordis.yml 挂的行)+ agent 层。
「preset 没挂某个插件」并不会让它的工具消失,要收窄得显式声明:
- id: preset-md
name: dsh-preset-md/preset
config:
tools:
deny:
- 'mnemon' # 前缀
- '_recall' # 后缀
- 'mcp' # 包含
- 'read_page' # 精确
allow: ['read_page', 'x_search'] # 白名单:只保留这些全局工具
只支持上面四种写法,中间通配(如 ab)一律不命中。
deny 是黑名单,allow 是白名单(两者同时给时都生效)。
插件会先把写法展开成精确的工具名再下发,因此没命中任何工具的条目只会打一条 warn,不会让插件加载失败——升级第三方插件后名单失效时你能从日志里看到。
自动记忆
后台异步执行,不阻塞对话,也不需要子代理。
触发时机
| 时机 | 条件 |
| 会话结束 | 必触发(绕过防抖;若正好有回顾在跑,排队等它结束后补跑) |
| 上下文压缩 | 压缩开始(compaction/start)时必触发——压缩会把老对话摘要掉,没归档的段落压缩后就再没机会总结 |
| 回合结束 | 满足其一即触发:未总结轮数 ≥ reviewTurns 或 新增字符数 ≥ reviewChars |
| 防抖 | 5 秒内不重复触发(只作用于「回合结束」这一路) |
| 超时 | 单次回顾最长 2 分钟,超时中止并复位状态 |
失败会重试:水位(已总结到哪)只在成功后才推进。调用失败或输出解析失败时,那一段内容的水位不推进,下一轮自然带上重试——否则失败那轮的内容滚出转写窗口后就静默丢了。
连续失败到 MAX_REVIEW_ATTEMPTS(3 次)则放弃这一段强制推进,避免一段坏内容把水位永久卡死。
只统计真人发言:user/message 这个事件类型不区分来源(真人发言、官方运行时快照、其他插件的注入消息都落成它),所以触发阈值只计 source.kind === 'user' 的发言与助手回复。
不过滤的话注入文本会撑大「新增字符数」,让回顾在真人几乎没说话时就被触发。
默认阈值 reviewTurns = 3、reviewChars = 2000:一次有实质内容的往来通常 2~3 轮就够, 2000 字符约等于一次中等长度的往返。阈值设得太大(旧默认是 10 轮 / 8000 字符)会让短会话几乎不可能在回合中触发,只能靠「会话结束」兜底,体感就是「根本不触发」。
阈值设置(reviewTurns / reviewChars)会在读写时做校验:非正数、空值或类型不符一律回落到默认值。
这一点很重要——阈值退化成 0 会让「未达阈值才跳过」的判断恒不成立,变成每个回合都跑一次 LLM 回顾。
转写窗口跟随 reviewChars:阈值调大后回顾间隔变长,窗口同比例放大,两次回顾之间的内容不会被尾部截断丢掉;阈值调小时窗口有下限,不会缩到把正常对话截成「太短」。
真的超窗时保留尾部(本轮结论比开头更值得总结),并在开头加一行 …(前文略) 标记 —— 不静默截断。
只统计本会话自己的事件:子代理会话由 fork 派生,磁盘上带着父会话的完整历史。
用官方 ownEvents()("after its fork-inherited prefix")而非 snapshotEvents()(全量),否则继承前缀会在第一轮就把触发阈值灌满 —— 实测子会话转写有 90%~99% 是父会话内容。
用哪个模型:直接用当前会话正在跑的模型(取自会话日志最后一条 request/header 的 provider/model),而不是全局默认模型——否则会话换过模型后,回顾会跑到另一个模型上去。
只有在会话还没有任何请求头的极端情况下才回退到全局默认。
一次回顾做两件事(单次调用):
1. 当天日志:追加到 memory/YYYY-MM-DD.md。正文可写一行「> 摘要:…」(本段最核心的结论,不超过 50 字,会被检索索引直接展示),其余按需分「讨论与解决 / 关键信息 / 感悟」三段;
2. 记忆更新:只允许改 SOUL.md / IDENTITY.md / USER.md / MEMORY.md,操作 add / replace / remove。replace / remove 的目标文本必须逐字来自原文且唯一,否则该条被跳过——永远不整文件覆盖。单条失败不影响后续条目。
记什么、不记什么:摘要与那三段都允许为空——判据是「本轮有没有值得以后回看的新内容」,不是「把格式填满」。没有对应内容的段落整段省略,不要凑字数写套话。
| 要记 | 不记 |
| 新出现的偏好、决定、约定、事实 | 无意义寒暄(打招呼、道谢、应答) |
| 达成的结论、方案、取舍理由 | 一问一答即结束、没有结论的简单问题 |
| 排查出的根因、踩过的坑、验证方式 | 测试性对话(「测试」「试试」「1」) |
| 关系或情绪的转折 | 纯操作确认(「重启了」「改了」) |
| 项目与环境的稳定事实 | 今天日志或长期记忆里已经记过的内容 |
拿不准时用一条判断:这条信息在往后某天回看时,还能帮我理解他、或理解当时的决定吗?
能就写,不能就跳过。当天已经有日志,不代表这一轮就不用写——只是别把旧内容重复抄一遍。
失败要看得见:回顾在后台跑,日志只进 dsh 进程的 stdout,默认看不到。所以「触发条件已满足、但没能写入」时(拿不到模型、调用异常、输出解析失败、模型没产出日志段落),除了打 warn,还会往对话里注入一条 [preset-md] 提示,说明是「已触发但失败」并带上原因。
同一条会话的这类提示有 60 秒节流,不会刷屏;「对话太短」这类正常跳过只记日志、不打扰用户。
写回来的换行风格:MD 文件若是 CRLF(Windows 编辑器保存过),改动后仍保持 CRLF,不会因为一次自动记忆就把整个文件的换行符换掉。
留痕:每次改动前先写 changelog/.changelog.md,一条记录一块,按块滚动裁剪,不切断单条记录。
上下文预算
六个 MD 拼起来就是系统提示词,所以插件按整体管体积:
| 项 | 默认 | 说明 |
| 预算 | 20000 字符 ≈ 9400 token | 可在「伙伴设置 → 参数」改;折算按 DeepSeek 口径(1 汉字 ≈ 0.6 token) |
| 分配 | 按固定比例瓜分 | MEMORY 25% / AGENTS 22% / SOUL 20% / IDENTITY 13% / SYSTEM 12% / USER 8% |
| 超限提醒 | 开 | 超预算时追加一段「请收敛」提醒;不硬截断——截断会把记忆切碎,比超一点更糟 |
| 关掉提醒 | — | 只度量并打日志,不往提示词里加任何东西;预算仍然生效(日志照打) |
单个文件偏大但总量没超 → 不提示。只有整体越过预算线才提醒,并在提醒里点名偏重的文件,让模型自己在下次更新记忆时合并、精简、清理过期条目。
启动时会打一条 info 日志,形如:
[preset-md] 注入体积 6031 字符 ≈ 2866 token,预算 20000(占 30%)| SYSTEM 533(9%) SOUL 1583(26%) ...
预算只管六个 MD。三个 preset_md_ 工具 schema 另占约 700 token,不含在内。
记忆工具:注册三个 preset_md_ 前缀工具,覆盖「读日志 / 写日志 / 更新记忆」。
| 工具 | 用途 |
| preset_md_search | 只读:检索历史日志 |
| preset_md_journal | 写入:把一段正文追加进当天日志(自动补日期头与时间标题) |
| preset_md_memory | 写入:条目级更新 IDENTITY.md / SOUL.md / USER.md / MEMORY.md |
preset_md_search 参数:
| 参数 | 行为 |
| days | 最多回溯几个有内容的日志文件(不是自然日),默认 7 |
| query | 全文逐行匹配,返回 日期:行号 与上下文;不填则返回日志索引(每段时间标题 + 摘要行,超长截断补 …) |
preset_md_memory 参数:file(白名单枚举)、op(add / replace / remove)、content、old_text。
replace / remove 的 old_text 必须逐字来自原文且全文唯一,否则被拒绝并提示先读文件。
为什么不直接用 write / edit 直写文件:后台自动记忆走 memory-store 的按路径写队列(enqueue),直写不经过队列会与后台形成「读-改-写」竞态;而且直写绕过 changelog 留痕与 old_text 校验。这两个写入工具内部走 appendJournal / applyUpdate,三条保护都在。
伙伴设置
装进 profile 后,官方设置页里会多一项「伙伴设置」(复用官方 settings.section,不自建侧栏入口)。
设置 → 伙伴设置 ├── 伙伴 卡片列表:昵称 + 个性签名 + 查看 / 复制 / 删除 │ └── 查看 昵称与签名可编辑,另有 7 个页签 │ 提示词 / 个性 / 身份 / 用户 / 准则 / 记忆 / 日记 └── 参数 自动记忆开关与阈值、注入预算与超限提醒
| 行为 | 说明 |
| 编辑 Markdown | 每个文件一个页签,纯文本编辑(不引 Markdown 渲染库)。无改动时保存按钮禁用;切换页签前若有未保存改动会先确认 |
| 新建伙伴 | 用内置模板生成 6 个 Markdown + preset.yml + memory/(不生成 bundle 声明——所以无需装包、无需重启) |
| 复制伙伴 | 克隆内容与组合,不带历史日志 |
| 删除 | 只移动到备份目录,不真删;新会话选不到,旧对话仍可查看 |
| 参数 | 存 /preset-md/settings.json;改完点「保存」提交。自动记忆与阈值实时生效(下一个回合就按新值走,不必重启或重开会话) |
参数表单是攒草稿、点保存才提交(与 dsh-memory-md 一致):改到一半不会生效,有未保存改动时按钮上方会显示提示。数字项留空即用默认值(提交 null,由服务端归一化回落);0、负数、非数字同样回落默认,不会被夹成一个更小的值。
生效时机分两类:
| 设置 | 何时生效 | 为什么 |
| autoMemory、reviewTurns、reviewChars | 实时(下一个回合) | 后台回顾每次触发时直接读设置文件 |
| contextBudget、budgetNotice | 新开会话 | 它们影响注入文本,而注入文本按会话冻结(见下方「固定行为」) |
目录结构
├── src/index.js 主入口(Host 半):/preset-md/api/* 与文件读写 ├── src/preset.js preset 行(子路径 ./preset):提示词注入 + 自动记忆 ├── src/core.js 纯逻辑:目录解析、变量与 section 注册、会话冻结、工具收窄 ├── src/memory-store.mjs 日志追加 / 条目级更新 / changelog ├── src/review.mjs 回顾提示词 + 模型调用 + 结果解析 ├── src/search.mjs preset_md_search 工具 ├── src/tools.mjs preset_md_journal / preset_md_memory 工具 ├── src/settings.mjs 设置读写 ├── src/templates.mjs 模板装载 ├── templates/.tpl 新建伙伴时写入的内置模板 ├── client/client.js Client 半:注册「伙伴设置」页面 ├── cordis.patch.yml bundle 补丁 └── test/.test.mjs
开发 sh
npm install
npm test # node --test
npm run check # 语法检查
运行时依赖只有官方的 @deepseek-ai/dsh-llm(用于构造回顾消息与解析模型输出流),版本需与 dsh 运行时一致——预发布版本不受 ^ 范围匹配,请写精确版本。当前对齐 0.1.7-rc.2。
0.1.7-rc.2 的破坏性变更:会话格式升到 v4 后,Message.source 里 plugin 这个兜底 kind 被退役了(官方注释:there is no shared catch-all plugin kind)。
新事件若写 { kind: 'plugin', plugin: 'dsh-preset-md' },官方准入函数
assertV4MessageSources / assertV4RowAdmission 会硬抛 SessionFormatError: format v4 message requires a producer-owned source kind。
本插件改用生产者自有 kind plugin:dsh-preset-md(与官方迁移器给未知第三方生产者的命名一致)。旧会话里已落盘的 plugin 只在读历史时由迁移器改写,新写入不受这层照顾,所以必须改调用点。有两条回归测试直接用官方真包的准入函数锁住这一点。
固定行为(不可配)
这几项没有开关——只有一种模式是对的,留着开关只会让人以为另一种也可用:
| 行为 | 说明 |
| 独占系统提示词(选了伙伴时) | 系统提示词只保留该伙伴的 MD。官方那句身份声明与其他插件注册的提示词段都不再进入请求。同一 scope 里若另有 complete 段,组装会直接失败(官方限制:只能有一个) |
| 未选伙伴则不注册任何段 | 选「无伙伴」时插件一个 section 都不注册,官方提示词原样生效。⚠️ 注意这不是"注册一个空文本的 complete 段"——官方只判 complete === true 就把该段当作全部提示词(dsh-system-prompt/lib/index.js:345,359),空文本会把提示词清成 "",比不注册糟糕得多 |
| 注入按会话隔离 | section 注册在每个会话自己的 scope 里(agent/created 监听器的 this,官方契约标为 Scoped)。所以一个会话选伙伴不会影响别的会话 |
| 会话内冻结 | 同一会话只读一次文件,改 Markdown 要新开对话才生效。代价是改动不即时,收益是系统提示词逐字节稳定、KV 缓存前缀持续命中 |
| 按会话隔离缓存 | 缓存键取会话 id;取不到时用 cwd 兜底,避免不同工作区的 {{cwd}} 串味 |
设计取舍:为什么伙伴不是"官方预设"
| | 做成官方预设 | 现在的做法 |
| 新建伙伴 | 生成 bundle → 装进 profile → 重启 dsh | 写几个文件,即插即用 |
| 出现在官方预设选择器 | ✅ | ❌(在对话工具栏选) |
| 会话级绑定 | 靠官方 agentPreset | 写会话事件 preset-md/companion-selected |
| 独占提示词 | ✅ complete | ✅ complete(同) |
| 每个伙伴独立人设/记忆 | ✅ | ✅ |
根因:rc2 起官方预设只能由已安装的 bundle 声明(agentPresets 的注册表只接受 @deepseek-ai/dsh-agent-preset 的声明,声明位置是 bundle 的 presets/.patch.yml)。
"新建伙伴 = 装一个包 + 重启" 与"即插即用"在 rc2 下互斥,二选一。
本插件选了后者,因为「每个伙伴独立人设 + 完全自定义提示词 + 完全自定义记忆」这三条都不依赖 preset 机制 —— complete: true 只是 systemPrompt.section() 的一个字段,任何已安装插件都能用。被放弃的只有"出现在官方预设选择器里"这一点。
注意事项
| 事项 | 说明 |
| 改插件代码要重启 dsh | 已挂载的组合不会热替换模块 |
| 伙伴增删不用重启 | 伙伴是插件自己的数据;新建/删除后刷新页面即可在下拉里看到 |
| 官方 context 不受影响 | 独占只替换 section;沙箱策略、审批策略等运行期快照照常注入 |
| preset.yml 只动三个键 | 昵称/签名写入时只替换 name / description / order 三行,注释与其余字段原样保留(官方 dsh-agent-presets 也读这个文件)。昵称不写进 agent.cordis.yml——那里只是插件行清单 |
| 设置页写入带冲突检测 | 保存 Markdown 时回传载入时的版本指纹;若后台自动记忆期间改过同一文件,服务端回 409 并提示重新载入,不会静默覆盖那条记忆 |
| 本机 HTTP 接口有来源校验 | /preset-md/api/* 的写请求(POST/PUT/DELETE)校验 Sec-Fetch-Site 与 Origin,跨站一律 403;非浏览器客户端(curl 等)不受影响 |
| 昵称 / 签名有长度上限 | 昵称 ≤ 60 字符、签名 ≤ 200 字符,超限报 400 |
关键词
dsh · deepseek-harness · persona · soul · memory · companion · ai-assistant ·
agent-preset · markdown · system-prompt
人格 · 灵魂 · 记忆 · 助手 · 伙伴 · 预设 · 提示词
致谢与借鉴
本项目参考了以下两个开源项目,仅借鉴设计思路与文件约定,代码为独立实现:
| 项目 | 地址 | 借鉴点 |
| dsh-claw-suite | https://github.com/xingyingyuzhui/dsh-claw-suite | 用约定的 Markdown(SOUL / IDENTITY / AGENTS)承载人设并注入系统提示词,USER / MEMORY + memory/YYYY-MM-DD.md 日记另行注入与回合后回顾;在设置页里按页签读写这些文件的交互思路 |
| DeepSeek-Harness-Hanako-Memory | https://github.com/moononnn/DeepSeek-Harness-Hanako-Memory | 卡片式伙伴管理界面与预设增删改的交互思路(本项目按官方 UI 规范重写,未照搬其界面代码) |
也感谢官方 @deepseek-ai/dsh 提供的 agent-presets / settings / home-paths 机制。
关于 AI 生成:本项目的代码、文档与界面实现均由 AI 编码代理生成并多轮迭代,人类负责需求定义、架构决策与实机验证。使用前请自行审阅,生产环境请谨慎评估。
许可
MIT预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
s867968286/dsh-companion
用 Markdown 定义伙伴人格,自动写日记并更新长期记忆
相关插件 · 技能 / 提示词
人设统管ZiChuanLan/agent-purge
一份系统提示词,喂给多个 coding…
★ 931已汉化DSH
73.8
人物画像蒸馏titanwings/distilly
Distilly — 把他们的思考方式提炼成可复用的技能,供任何智能体或机器人使用。原名 Colleague Skill(原同事 Skill)。
★ 25,659已汉化DSH
71.3
推理工作空间套件Tiger3807861189/J-Space-Cognition-Suite
J-Space 是面向复杂推理、大型仓库工程、子代理协作与授权安全分析的推理时工作空间和控制套件。
★ 2,957已汉化DSH
70.5
两阶段工具锚定预设xiaobright/dsh-anchored-standard
实验性 DeepSeek Harness agent preset…
★ 3,742已汉化DSH
70.1
智能体工作流编排nrslib/takt
不再日夜盯着 AI 编码智能体。
★ 1,402已汉化DSH
70
Agent 运行时手册Electricitysheep/dsh-handbook
DeepSeek Harness dsh 从 0 到 1 深度手册:安装/插件开发/性能调优/实测案例/同模型多…
★ 827已汉化DSH
68.7