dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DSH 插件:自定义模型/提供方顺序——侧边栏拖拽排序,宿主的模型列表按这份顺序返回;顺序写进 settings.yaml 前自动备份
自定义模型 / 提供方的排列顺序。宿主的模型选择列表按适配器注册顺序排,常用的模型 常常排在后面;这个插件让你在模型设置页里拖一下,把它顶到前面去。
两个入口(2026-10-15 第二轮定型):
settings.models.provider-card,
key=llm-deepseek):内置 DeepSeek 家族维持卡片内拖拽。llm-pi-ai 那张卡片格已被 web-all 0.4.6 的「模型能力」面板认领
(keyed 槽一格一主,上游契约如此)。0.3.0 曾把 pi-ai 入口挪到模型页底部 footer 区,
实测没人滚到那儿、等于没有,第二轮改侧边栏页 —— 不指望上游,动自己的代码。展开后是分组后的模型列表(百炼一个路由上百个模型,按 qwen/glm/kimi 家族分段各自折叠), 按住行拖动即写盘(保存制),「恢复默认」回到宿主原顺序。
models 数组的物理顺序(POST /settings-order 文本块级重排)。
~/.dsh/model-order.json 是 0.1.x 时代的遗留文件(读钩子 09-10 已停用,仅剩状态展示兼容)。agent-default-model 声明的那个模型写回时强制钉回原位,怎么拖都不动它。llm-pi-ai 的 profile 层(web↔desktop),
两边宿主各自 patchReload: live 盯自己的文件,一次拖动两端实时跟随;config: { mirror: false } 可关。ctx.llm 的实例属性上包一层,让这三个方法按这份顺序返回:
listProviders()、listConfigurableProviders()、listModels(provider)。
排序是稳定排序:没被点过名的条目保持原来的相对位置,所以只调两个不会搅乱别的。Reflect.get(活实例, 'listProviders')
(dsh-api-gateway 的 prepareInvocation),own property 优先,所以这一处改动
同时覆盖直调方与远端两条路。模型选择对话框走的 session/modelCatalog 链内部
同步调 ctx.llm.listProviders()、异步调 ctx.llm.listModels(),都在这条路上。listProviders / listConfigurableProviders 的替换必须是同步函数。
宿主 buildModelCatalog 同步调用它,返回 Promise 会在紧接着的
providers.map(...) 上炸掉,模型选择对话框直接打不开。listProviders() 收 0 个,
listModels(provider) 收 1 个。GET /dsh-model-priority/state.json —— 目录快照 + 当前顺序 + 挂钩状态GET /dsh-model-priority/provider-models?route=<route> —— 某路由当前的模型 id 顺序GET /dsh-model-priority/suggest?route=<route>&mode=capability|cheap|quota —— 建议顺序PUT /dsh-model-priority/order.json —— 保存顺序文件({"reset":true} 清空)POST /dsh-model-priority/settings-order —— 按给定顺序重排当前生效真源里该提供方的 models
(0.1.5 线是 ~/.dsh/settings.yaml;0.1.7 线起是 profile 用户层 ~/.dsh/profiles/<p>/cordis.patch.yml)这些路由注册在 ctx.webServer 上,是裸路由:宿主的鉴权只覆盖 client-connection
注册的通道与首页。所以本包自己判来源(Host 必须是 loopback 或宿主登记的权威、
sec-fetch-site 不是 cross-site、有 Origin 时主机名要与 Host 一致),
浏览器里任意站点的跨域请求一律 403,响应也不再带 Access-Control-Allow-Origin。
本机 shell 里 curl http://127.0.0.1:3080/dsh-model-priority/state.json 照常能用。
| 文件 | 什么时候 | 怎么收拾 |
|---|---|---|
~/.dsh/model-order.json | 每次点「保存」 | 删掉就回默认 |
~/.dsh/settings.yaml(0.1.5 线) | 点「保存」并同步宿主时 | 写之前先备份成 settings.yaml.bak-<ISO 时间戳>(内容没变就不写也不备份;已有备份存着同一份写前状态时复用它;默认最多留最近 5 份,只清理本插件自己命名的 <ISO> 形状,手工放的备份一律不碰);只重排对应提供方 models 数组的顺序,其它键一个都不动 |
~/.dsh/profiles/<p>/cordis.patch.yml(0.1.7 线起的真源) | 同上 | 写之前先备份成 cordis.patch.yml.bak-<ISO 时间戳>(同一条备份策略:未变不写、同内容复用、默认留最近 5 份、只清自己命名的);只动对应提供方 models 的那几行,块外逐行必须一字不变。落盘前后各做一次校验:条目集合未增删、总行数不变、区域外逐行一致、重读一遍顺序符合要求 —— 任一道不过就整次拒绝、一个字节都不写 |
~/.dsh/model-priority-proxy.json | 只有启用下面那个轮换代理才会创建 | 删掉即停用 |
为什么要写这份配置:宿主是拿 models 数组的顺序来渲染模型列表的(设置页与选择器都看它)。
只在读的时候排序,会出现「设置页一个顺序、模型选择器另一个顺序」,两套顺序来源必然打架。所以写盘这一边是刻意的 ——
也正因为如此,写之前必须留一份能回到写前状态的备份 —— 但只留有用的那份,不刷串。0.1.7 把配置从 settings.yaml 搬进了 profile 用户层(老文件只留 settings.yaml.imported),
本包两代形状都认:读到的提供方与模型顺序在两边完全一致,这一点有回归测试盯着(test/settings-source.test.mjs)。
dsh plugin --profile web add "<本仓目录,或 git 地址>"
dsh plugin --profile web remove dsh-model-priority
面板挂在上游的 settings.models.provider-card 席位(仅 llm-deepseek 家族)与
dsh-better-sidebar 的 registerTab(pi-ai 家族的「模型排序」页,2026-10-15 第二轮起)。
拿不到 slots 时卡片格不挂;没装 better-sidebar 时侧边栏页 warn 跳过、卡片格照常——
那几条 HTTP 路由任何情况下都可用。
装完要重启 dsh web:服务端半边(注册路由、挂钩)与浏览器侧半边(进 boot 图的 combo) 都是启动时装配的,只有重启才生效。顺序文件是每次调用现读的,改它不用重启。
npm test
五个脚本,合计 54 项,都不启动 dsh、不碰 3080 端口:
test/selftest.mjs —— 数据层:顺序文件的读写与清洗、稳定排序的边界
(名单里有不存在的 id、缺 id、空名单、原数组不被就地改动)。test/server-routes.mjs —— 服务端半边端到端:拿假 ctx(假 webServer + 假 llm)
把八条路由真跑一遍,验状态码、排序真的作用到 listProviders / listModels /
listConfigurableProviders、坏 body 回 400、不支持的方法回 405、
同步契约、重复 apply 不套第二层挂钩,以及信任栅栏的那五条
(跨站 403、DNS 重绑定 403、宿主登记的权威放行、响应不带跨域头、proxy-status 不含 token)。test/client-smoke.mjs —— 浏览器侧半边:用假 window.__ModuleLoader__ 与假 react
把 bundle 跑一遍,验模块 id、只 require react、注册的描述符字段、icon 是内联 svg。test/settings-source.test.mjs(5 项)—— 配置真源:0.1.5 的 settings.yaml 与 0.1.7 的 profile 用户层
cordis.patch.yml 两代形状解析结果必须一致;写回只动 models 块、块外逐行不变、找不到提供方就一个字节不落。test/client-failure-state.test.mjs(3 项)—— 读侧失败态:provider-models 被拒或回 ok:false 时,
卡片标题必须落回「读取失败」(0.2.2 之前会永远停在「读取中…」,因为错误正文只在展开后才渲染)。ctx.llm 真的暴露上述方法的宿主版本上生效;挂不上时 state.json 的
hook.ok 会是 false 并带上原因,页面顶部会把原因显示出来,顺序文件仍然可编辑。llm-pi-ai 家族);宿主内置的 DeepSeek 卡片里这块显示为只读,
那份模型清单不在本机配置真源里,插件不碰。读侧挂住 10s 或报错时标题写「读取失败」,悬停看原因。models 数组(0.1.5 线是 ~/.dsh/settings.yaml,0.1.7 线起是 ~/.dsh/profiles/<p>/cordis.patch.yml;写前都自动备份,见上)。卸载后 model-order.json 与代理配置留在 ~/.dsh 下,手动删。registrationFacts 会对 provider 做 sort 来判断"是否变化",单纯调键序不触发
replace,运行中不会立刻生效,而且被 replace 的那批路由会被挪到 Map 末尾。
要固定顺序就用这个插件。dsh-model-router 一类,用量统计看 dsh-provider-usage 一类),
塞进一个插件里最容易互相打架。包内另有一个小的本机转发层:把某个 provider 的 baseURL 指到本插件的 rotate 端点,
它会在 .credentials.yaml 里的多把 key 之间依次试(429 / 额度尽那类响应才换)。
~/.dsh/model-priority-proxy.json),不知道 token 一律 403 ——
插件路由不走浏览器鉴权,不设这道门等于本机任何进程都能拿你的密钥刷额度;dsh-model-router 那类插件比过再决定用哪个。GET /dsh-model-priority/proxy-status 只报密钥数量、冷却与配置文件位置,
不回显 token(要手工配 baseURL 就自己看 ~/.dsh/model-priority-proxy.json)。