DeepSeek Harness 插件

pc439527/dsh-model-provider

Star 数 ★ 1 分类 UI 增强 收录于 2026-08-29

Provider-first 三级模型选择器:先选供应商再选模型,两级均可行内搜索,失败供应商以可重试行展示,触发器显示 Model · Provider。

安装

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

dsh plugin --profile web add github:pc439527/dsh-model-provider

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

License: MIT · Platform: DSH Web(客户端插件)

English · 简体中文

Provider-first Model Selector —— DeepSeek Harness 模型选择器插件。

先选择模型供应商,再选择该供应商下的模型;当前模型始终显示 Model · Provider, 但不改变 DeepSeek Harness 原有模型调用和会话状态逻辑。

在 DeepSeek Harness 的 Web 界面中,把编译器(composer)里的模型座位(model seat)从 「Provider 分组 + 全模型展开」升级为 三级选择器(v0.3.0):

启用前                    启用后(本插件 v0.3.0)
DeepSeek V4 Flash          DeepSeek V4 Flash · OpenCode Go

试试打开下拉(模型很多也不乱):

第一层(主菜单)            第二层(Provider)            第三层(Model)
├─ 模型   DeepSeek V4 Flash >   ├─ opencode-go  8 个模型 · 当前 >   opencode-go
└─ 推理等级 High            >   ├─ luckikey     2 个模型       >   ├─ MiniMax-M3
🔍 搜索供应商                   ├─ OpenRouter  20 个模型      >   ├─ Qwen3.7 Max
    (过滤 Provider 行)            ├─ DeepSeek     4 个模型       >   ├─ DeepSeek V4 Flash ✓
                                  └─ OpenRouterX  加载失败 ⚠ 重试    ├─ DeepSeek V4 Pro
                               🔍 搜索 opencode-go 模型            └─ GLM-5.1
                                  (只搜当前供应商)
  • Provider 单独成为一级:Provider 列表把当前供应商置顶并标出「· 当前」;其余 供应商保持目录顺序。Model 页只渲染选中供应商的模型,不再平铺 Provider × Model。
  • 失败 Provider 也是一行:加载失败的供应商不会只出现在警告横幅里,而是作为普通 Provider 行展示(「加载失败 ⚠ 重试」),点击即重载。
  • 搜索(v0.3):Provider 页和 Model 页都有行内搜索框 —— Provider 页按名称/ID 过滤 供应商,Model 页只过滤当前供应商的模型(不跨 Provider 搜索)。
  • Model 页头部:进入某供应商后,顶部为「‹ {供应商名}」+「{N} 个模型」副标题, 更像一个独立页面。
  • 触发器精简:默认显示 Model · Provider;只有当你主动选了非默认推理等级时 才附加 · Effort,不再浪费横向空间显示「Default」。
  • Esc 逐层返回:Model → Provider → 主菜单 → 关闭(鼠标点顶部「‹」返回同样逐层退)。
  • 触发器的 Model · Provider [· Effort] 与 Harness 会话状态完全一致。

工作原理

环节 说明
扩展点 官方 Slot 体系:conversation.input.model(single slot,session scope),非 DOM Hack
覆盖方式 以 priority: -1 注册同名单 slot —— 该 slot 渲染最低 priority 的 entry,因此本组件胜出、原座位被 shadow
数据 复用 Harness 原生的 modelDirectories 服务(每会话共享的 ModelDirectory),选择语义与禁选逻辑不变;Provider 列表直接来自 state.groups,失败列表来自 state.failures
回退 插件卸载(slots.inject 的 effect 销毁)时注册消失,原模型座位立即原样恢复
命名空间 独立 locale 词典 modelProvider(zh/en),不侵入 Harness 文案

兼容性

已在 DeepSeek Harness 0.1.1-rc.2(dsh CLI 0.1.1-rc.2 + Web 前端)上验证。 本插件依赖的公开 API 表面从 rc.8 到 rc.2 一路未变:

表面 rc.2 状态
Slot 组合 ctx.slots.inject(key, cb) / slots.register,支持 priority(升序、数值最小者渲染)+ 可选 registrant —— 未变;同名同 priority 会抛错,不同 priority 则是干净的 shadow
座位契约 conversation.input.model(single slot,session scope):owner 提供 locked、locale t 席、inject 面 { available, directory, load, select } —— 未变
目录接口 共享的每会话 ModelDirectory 快照 { current, routable, groups, failures, status, error } —— 未变
基础组件 IconChevronDown/Left/RightOutline14、IconCheck/Search/WarningOutline16、Toast { text, icon, anchor, onDone } —— 未变
设计令牌 --dsw-alias-*、--dsw-specific-menu、--dsw-shadow-lv3、--dsh-scrollbar-* —— 未变

peerDependencies 已对齐 rc.2 线(^0.1.1-rc.2,与 Harness 官方客户端包一致)。

组件保留原 ModelSelect 的交互基线(共享目录与选择 RPC / 键盘上下键与 Esc / 失败重试与 Toast / 推理等级页),仅把两级平铺改为三级导航:

  • 触发器:模型名 + · Provider(弱化样式);仅在用户选择非默认推理等级时附加 · Effort; title 与 aria 同步带上 Provider
  • 根菜单:模型(→ Provider 列表)、推理等级(→ 当前模型的 effort 列表)
  • Provider 页:顶部「‹ 选择供应商」返回根菜单;搜索框过滤;当前供应商置顶并以文字标记 「· 当前」(不做整行高亮);每行显示「N 个模型」;失败的供应商渲染为可重试行
  • Model 页:顶部「‹ {供应商名}」+「{N} 个模型」副标题;搜索框只过滤本供应商模型; 选中行以 ✓ 标记(providerId + modelId 复合键判定,同名模型跨 Provider 不串)
  • 默认推理等级:切到模型时自动把该模型的 defaultEffort 带进选择(selectionFor 是 唯一构造 Selection 的入口,choice 预构建与点击路径语义一致)

目录

dsh-model-provider/
|- package.json            # dsh.client 声明(platform: web, inject 列表)
|- pnpm-workspace.yaml     # pnpm 11 设置(批准 esbuild 构建脚本)
|- build.mjs               # esbuild 打包脚本 → lib/client.js(ModuleLoader 格式)
|- tsconfig.json           # noEmit 类型检查(src + test)
|- src/
|  |- index.ts             # Host 半区:空 apply(纯浏览器表面插件)
|  |- client.tsx           # 客户端入口:apply() + slot 接线 + 兼容导出
|  |- locale.ts            # modelProvider 词典(zh/en)
|  |- model/
|  |  ├─ types.ts          # 目录/选择 wire 类型
|  |  └─ selection.ts      # 纯函数:selectionFor / sortGroupsForCurrent /
|  |                       #  搜索过滤 / Esc 栈(UI 与测试共用)
|  |- components/
|  |  ├─ ModelSelector.tsx # 触发器 + 菜单壳 + 状态编排
|  |  ├─ RootPane.tsx      # 第一层:模型 / 推理等级
|  |  ├─ ProviderPane.tsx  # 第二层:供应商(搜索 + 失败行)
|  |  ├─ ModelPane.tsx     # 第三层:单供应商模型(搜索 + 复合键)
|  |  ├─ EffortPane.tsx    # 推理等级
|  |  └─ StatusBlock.tsx   # 目录加载/错误横幅
|  |- hooks/
|  |  └─ useKeyboardNavigation.ts  # Esc 栈 + 方向键焦点
|  └─ model-provider.css   # 作用域样式(dshmp- 前缀 + 设计令牌)
|- test/model.test.ts      # node --test 单元测试(纯函数层)
|- lib/                    # 构建产物(宿主伺服 /plugins/<id>/client.js)
|- assets/icon.svg

构建

pnpm install        # 首次:安装 esbuild / typescript(npm 亦可,见下)
pnpm build          # node build.mjs → lib/client.js
pnpm typecheck      # tsc --noEmit
pnpm test           # node --test(无需 DOM,直接跑纯函数层)

构建脚本通过 require.resolve("esbuild") 使用本项目声明的 esbuild devDependency, 不含任何本机硬编码路径,可在任意机器构建。(若用 npm:npm i && npm run build, 提交的 lockfile 为 pnpm 生成,npm 会自行解析。)

产出为 DeepSeek Harness 客户端插件标准格式:

window.__ModuleLoader__.load({ id: "dsh-model-provider", factory: (require) => { ... return module.exports; } });

安装到 Web Profile

正确姿势(v0.1.0 起):本包已声明 dsh.bundle.patch + 自带 cordis.patch.yml, 属于标准 dsh 插件形状(与 dsh-balance-meter / dsh-context 一致)。不要再写成 「无元数据的 bundle」——那会触发启动检查报错: profile bundle "dsh-model-provider" declares no dsh.bundle in its package.json 并循环重启。

  1. 依赖链接进 profile(/data/.dsh/profiles/web/package.json):

    "dependencies": { "dsh-model-provider": "link:/data/opt/dev/dsh-provider-model" }
    "dsh": { "profile": { "bundles": [ ..., "dsh-model-provider" ] } }
    

    (用 dsh 官方 CLI 亦可:dsh plugin --profile web add /data/opt/dev/dsh-provider-model, 它会按 dsh.bundle.patch 声明自动 reconcile 进 bundles。)

  2. pnpm install(materialize link)

  3. 重启 web 主机(client 插件集合变更以重启生效):docker restart deepseek-harness 或等效的 dsh web 重启

  4. 验证:

    curl -s http://127.0.0.1:3080/ | grep -o '"id":"dsh-model-provider"'
    curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3080/plugins/dsh-model-provider/client.js   # 200
    

    仅改 client.js(不加/删插件)时无需重启,重新 build 后刷新页面即可生效。

关闭插件 / 恢复原界面

从 dsh.profile.bundles 移除本包(或卸载插件)并重启 —— 原 ModelSelect 座位位次恢复为唯一 entry,界面还原。

Roadmap

已交付(v0.3.1):

  • v0.3 功能集:三级选择器(主菜单 → Provider → 单 Provider 的 Model 列表)、当前供应商置顶、失败 Provider 可重试行、两级行内搜索、精简的 Model · Provider [· Effort] 触发器、统一默认推理等级
  • 已在 DeepSeek Harness 0.1.1-rc.2 上验证(Slot 组合 / 座位契约 / 目录接口 / 基础组件 / 设计令牌全线未变)
  • peerDependencies 对齐 ^0.1.1-rc.2
  • node --test 单元测试(当前置顶 / 同名模型 / defaultEffort / Esc 栈 / 搜索过滤)

候选:

  • 插件设置页(显示模式:纯分组 / 模型后跟 Provider / 两者;当前模型是否显示 Provider)
  • 默认模型徽标(依赖 host wire 暴露 isDefault 字段)
  • 最近使用 / 收藏 / 模型能力(上下文长度、价格)等展示增强
  • Provider 图标

License

MIT

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →

社区评论

评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。