dsh-plugin-model-provider-readout

August 18, 2026 · View on GitHub

DSH Web 客户端插件:在 composer 工具行右侧、模型选择器按钮正左侧显示 「模型提供方 |」——与右下角模型按钮连读即「模型提供方 | 模型」, 数据与官方选择器同源、实时同步(在模型选择器里切换模型,标签立即跟随)。

  ┌────────────────────────────────────────────────────┐
  │ …          DeepSeek | [deepseek-v4-flash ▾]  (发送)│
  └────────────────────────────────────────────────────┘
                ↑ 本插件的提供方标签

特性

  • 纯增量:挂在 conversation.input.right(list 槽位,工具行右端、模型座位 正左方),不替换、不抢占任何官方 UI。
  • 数据与官方 ModelSelect 完全同一条通路:ui-model-selectionctx.modelDirectories 每会话共享目录,current = { provider, model } 由 Host 上报,选择器切换模型后立即反映。
  • 零运行时依赖:源代码刻意不带运行时 import(React 由宿主注入), lib/ 编译产物可直接作为动态注册代码体使用。
  • 子代理会话自动隐藏(Agent 绑定 RPC 不可用时渲染空)。
  • 目录未就绪/加载失败时渲染空,不打扰界面;错误面由官方选择器承担。

为什么不做成替换右下角模型按钮

conversation.input.modelsingle 槽位、被官方 ModelSelect 占用, 抢占意味着整段重写选择器(下拉、目录加载、selection、effort…),官方 升级即冲突。本插件选择其正左方的可加性槽位 conversation.input.right, 零风险且视觉上直接贴着模型按钮。

目录结构

dsh-plugin-model-provider-readout/
├── src/index.ts              # host 半部(空 apply:让 Loader 行挂上 dsh.client 包)
├── src/client/index.ts       # client 半部(唯一事实来源,标准 client-plugin 形状)
├── lib/index.js              # host 编译产物(已提交)
├── lib/client/index.js       # tsc 中间产物(普通 ESM)
├── lib/client.js             # DSH 静态 client bundle(安装时由 ./client 导出)
├── dynamic/client-body.js    # 动态注册代码体(lib 经 scripts/to-dynamic.mjs 转换)
├── cordis.patch.yml          # 组合补丁:插入 model-provider-readout 行(安装必备)
├── scripts/to-dynamic.mjs    # lib → 动态代码体 转换脚本
├── tsconfig.json             # 严格模式,ES2020,零依赖
├── package.json              # 插件元数据(dsh.bundle.patch + dsh.client.platform=web)
└── README.md / LICENSE

构建

仅需 TypeScript,无任何其他依赖:

npm install --save-dev typescript   # 或复用任意 tsc
pnpm run build                      # tsc + 静态 bundle + 动态代码体
pnpm pack                           # → 可安装 tarball(dsh plugin add 也支持 file: 路径)

lib/ 已提交,克隆后无需构建即可安装使用。

安装到自己的 harness(git 链接,一条命令)

拿到本仓库的 git 链接后,任何人的 DSH 机器都可以让 harness 自己完成 安装与注册:

dsh plugin --profile web add git+https://github.com/<你的用户>/<>.git

内部发生的事:

  1. dsh plugin 在 web profile($DSH_HOME/profiles/web)里跑 pnpm add, 克隆仓库并按 package.jsonname 安装;
  2. 安装成功后自动对账:包声明了 dsh.bundle.patch,即自动追加进 dsh.profile.bundles 层叠(无需手改任何配置);
  3. cordis.patch.yml 把插件行插入组合:model-provider-readout@dsh-external/dsh-plugin-model-provider-readout
  4. 重启 harness(或 web host)后,clientModules 扫描 loader 条目发现 dsh.client 声明,把 lib/client.js 作为 /plugins/.../client.js 挂进页面 —— 标签出现在模型按钮左侧。

重启是唯一需要的手动步骤(clientModules 对插件集合的判定按进程缓存, "plugin-set changes take effect on restart")。重启前本机当前进程不受影响。

零构建:仓库没有 prepare 脚本、lib/ 已提交,pnpm ≥10 不会触发 allowBuilds 审批,安装后无需任何额外命令。

卸载:

dsh plugin --profile web remove @dsh-external/dsh-plugin-model-provider-readout

快速开始(给使用者,免重启的即时方案)

不想重启 harness 时,可以在单个会话里动态注册:

  1. git clone <仓库链接>,打开 dynamic/client-body.js
  2. 在 DSH Web GUI 的会话里把文件内容交给 Agent,说"按动态 Cordis 插件注册这段客户端代码";
  3. 在 UI 批准授权后,提供方标签立即出现在模型按钮左侧。

动态注册随进程存活,重启后需要重新注册;dsh plugin 安装则是持久的。

数据契约(依赖官方包,均已随 dsh web 挂载)

依赖说明
slots槽位注册(conversation.input.right,list,id/order/inject)
sessionssubagentAddress(sessionId) 判断子代理会话
modelDirectoriesui-model-selection 的每会话 ModelDirectorystore + load()

三者缺失时插件保持等待不激活(inject 硬依赖语义)。

License

MIT