DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

BPTumbleweed /

BPTumbleweed/dsh-session-retitle

Verified

DSH 会话重命名插件:会话头部一个「重命名」按钮,手动触发时读取本会话内容、用当前模型起中文短标题并写回会话名。零运行时依赖,改名走官方 session-title 服务,含候选路由回退与同会话并发保护。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@0d016509

dsh-session-retitle

DSH(DeepSeek Harness)插件:在会话头部加一个「重命名」按钮,手动触发时读取本会话内容、用当前模型起一个中文短标题,并写回会话名。

补的是官方自动命名的空档:官方 session-title-first-prompt-llm 只在第一条消息时自动命名一次,之后聊偏了也不会改;本插件让你在任何时刻按一次按钮,用整个会话的实际内容重新起名,并且一旦手动改过,官方的自动命名不会再覆盖(session/title 的 source.kind = user 会被钉住)。

  • 手动:只有你点按钮才会跑。不轮询、不后台常驻、不自动改你的会话名。
  • 一次调用:读会话 → 调一次模型 → 写一条 session/title。
  • 两条路:留空输入框 = 按内容自动起名;填了名字 = 直接用你给的名字(不花模型调用)。
  • 跟随主题:界面颜色全部走 DSH 自己的 CSS 变量(--dsw-alias-*),明暗主题切换自动生效。
  • 零运行时依赖:不 import 任何 @deepseek-ai/* 包,只发两条自己的 HTTP 路由。

安装

# 1) 备份 profile 三件套(回滚靠它)
P=<profile 目录>          # 例如 $DSH_HOME/profiles/web
S=$(date +%Y%m%d-%H%M%S)
cp -p $P/package.json        $P/package.json.bak-$S-prepluginupdate
cp -p $P/pnpm-lock.yaml      $P/pnpm-lock.yaml.bak-$S-prepluginupdate
cp -p $P/pnpm-workspace.yaml $P/pnpm-workspace.yaml.bak-$S-prepluginupdate

# 2) 安装。link: 指向源码目录:改代码只需重启,不用重装
dsh plugin --profile web add link:/path/to/dsh-session-retitle
#    也可以直接从 GitHub 装:dsh plugin --profile web add github:BPTumbleweed/dsh-session-retitle

# 3) 重启 dsh-web(host 与客户端插件都要重启才生效)
#    自己就跑在这个服务里的话,重启要交给脱离会话 cgroup 的瞬时单元执行
sudo systemd-run --on-active=40 --unit=dsh-retitle-restart-$(date +%Y%m%d-%H%M%S) --collect \
  /bin/bash /path/to/restart-and-selfcheck.sh

dsh plugin 需要 pnpm 在 PATH 上。重启会让 GUI 中断 35–45 秒,之后需要 Ctrl+Shift+R 硬刷新才会加载到新的客户端按钮。

验证

curl -s http://127.0.0.1:<端口>/dsh-session-retitle/status | head -40   # 期望 caps 全是 ok

(带认证的部署需要先拿到浏览器 cookie;未认证时该路由返回 401,属预期。)

界面上:打开任意会话 → 头部右侧出现「重命名」按钮 → 点开 → 直接点「自动起名」,几秒后顶部会话名变成模型起的标题;侧边栏列表同步更新。

失败时按钮旁会显示原因(例如"这个会话里还没有可用来起名的内容")。

配置(profile 的 cordis.patch.yml 覆盖)

键 默认 说明
routePrefix /dsh-session-retitle 路由前缀,与客户端常量 window.__DSH_SESSION_RETITLE_PREFIX__ 对应
maxTitleBytes 80 标题字节预算(与官方 session-title.maxTitleBytes 对齐)
maxDigestBytes 8000 送给模型的会话素材上限,超了从头丢(保留最近的对话)
maxDigestItems 16 最多取多少条消息(人类消息 + 助手回复)
timeoutMs 45000 标题模型调用超时
maxOutputTokens 512 标题模型的最大输出 token(请求带 purpose=session-title,deepseek 适配器会据此关思考)
provider / model deepseek-official / deepseek-flash 兜底路由:会话读不到 request/header 时才用

路由选择顺序:会话自己的 request/header → 官方 agent-default-model 当前选择 → 插件配置兜底;三者都拿不到就明确报错,不编造标题。

停用与回滚

# 临时停用:给 cordis.patch.yml 里的 dsh-session-retitle 条目加 disabled: true,然后重启
# 彻底移除:
dsh plugin --profile web remove dsh-session-retitle
# 三件套回滚:把 package.json / pnpm-lock.yaml / pnpm-workspace.yaml 还原成 .bak-<stamp>-prepluginupdate,再 pnpm install + 重启

插件不改任何已有文件、不写任何数据目录,移除后不会留下垃圾。

自测

node test/selftest.mjs         # 35 项:纯函数 + 假 ctx 路由分支 + 客户端插槽注册 + 主题跟随
node test/contract-check.mjs   # 4 项:拿真实 DSH 包验证消息形状/分片处理/官方标题归一化

contract-check.mjs 会去读本机安装的 DSH 包(用 DSH_CHECKOUT=<dsh 安装目录> 指定,或从当前 Node 安装前缀自动推断);读不到就跳过(退出码 0)。

踩过的坑(2026-09-16)

症状:点「重命名」按钮,4 次里有 3~4 次报"模型输出被 maxTokens 截断,未得到完整标题"。

根因:本插件最初把请求的 purpose 写成自定义值 session-retitle,而 dsh-llm-deepseek 只在 purpose === "session-title" 时关闭思考(thinking: disabled)。适配器不认自定义 purpose → 思考照开, 本机默认 reasoningEffort: high → 给的 64 个输出 token 全被 reasoning 吃掉,正文一个字都没写就被判 max-tokens(官方标题 provider 敢用 64 token,正是因为它的 purpose 会被适配器关掉思考)。

修复(三处,已加回归用例):

  1. purpose 改为官方槽位 session-title;
  2. maxOutputTokens 默认 64 → 512,给其他适配器/长标题留余量;
  3. 宽容收尾:只要已经拿到可用的标题文本就采用(附带一条 warnings),只有"一个字都没有"时才 把结束原因当失败报出来 —— 截断不该丢掉已经拿到的好标题。

同一天发现的第二个坑:有的会话日志里记着 deepseek-vision 这个 provider,而当前部署没有它的 adapter,按"选中一个路由就死磕"的写法必然失败。改为候选路由依次尝试:会话路由 → 官方默认模型 → 插件兜底,前一个不可用就换下一个,并在 warnings 里说明发生了回退。同时加了同会话并发保护 (连点按钮第二次返回 429)和 /status 错误台账(byCode 计数 + 最近 5 条 recentErrors)。

第三个坑:暗色主题下白底白字。按钮/气泡的颜色最初写成 var(--dsh-bg-elevated, …) —— DSH 里根本没有 --dsh-* 这族变量(它用的是 --dsw-alias-*,定义在 dsh-client-ui-theme 的 :root{} 与 [data-ds-dark-theme]{} 两组里,同名两套值),于是 #fff 兜底生效、面板在暗色下惨白。 改为三层保险:

  1. 主:颜色全走 --dsw-alias-*(label-primary/secondary/tertiary、border-l1/l2、bg-layer-2、 specific-menu、interactive-bg-hover、elevation-*)—— 值随主题切换,浏览器自动重绘,零 JS;
  2. 备:运行时探测这些变量是否存在;不存在(DSH 以后改名)就用 detectTheme() 读到的明暗落自带色板;
  3. 兜底:CSS 系统色 Canvas / CanvasText,至少不会白底白字。

顺带把悬停/聚焦态从内联样式搬进注入的 <style>(内联写不了 :hover),并给气泡设 color-scheme, 让输入框的原生控件(光标、选区)也跟着主题走。

实现(为什么这么写)

lib/retitle.js   纯逻辑:会话事件 → 素材 → 模型请求 → 标题清洗(零依赖,可单测)
lib/index.js     host:两条 HTTP 路由(/rename、/status),探测 sessions/llm/sessionTitle
lib/client.js    客户端:会话头部动作区一个按钮 + 一个小气泡
  • 不自己写 session/title:改名交给官方 SessionTitleService.rename(),归一化、长度上限、user 来源钉住,全由官方负责;官方以后改规则,本插件自动跟上。
  • 能力逐个探测:webServer / connection / sessions / llm / sessionTitle 缺任何一个,只让按钮报错(503 + 原因),不阻塞 DSH 启动。
  • 信任栅栏:所有路由先过 connection.requestRejection(req),栅栏不可用时 fail-closed(403),改名接口不会对外裸奔。
  • 客户端薄到极致:只注册一个按钮;插件 UI API(插槽 + React 运行时)是最容易被 DSH 升级打断的一层,最坏情况是按钮消失,不影响会话本体。
  • 不依赖 DSH 内部包:插件以 link: 装在 workspace,Node 从插件真实路径解析不到 @deepseek-ai/*,硬依赖会直接炸掉实例。消息对象按官方 createUserMessage() 的形状手工构造({id, role, content[], source:{kind:'plugin',plugin}})。

已知边界

  • 只有当前在内存里活着的会话能改名(官方 rename 要求 sessions.get(id) === session)。历史归档会话点不到按钮,也就改不了。
  • 素材只取人类消息与助手文本回复,工具结果/插件快照/斜杠命令都当噪音丢掉 —— 这是刻意的,避免把 bash 输出当成会话主题。
  • 标题用会话主要语言(通常是中文),10 个汉字以内的提示词约束;模型不听话时由 maxTitleBytes 硬截断兜底。

授权

MIT © 2026 Kan Zheng <202309068@uibe.edu.cn>

—/ 5

No ratings yet

Verified DSH bundle

Commit 0d01650904d9

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout