DeepSeek Harness 插件

JohnXu22786/session-titler

Star 数 ★ 0 分类 会话与消息 收录于 2026-08-16

两阶段会话题词:会话进行中即时关键词题名,空闲后再调用最经济的预算模型精修,并附带一句话摘要。

安装

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:JohnXu22786/session-titler

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

English

为 DeepSeek Harness(dsh)提供两阶段会话题词(自动命名):会话进行中先用关键词即时生成标题,空闲后再调用最经济的模型精修。全程后台运行,不打断主流程,不为标题多花一分冤枉钱。

用户发消息 ──► [阶段一] 关键词即时题词(零成本、毫秒级)
                   │
                   └─► 会话空闲 5 秒 ──► [阶段二] 预算模型精修 + 一句话摘要
                                              │
                                              └─► 写入 session/title(可追溯)

解决的问题

Harness 的新会话默认只有时间戳编号,长会话列表中难以分辨。已有方案要么只做「等空闲再生成」(用户等待期间没有标题),要么每轮都调用模型(成本高)。本插件把两个思路拆成互补的两段:

  • 阶段一 · 即时题词:用户消息一落地,立即从最新消息提取关键词,标题几乎零延迟出现,不调用任何模型
  • 阶段二 · 空闲精修:会话安静下来后,用一次辅助调用把标题从「关键词串」升级为通顺的短语,并顺带产出一句话会话摘要(同一请求内完成,不额外计费);
  • 成本护栏:精修默认只使用注册模型中最便宜的一档(flash/haiku/mini 等),可显式指定模型,也可完全关闭阶段二。

功能特性

  • 两阶段流水线:即时关键词题词 → 空闲预算模型精修,标题随会话演进;
  • 成本控制:预算路由按名称模式从已注册模型目录中挑选最便宜模型并缓存,模型拓扑变化自动失效;
  • 原创关键词算法:噪声剥离(代码块/URL/Markdown)→ 脚本检测(拉丁/CJK)→ 停用词与虚词过滤 → 词序保持/字符预算截断,中英日韩均可用;
  • 多语言:标题语言跟随消息语言,拉丁标题按词数、CJK 标题按字符数控制长度;
  • 标题去重:同一标题不重复写入;跨会话重名时自动追加编号后缀(Fix Login Bug (2));
  • 摘要联动:精修时顺带生成一行会话摘要,以 session/caption-note 事件写入会话日志,供列表 UI、导出工具等消费;
  • 尊重人工标题:用户手动改名后自动生成完全停止,绝不覆盖(包括精修调用进行中的改名,也不会被回写);
  • 零配置可用:默认值即可运行,全部行为可调。

安装

在 DSH 中安装(从 GitHub)

从 GitHub 安装最新版本到 profile:

dsh plugin --profile demo add github:JohnXu22786/session-titler

移除:

dsh plugin --profile demo remove dsh-session-caption

本插件是一个标准 dsh bundle(配置层 + 插件代码),通过 dsh plugin 安装到 profile:

# 从本地目录安装(开发/自用)
dsh plugin --profile web add /path/to/dsh-session-caption

# 或打包后安装(tarball / git 引用同理)
npm pack
dsh plugin --profile web add ./dsh-session-caption-0.1.0.tgz

安装时 pnpm 会把包链入 profile 的 node_modulesdsh 识别 package.json 中的 dsh.bundle 声明,将 cordis.patch.yml 层加入 dsh.profile.bundles。重启后生效:

dsh --profile web --dump-config   # 应能看到 "session-caption" 行
dsh web

加载原理(给 harness 开发者)

  1. Bundle 清单package.jsondsh.bundle.patch 指向 cordis.patch.yml——这是 bundle 唯一必需的元数据;
  2. 配置层cordis.patch.yml 先按行 id 停用内置的单阶段标题提供方(会话标题服务同一时刻只接受一个提供方),再插入本插件的配置行;
  3. 入口文件lib/src/index.js 导出标准 Cordis 插件契约——namesession-caption)、inject['sessionTitle', 'sessions', 'llm'])、Config(schemastery 校验 schema)、apply(ctx, config)
  4. 能力注册apply 中把两阶段流程注册为 ctx.sessionTitle唯一提供方automatic: 'all-user-messages'),同时监听 session/eventllm/adapters-updated;所有监听器、定时器、注册项随插件卸载自动回收。

注意:session-title 服务是单提供方设计。若其他插件也注册了标题提供方,二者会互相取代;本插件的 bundle 层默认已停用内置的 session-title-llm 行。

配置

所有字段可选,默认值见下。全局配置写入 $DSH_HOME/cordis.patch.yml,按行 id 覆盖:

# $DSH_HOME/cordis.patch.yml(home 级,作用于所有 profile)
- id: session-caption
  config:
    instant:
      enabled: true        # 阶段一开关
      prefix: ''           # 即时题词前缀,如 '⚡ '
      maxWords: 6          # 拉丁标题最大词数
      maxCjkChars: 14      # CJK 标题最大字符数
    refine:
      enabled: true        # 阶段二开关
      maxWords: 5          # 精修标题目标词数(拉丁)
      maxCjkChars: 10      # 精修标题目标字符数(CJK)
      maxInputBytes: 4096  # 精修输入消息字节上限(JSON 框架后)
      maxOutputTokens: 64  # 精修输出 token 上限
      timeoutMs: 60000     # 精修单次调用超时
    budget:
      preferCheap: true    # 只从低成本模型目录挑选
      # patterns: [...]    # 低成本模型名称模式(按性价比排序)
    summary:
      enabled: true        # 摘要联动开关
      maxChars: 120        # 摘要最大字符数
    timing:
      idleDelayMs: 5000    # 空闲判定延迟(精修触发点)
      activityWindowMs: 1500  # 事件后的活跃窗口
      modelCacheMs: 120000    # 预算路由缓存时长
    model:
      provider: ''         # 显式精修路由(与 model 成对)
      model: ''            # 如 deepseek-official / deepseek-v4-flash
    dedup:
      enabled: true        # 标题去重(同标题跳过 + 跨会话编号)
      suffix: '({n})'      # 编号后缀模板,必须含 {n} 占位符(从 2 起)
    debug: false           # 调试日志

关闭 instant.enabled 后,阶段一不再产出关键词标题,但阶段二依然只在空闲窗口运行(忙碌期间的自动生成请求被跳过,标题等会话安静后由定时器驱动生成),不会变成「每条消息都调用模型」。

模型选择优先级(阶段二)

  1. model.provider + model.model 显式配置;
  2. budget.preferCheap 开启时,扫描所有可配置提供方的模型目录,按 budget.patterns 中的模式名匹配并取最优(默认顺序:flashhaikulitemininanofast → …,同档取名字最短者),结果缓存 timing.modelCacheMs
  3. 会话自身的模型路由(request.route);
  4. 都不可用时跳过精修,保留即时题词。

接口

提供方(Provider)

注册于 ctx.sessionTitleidsession-caption,自动模式 all-user-messages

字段 说明
id session-caption 写入 session/title 事件的来源标识
automatic all-user-messages 每条新用户消息触发一次生成
generate(request) 活跃 → 即时题词;空闲 → 精修

generate 输入 { session, messages, route?, signal },输出 { title, messageSeqs, model? }。以下情况抛 CaptionSkippedError(服务端保留现有标题,不视为故障):

  • 用户已手动改名(source.kind === 'user');
  • 即时阶段无可提取的关键词;
  • 精修结果与当前标题相同(去重,同时标记会话为稳定,避免反复生成);
  • 无可用的模型路由。

事件

事件 类型 说明
session/title log-only(Harness 自带) 每次接受的标题快照,含来源与消息 seq
session/caption-note log-only(本插件贡献) 精修时的一句话摘要:{ title, note, messageSeqs }

caption-notetitle 一样不进入模型上下文;不识别该事件的回放器可安全跳过(信息性记录)。

目录结构

src/
├── index.ts       # 插件入口:name / inject / Config / apply
├── config.ts      # 配置 schema 与运行时校验
├── context.ts     # 结构化 Harness 上下文类型
├── flow.ts        # 两阶段编排(generate / 事件喂入 / 去重 / 摘要)
├── keywords.ts    # 阶段一:关键词题词引擎
├── refine.ts      # 阶段二:预算模型精修 + 摘要
├── budget.ts      # 成本路由:最便宜模型选择与缓存
├── pacemaker.ts   # 空闲节拍器:活动感知 + 精修定时
├── normalizer.ts  # 标题清洗、限长、比较
├── language.ts    # 拉丁/CJK 脚本检测
├── events.ts      # 自定义事件声明
└── errors.ts      # CaptionSkippedError:跳过的修订

开发

npm install     # 开发依赖(含 dev/pkgs 下三个转发包,file: 引用,可重装)
npm run typecheck   # tsc 类型检查
npm test            # vitest 单元与流程测试(86 例)
npm run build       # 编译到 lib/src/

运行时依赖说明:插件在运行期使用 @deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-session-title,它们由 dsh 安装本身提供,未在 manifest 中声明为 dependencies/peerDependencies——这三个包的 npm 传递依赖链目前不完整(一个传递包未发布),声明会导致安装失败;若装入不含这些包的自定义 profile,加载时会报 ERR_MODULE_NOT_FOUND,把包装进 profile 的 node_modules 即可。

本地开发镜像stubs/ 目录是这三个包的最小 API 镜像(与发布版 rc.1 的已消费成员逐一核对);dev/pkgs/ 下是三个薄转发包(file: 依赖),供 tsc 解析与本地测试,不随插件发布(files 只含 lib/src、配置层与文档)。

许可

MIT — 见 LICENSE

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →