DeepSeek Harness 会话标题插件:dsh-session-namer

前言

DeepSeek Harness(DSH)默认的会话标题 provider 只用第一条人类消息取名,并且 system prompt 里有一句 still return a short best-effort title, such as Greeting。这导致一个以「你好」开头的会话就永久叫「打招呼」「简单问候」「Greeting in Chinese」。

dsh-session-namer 替换掉这个 provider,并额外提供两个手动入口(模型工具 + 界面按钮)。

插件定位

插件名称为 dsh-session-namer,由 fantasy123246 维护,分类为客户端。它是一个 DSH 插件,旨在解决默认标题 provider 过于依赖问候语、无法反映实际工作内容的问题。

核心功能

1. 替换标题 provider

插件将默认的 automatic: 'first-prompt' provider 替换为自定义 prompt。prompt 删除了 such as Greeting,并修改为:
- 标题是列表里的路标,不是摘要
- 以主语开头
- 名词短语、2-4 个词
- 禁止用问候类标签:no "Greeting", "打招呼", "你好", "问候", "New chat", "闲聊", "简单问候"

同时,插件会将工作目录、agent preset 和会话实际做了什么一起喂给模型。

2. 喂「会话做了什么」而不只是「人说了什么」

这是覆盖面问题的解。一条几千事件的会话,人类消息加起来可能只有一两千字节,而 tool/call + job/registered 里藏着主语。

digest 只取工具名、文件名(basename)、脚本名及其出现次数,不取任何工具输出、不取 assistant 正文。体积小(约 300 字节)且全是有信息的名词:

{"toolsUsed":["pwsh×166","read×89","write×74"],
 "filesTouched":["adapter.js×47","serialize.js×20","AGENTS.md×13"],
 "scriptsRun":["_probe_variant.mjs×10","_scan_logs.py×8"]}

只出现一次的不带 ×1。

3. 有界的自我修订

一轮结束后,如果人类说了当前标题尚未引用的新内容,就 sessionTitle.refresh() 重跑一次(默认最多 4 次,两次之间至少隔 120 秒),让标题跟上实际工作。

只对本插件自己命名的会话生效:装插件前就已有标题的会话不会进入这张表,而 first-prompt 语义上也不会让服务把「已有标题的会话」交给本插件。历史会话名永远不会被改写。

4. 长度按显示宽度算,不是字数

CJK 字符算 2 格、拉丁字母算 1 格。超出上限时按边界截断:切在拉丁单词中间会退回词首,切在 CJK 串中间会退回最近的分隔符。

5. 被拒的答案重来一次

模型偶尔还是会返回「你好」(旧 prompt 教出来的习惯),或者超宽到必须截断。这两种情况会把拒稿理由追加进请求再问一次(只对这两种硬失败:略超目标宽度是正常的,不值得为它花第二次模型调用)。

6. 手动入口

用户点了才跑:

  • 模型工具 session_title:对话里说一句「给这个会话重新取个名字」即可。
  • 对话头部按钮「重新取名」:只作用于当前打开的会话。

不做什么

插件不批量修历史会话名,不改写任何已有的 session.v4.jsonl.zstd,不刷新投影缓存。打开一个旧会话再点按钮属于显式用户动作,那一刻它是活会话,走的是 sessionTitle.refresh() —— 和自动流程无关。

安装与启用

将插件目录放到任意位置(例如 ~/.dsh/plugins/dsh-session-namer),然后运行:

dsh plugin --profile desktop add link:C:/Users/<you>/.dsh/plugins/dsh-session-namer

装完完全退出 DSH(含托盘)再启动。宿主在启动时注册 provider,cordis.patch.yml 里 session-title-llm: disabled 会同时生效。

改完 lib/index.js 想立刻生效:宿主有 dsh-hmr 在盯着插件目录,touch 一下文件等几秒即可,GET /dsh-session-namer/status 的 revision 字段会变成源码里的 REVISION 常量。

配置

在插件自己的 cordis.patch.yml 里 config: 段(或在 profile 的 cordis.patch.yml 覆盖同名条目)。全部可选:

键 默认 说明
targetTitleWidth 16 目标显示宽度(格);CJK 字符 2 格、拉丁字母 1 格,即 8 个汉字或 16 个字母
maxTitleWidth 24 硬上限;超出按边界截断
maxInputBytes 8192 送给模型的输入字节上限(超了从最旧的消息开始丢)
maxOutputTokens 1024 输出上限;推理模型会先花 token 思考
timeoutMs 45000 单次取名超时
maxRefinements 4 自驱动修订上限;0 = 只取一次名,之后不再自动改
refineGapMs 120000 同一会话两次修订之间的最小间隔,防止连着几个短回合就刷一串模型调用
includeCwd true 是否把工作目录作为主语素材
includeActivity true 是否把「会话做了什么」的 digest 一起发
provider / model 空 显式路由覆盖,两个必须同时给;留空则用会话已记录的 route

手动入口的行为

  • 工具:exec.agent.session → sessionTitle.refresh(),返回 {ok, title, previous, changed};失败返回 {ok: false, message},不会抛到模型。
  • 按钮:POST /dsh-session-namer/refresh {sessionId, hint?},返回 {ok, title, previous, changed, source, model, status}。GET /dsh-session-namer/status 看 revision、生效配置、最近一次生成结果与失败原因。会话不在内存里时返回 400「该会话当前没有打开」——不碰冷会话。
  • hint 可以给一句话强调,例如 偏向备份脚本。

适用场景与注意

适合需要更准确、更反映实际工作内容的会话标题场景。插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。

已知边界

  • sessionTitle 同时只允许一个 provider;装本插件必须让 session-title-llm 保持 disabled,否则服务会报 session-title provider "..." is already registered。
  • 会话若被用户手动改过名(source.kind === 'user'),refinement 会立刻放弃该会话,只有显式点按钮/调工具才会覆盖。
  • refresh() 只对内存中的活会话可用(session "${id}" is not live in this store)。

生态背景

DSH 理念是「一切皆插件」;社区目录是独立站点,与 DeepSeek / 幻方无官方从属关系。

短结尾

dsh-session-namer 通过改进 prompt、引入会话活动摘要、有界自我修订和手动入口,让 DeepSeek Harness 的会话标题更贴近实际工作内容。适合需要精细控制会话命名的开发者。目录页:https://www.skillhub.cn/plugins/fantasy123246/dsh-session-namer,GitHub:https://github.com/fantasy123246/dsh-session-namer。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye