DeepSeek Harness Hub
← 返回列表

体验优化工具箱kolawong/dsh-plugin-toolkit

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

面向 DeepSeek Harness 的个人体验优化工具包。每项优化都太小,不足以单独成为一个垂直插件,因此它们作为…

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/16 · 已提供中文文档

DeepSeek Harness 个人工具包:可运行时切换的体验优化功能,每项功能都作为 Toolkit 设置页面中的一张卡片提供。

综合分
30.6
GitHub 分
30.6
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add kolawong/dsh-plugin-toolkit
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/schemastery@deepseek-ai/dsh-settings
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

English · 简体中文

面向 DeepSeek Harness 的个人体验优化工具包。每项优化都太小,不足以单独成为一个垂直插件,因此它们作为 Toolkit 设置卡片中的一个条目一起发布:Web 设置 → 插件 → DSH-Toolkit 会展开一个半宽子卡片网格(图标、标题、简短副标题、开/关徽标),点击子卡片即可打开该优化的对话框。随着列表增长,插件页面仍保持为一个紧凑的启动器。

一切都通过公开扩展接口接入——设置命名空间、客户端模块表、对话槽位、llm/stream、模型发现以及 webServer 路由——因此不会修改任何 dsh 核心包,上游一键升级也始终轻松无痛。

目录

- 一览
- 安装
- 架构
- 设置卡片
- 优化项
- workspacelessChat
- editLastMessage
- viewActivity
- slashI18n
- changeReport
- opencodeSession
- modelCapability
- 配置参考
- 开发
- 毕业规则
- 模型体验
- 许可证

一览

| # | 优化项 | 功能 | 默认 | 半宽 |
|---|---|---|---|---|
| 1 | workspacelessChat | 保留一个无项目聊天工作区,并在冷启动时自动连接它 | 开启 | 客户端 + 主机 |
| 2 | editLastMessage | 编辑并重新发送最后一条用户消息,回退模型上下文 | 开启 | 客户端(主机 session.rewrite RPC) |
| 3 | viewActivity | 侧边栏活动图标:优先显示运行中,然后按今天 / 昨天 / 星期几 / 更早 | 开启 | 客户端 |
| 4 | slashI18n | 为 / 菜单中的命令和技能提供中文描述 | 开启 | 客户端 |
| 5 | changeReport | 在回合末尾显示 Codex 风格的每回合文件变更卡片 | 开启 | 客户端 |
| 6 | opencodeSession | 在 OpenCode Go/Zen 请求上添加稳定的 x-opencode-session 请求头 | 开启 | 主机 |
| 7 | modelCapability | 保持一条 llm-pi-ai 路由的模型列表、容量和图像支持为最新 | 开启 | 主机 + 客户端 |

安装(web 配置)

cd ~/.dsh/profiles/web
pnpm add file:/path/to/dsh-plugin-toolkit   # link:/path/to/dsh-plugin-toolkit while developing
add "dsh-plugin-toolkit" to the dsh.profile.bundles list in package.json
systemctl restart deepseek-harness.service  # or your profile's restart path
服务端改动(本包)需要重启 profile;客户端 bundle 需要在 profile 内执行 pnpm install 重新同步,然后硬刷新浏览器。开关、路径和模型列表都是 settings 命名空间中的值,因此日常编辑无需重启即可实时生效。

架构

本包分为浏览器部分和宿主部分;两者读取同一个 toolkit settings 命名空间,且都不改动 dsh 源码。

| 部分 | 文件 | 职责 | 使用的接缝 |
|---|---|---|---|
| 客户端 | client.js | 设置卡片、内联编辑 UI、侧边栏重新排序、/ 菜单重写、变更报告卡片、模型 ID 选择器 | 客户端模块表、会话节点/轮次尾部插槽、remote. 命名空间包装、settings 作用域 |
| 宿主 | index.js | Settings schema 与默认值、默认聊天工作区目录、OpenCode 会话头标记 | settings、llm/stream、globalThis.fetch |
| 宿主 | model-sync.js + models-core.js | 模型发现包装、同步/列表路由、容量与模态增强 | llm 模型发现、webServer 路由、settings 存储 |

贯穿本包的设计规则:

- 不打核心补丁。 每个钩子都是文档化的扩展面,因此上游升级不会与 toolkit 冲突。
- 休眠而非损坏。 缺少某个接缝(旧版宿主、没有 webServer、没有 session.rewrite)只会禁用那一项优化;UI 的其余部分不受影响。
- 实时配置。 每个开关和字段都位于 toolkit settings 命名空间中,并在使用时重新读取。
- 独立开关。 每项优化都可以从其子卡片中关闭,并原样恢复默认行为。

设置卡片

卡片为每项优化渲染一个子卡片,带有实时开/关徽章,以及一对 Enable all / Disable all 按钮。打开子卡片会显示该优化自己的描述和字段(例如聊天目录,或模型能力键与选择器)。

优化项

workspacelessChat

无需先选择工作区即可聊天,类似其他 agent harness 的默认项目行为。dsh 的 composer 要求空白会话必须属于某个工作区,因此该优化会保留一个专用的无项目聊天工作区(「通用对话」):只要启用该优化,就会以友好标题幂等地创建它,因此该选项始终显示在侧边栏和工作区选择器中——打开它即可在没有项目的情况下聊天。
除此之外,当两个基线都就绪、没有选中任何会话,且运行时自身的启动策略没有最近的工作区可连接时(首次运行、没有工作区),客户端还会在该工作区中自动连接一个空白会话,使编辑器立即处于可用状态。

冷启动自动连接的失败最多重试 3 次(间隔 2 秒),之后保持休眠,直到列表变化重新触发检查。运行时自身的最近工作区自动连接始终优先;自动连接只填补无内容可连接的情况,而工作区本身则无条件存在。仅当工作区仍带有自动派生的基名时,才会将其重命名为友好标题(你自己设置的标题永远不会被覆盖)。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.workspacelessChat | true | 切换无项目聊天工作区 + 自动连接。 |
| chatWorkspacePath | "" | 默认聊天工作区的主机目录;为空时解析为 /chat。服务器会创建该目录(在设置编辑时也会实时创建)。 |
| chatWorkspaceTitle | 通用对话 | 无项目聊天工作区的显示标题。 |

卡片写入通过 toolkit 设置命名空间进行,因此切换和路径编辑无需重启即可实时生效。

editLastMessage

无需复制粘贴、也不会污染模型上下文即可重试失败的回复:最后一条用户消息的悬停操作中会新增一个 Edit 按钮。点击它会打开一个内联编辑器,并预填该消息;Save & resend 会就地重写会话——被编辑的消息及其之后的所有内容都会被替换(模型上下文真正回退,因此下一次请求只包含编辑后的内容),并由新一轮回复来回答编辑后的消息。

这需要主机支持 session.rewrite RPC(对本仓库的 dsh 检出做一个小改动)。在不支持它的主机上,按钮仍会显示,但会报告不支持重写。客户端记录会抹除旧消息及其失败的轮次;轮次边界会保留,因此失败的轮次会折叠为一个不可见的空轮次。需要会话处于空闲状态(正在运行的轮次会以 agent-busy 拒绝);只有最后一条人类用户消息可编辑,且仅限文本。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.editLastMessage | true | 最后一条用户消息上的编辑并重发按钮。 |

viewActivity
向工作区侧边栏添加一个 Activity 图标(原生时钟字形),紧跟在搜索(放大镜)控件之后。点击它会就地重新排序侧边栏的对话列表:正在运行的对话会浮现在最前面的 Priority 分组中,其余历史记录则按 Today / Yesterday / Weekday / Earlier 分组(每组内最新的排在最前)——这就是熟悉的“最近对话”模式。再次点击会恢复之前的分组(工作区分区或扁平列表);当活动排序开启时,该图标会高亮显示。

100% 非侵入式外部实现:将活动切换钩入侧边栏头部,并动态替换会话树,对官方 DSH 核心包零修改,与上游一键升级零冲突。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.viewActivity | true | 工作区头部活动图标 + 就地运行的优先 / 按天重新排序。 |

slashI18n

/ 菜单的外壳文案(分组标题、仅用户徽章、骨架行)已经本地化,但条目的描述直接来自宿主:内置命令描述、参数提示和技能目录描述即使在中文界面下也全部以英文原样呈现。此优化在客户端翻译它们:工具包包装了 remote.commands.list 和 remote.skills.list 命名空间方法,并在任何消费者读取之前,通过精确匹配的英→中词典重写每个响应的 description / input.hint。

范围与安全护栏:

- name 字段从不翻译——模糊匹配、草稿芯片词典和声明裁定都会读取它们;whenToUse / modelInvocable 也原样保留。
- 词典未命中时会回退到原始字符串,因此 dsh 更新若改写了描述,会降级为英文,直到词典跟上(绝不会破坏菜单)。
- 翻译仅在 UI 语言为中文时应用,并且设置开关会针对每个 RPC 结果重新读取,因此切换会在下一次打开菜单时立即生效。
- 结果会被重建为全新对象,因此没有调用方缓存会别名引用线上数据;拒绝和错误结果原样通过;重新应用插件不会对方法进行双重包装。
- 你自己编写的技能只需在其 SKILL.md frontmatter 中携带中文 description 即可——无需词典。词典只覆盖 dsh 自带的内容(6 个内置命令、2 个尚未由 ui-conversation 自身的 hint. 语言键映射的提示,以及 2 个内置技能)。
- 无需修改 dsh 源代码,也无需主机扩展;在没有这些命名空间的主机上,该优化只是保持休眠状态。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.slashI18n | true | 为 / 菜单中的命令和技能提供中文描述。 |

changeReport

在每个已完成回合的末尾生成 codex 风格的变更报告。当一个回合更改了文件(edit / write / 会修改内容的 str_replace_editor 调用)时,末尾会渲染一张紧凑卡片:“N files edited · +A -R”,每个文件一行,并带有各自的 +N -M(点击某一行可在查看器中打开该文件),超过四行时显示 show more 展开器,以及一个 Review 按钮,用于打开该回合的完整 diff。该卡片是 dsh 内置 produced-files 末尾输出的超集:它接入同一条 conversation.chat.turnTail 链并位于其前面(优先级更低),并且在非修改型回合中不生效,因此原生末尾输出会与之前完全一致地渲染。

其工作方式及边界如下:

- 数据来自客户端侧的转录记录:会话回合数据累加器会为每次成功的修改调用记录一个变更前后的 hunk——包括直接的 agent 工具调用以及 run_code 的嵌套子调用(它们会以其根调用为键记录为 tool/code-dispatch 事件)。行数统计复用这些原语的 diffTotals,因此头部数字始终与 review DiffBlock 渲染的内容一致。
- bash 侧的文件写入(sed、重定向等)对转录记录不可见,因此不会被跟踪——该报告只覆盖专用的文件修改工具,就像 codex 跟踪它自己的工具一样。
- 失败的调用(工具错误结果)不会贡献任何内容;关闭 assistant seq 之后的结算会被排除;聚合结果会在每次渲染时重建(不与线上数据产生别名)。
- 没有 undo:在磁盘上还原文件需要浏览器不具备的主机侧能力。不提供该功能是有意为之——V1 仅用于显示。
- 无需修改 dsh 源代码:该插槽、回合数据定义注册表以及 diff 原语都是公开扩展接口。禁用该开关会原样恢复原生末尾输出。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.changeReport | true | 回合末尾的每回合变更报告卡片。 |

opencodeSession
OpenCode Go 现在会对缺少 x-opencode-session 的请求返回 400 拒绝({"type":"MissingSessionID", ...}),并且其指南要求编码代理用自己的 user agent 标识自身,并为每个对话发送一个稳定的 session id,以便网关能够路由请求并复用提示缓存。user-agent 部分已经满足——每个 dsh provider 请求都带有 deepseek-harness/ 归属标识。本次优化修复了 session 这一半,完全从插件侧实现:一个 llm/stream 监听器通过 AsyncLocalStorage 将进行中请求的会话身份沿异步链向下传递,而一个轻量的启动时 globalThis.fetch 包装会将请求头盖到目标主机为 opencode.ai 或其子域名的任何请求上(Go 和 Zen 皆然)。

其工作原理及边界:

- 该 id 是 dsh 已经附加到其构建的每个请求上的循环盖章会话身份(agent-loop 不变量要求如此),因此该请求头按构造即为每个对话稳定——新对话,新 id;同一对话,在轮次、重试、压缩和标题生成之间保持同一 id。
- 不携带会话身份的调用(罕见的手工构建一次性调用;也包括模型发现)会回退为每个进程一个 id,而不是以网关的 MissingSessionID 失败。
- 该包装只安装一次(带标记保护),仅在请求头缺失时添加,任何装饰失败都会回退到普通 fetch——它绝不会破坏请求。非 OpenCode 请求按字节原样通过。
- Provider SDK 按请求解析全局 fetch(pi-ai 在每次流调用时构造其客户端),因此启动时包装无需修改 dsh 源码,并且能在上游一键升级后原样存活。
- 100% 非侵入式外部实现,与 viewActivity 一样:对 dsh 核心包零修改。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.opencodeSession | true | 在 OpenCode Go/Zen 请求上使用稳定的每对话 x-opencode-session 请求头。 |

modelCapability

使一个 llm-pi-ai 路由的模型列表(默认 opencode-go)与端点的实时列表保持同步:新上线的模型立即可选,无需重启;缺失的上下文/输出限制从 models.dev 注册表和具有尺寸信息的同类模型补齐;图像输入从任何其他声明同一 id 为多模态的已注册 provider 借用;并且可以强制模型支持视觉或仅支持文本。这曾是 dsh-plugin-quota-badges 的「模型能力」部分,现在完整地放在这里——另一个插件不再包含它。

工作原理及其边界:

- 发现包装:包装运行时的 llm-pi-ai 模型发现,使 GUI 的“获取可用模型”以实时列表合并已安装目录后的结果作答,而非仅返回目录。该包装被标记为 enrichedByToolkit:只有探测确实成功的应答才算作同步路由的实时列表,因此临时的探测失败会回退到目录,绝不会缩减已存储的路由。卡片上没有“同步模型列表”按钮:采纳新模型发生在 dsh 自己的模型设置中(点击“获取可用模型”;列表由你确认后才会写入),因此不会有任何东西意外地把整个实时列表倾倒进路由。执行该操作的服务器路由——POST /api/toolkit/sync-models——保持注册,仅在显式调用时运行(API/脚本)。
- 可搜索的模型选择器:强制视觉 / 纯文本字段不再是逗号分隔的 id 输入框。每个都是在路由已知模型上按类型筛选的选择器——点击候选项将其添加为标签,点击标签的 × 将其移除,按 Enter 添加列表未知的 id,按 Backspace 删除最后一个标签。候选项来自 GET /api/toolkit/models(路由的已存储行 ∪ 运行时的 listModels,去重并排序,仅进程内读取——无网络),每次打开对话框时获取一次:它只读取已配置的模型,不做任何更改。两个列表互斥:添加到其中一个会从另一个中移除该 id。
- 启动修复:预先写入路由的线路协议(api),使配置界面自身的保存也能通过可服务性检查,并修复已保存模型上的图像输入(该保存路径不发送 input 字段)。对强制视觉 / 纯文本列表的编辑会立即应用到已存储的模型——无需重启,无需重新同步。
- 单向迁移:在 modelsApiKey 为空的情况下首次启动时,原 quota-badges 命名空间捐出其 OpenCode 密钥、强制视觉 / 纯文本列表和路由形态;迁移标记在同一次写入中落盘,因此之后清空密钥绝不会被重新填充。
- 在没有 settings / llm / webServer 接缝的主机上处于休眠状态——而非损坏——并且一切都留在此包内:不修改 dsh 源代码。

| 配置 | 默认值 | 含义 |
|---|---|---|
| optimizations.modelCapability | true | 发现包装、同步路由和能力修复的总开关。 |
| modelsApiKey | "" | OpenCode API 密钥;为空时回退到环境变量。 |
| modelsApiKeyEnvVar | OPENCODE_API_KEY | 当密钥为空时查询的环境变量。 |
| modelsRouteKey | opencode-go | 保持最新的 llm-pi-ai 路由。 |
| modelsBaseURL | https://opencode.ai/zen/go/v1 | 用于探测实时模型列表的端点。 |
| modelsRouteApi | openai-completions | 预先写入路由的通信协议。 |
| modelsSyncPath | /api/toolkit/sync-models | 同源显式同步路由(无卡片入口点;仅限 API/脚本;更改后需要重启)。 |
| modelsPath | /api/toolkit/models | 同源路由,列出选择器的候选项。服务器只注册该路径一次(更改后需要重启),而卡片会实时重新读取它,因此在重启之前,编辑会使卡片指向服务器尚未提供的路由。 |
| modelsEnrichFromRegistry | true | 从 models.dev 注册表填充缺失的容量/模态。 |
| modelsRegistryProvider | opencode-go | models.dev 注册表中的提供方目录。 |
| modelsVision | [] | 强制接受图像输入的模型 id。 |
| modelsTextOnly | [] | 强制丢弃图像输入的模型 id。 |
| modelsTimeoutSec | 10 | 实时探测的每请求总截止时间(秒),包括标头和正文。models.dev 注册表读取使用其自己固定的 4 秒预算。 |

注意:此优化带有一个服务器路由及其自己的配置字段,因此它已经满足下面的毕业规则;它目前有意留在 Toolkit 中,作为一个编号优化。

配置参考

所有字段都位于 toolkit 设置命名空间中。组合默认值在 cordis.patch.yml 中声明,schema 在 index.js 中,公共类型在 index.d.ts 中。

| 字段 | 类型 | 默认值 | 使用者 |
|---|---|---|---|
| optimizations.workspacelessChat | boolean | true | workspacelessChat |
| optimizations.editLastMessage | boolean | true | editLastMessage |
| optimizations.viewActivity | boolean | true | viewActivity |
| optimizations.slashI18n | boolean | true | slashI18n |
| optimizations.changeReport | boolean | true | changeReport |
| optimizations.opencodeSession | boolean | true | opencodeSession |
| optimizations.modelCapability | boolean | true | modelCapability |
| modelsMigratedFromQuotaBadges | boolean | false | modelCapability — 当采用原配额徽章模型设置时设置的内部单向标记;切勿手动设置。 |
| chatWorkspacePath | string | "" → /chat | workspacelessChat |
| chatWorkspaceTitle | string | 通用对话 | workspacelessChat |
| modelsApiKey | string | "" | modelCapability |
| modelsApiKeyEnvVar | string | OPENCODE_API_KEY | modelCapability |
| modelsRouteKey | string | opencode-go | modelCapability |
| modelsBaseURL | string | https://opencode.ai/zen/go/v1 | modelCapability |
| modelsRouteApi | string | openai-completions | modelCapability |
| modelsSyncPath | string | /api/toolkit/sync-models | modelCapability |
| modelsPath | string | /api/toolkit/models | modelCapability |
| modelsEnrichFromRegistry | boolean | true | modelCapability |
| modelsRegistryProvider | string | opencode-go | modelCapability |
| modelsVision | string[] | [] | modelCapability |
| modelsTextOnly | string[] | [] | modelCapability |
| modelsTimeoutSec | number | 10 | modelCapability |

开发

npm test              # node --test tests/.test.js — 无需宿主
npm run smoke         # index.js + model-sync.js 的宿主侧冒烟测试(需要同级依赖,见下文)
npm run smoke:client  # 客户端 bundle 的离线冒烟测试(无需宿主)

npm test 和 npm run smoke:client 是自包含的。npm run smoke 会导入
index.js,而后者会导入 @deepseek-ai/schemastery 和
@deepseek-ai/dsh-settings 这两个同级依赖;它们并非本包的依赖项,
因此请从能够解析它们的检出目录中运行(例如 dsh 工作区,或已安装本包的
profile),而不要从裸 npm install 的环境中运行:

cd /root/deepseek-harness && node /root/dsh-plugin-toolkit/scripts/smoke.mjs

| 路径 | 内容 |
|---|---|
| index.js / index.d.ts | 宿主侧:设置命名空间、聊天目录、OpenCode fetch 包装。 |
| model-sync.js | 宿主侧:发现包装、同步/列表路由、增强与迁移。 |
| models-core.js | 纯合并/增强/差异辅助函数(无网络、无设置访问)。 |
| client.js | 浏览器侧:设置卡片及所有客户端侧优化。 |
| cordis.patch.yml | 插入到 dsh bundle 补丁中的组合默认值。 |
| tests/ | 单元测试:纯核心、同步路由、设置卡片,以及 index.js(fetch 包装 + llm/stream 会话链)。 |
| scripts/ | 冒烟、e2e 和验证脚本。smoke.mjs / client-smoke.mjs 为离线;e2e-verify.mjs(TOOLKIT_VERIFY_URL、DSH_AUTH_PASS)和 verify-opencode-session.mjs 需要活动宿主。 |
| docs/assets/ | 本 README 系列使用的 SVG 图表。docs/initiative-.md 为内部设计笔记,已刻意从 npm 包中排除。 |

毕业规则

当满足以下任一条件时,某项优化会从本包中毕业,成为独立的 dsh-plugin-*:

- 它发展出超出单行开关的设置 GUI、服务路由、后台任务或 client.js 功能面;
- 它需要按组合行启用/禁用(Cordis 切换整行,而非单个工具);
- 其定义加测试超过约 200 行;
- 它值得单独发布或分享。

模型体验

未注册任何工具,也未更改任何提示面;本包纯粹是 UI/运行时人体工学。唯一的例外是 editLastMessage 重写,它按设计会改变模型所见内容:编辑后,被擦除的尾部会从派生的请求历史中移除(通过 surface replace),因此后续轮次只会读到编辑后的内容。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(kolawong)的其他插件

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群