@dushayulll/dsh-model-catalog-refresh
v0.2.2
Published
Append-only auto-sync for dsh llm-pi-ai provider catalogs (models.dev + OpenAI /models) with backup and restore. Discovers providers from your settings — no hard-coded provider in JSON.
Maintainers
Readme
@dushayulll/dsh-model-catalog-refresh
纯 host 型 DeepSeek Harness (dsh) 插件:
自动发现用户已经配置在 llm-pi-ai.providers 里的所有模型商,并在 DSH
启动后一次性联网刷新模型目录。插件配置里不写死任何 provider。
追加式(append-only):只往你的模型列表里追加新模型,绝不删减你已有的; 原有条目的字段、顺序全部保持不变。原始配置会在写入前备份,卸载时可恢复。
特性
- 自动发现 — 读取
llm-pi-ai.providers里现存的所有 provider;在 settings 里 新增 model 商,下次 DSH 启动自动纳入。 - 追加式(只增加不减少) — 你现有的
models条目原样不动(字段、顺序), 只追加在线目录里发现的新模型 id。 - 多数据源 — 认识的 provider 走
models.dev(无需凭据,含 context/output); OpenAI 兼容路由现场拉GET {baseURL}/models。 - 已知 provider 内置兜底 — models.dev 不可达时,若 provider 是本插件已知的
(目前为
opencode-go),自动使用其稳定的 OpenAI 兼容/models地址,并在下次 写入时自动补上api/baseURL,用户无需手动改路由。 - 校验安全的追加 — 不在 dsh 内置目录里的模型需要路由级
api/baseURL; 你没有声明时,插件从 models.dev 的 provider 元数据推断(npm客户端 → 线协议、 providerapi→ baseURL),保证写入能通过dsh-llm-pi-ai校验。 - 推理档位可调 — 追加的模型按 models.dev 的
reasoning_options推导reasoningEfforts(显式档位列表优先;否则默认low/medium/high), 让思考等级在 DSH 里可直接调节,而不是被静默关死。 - 输入模态保留 — 来源的
text/image输入模态会保留到追加模型上 (不支持的如video会被安全丢弃),多模态模型既能声明输入,又不会让 dsh 校验失败。 - 一次性,非轮询 — 启动后刷新一次,之后安静。
- 可逆 — 首次写入前备份原始配置;卸载时自动恢复(尽力而为),或用独立的
restore.mjs脚本兜底恢复(保证)。
解决的问题
dsh 的 llm-pi-ai.providers.* 模型列表是纯静态的:dsh 只读 llm-pi-ai
配置节里写的东西,从不向 provider 查询它实际提供哪些模型。因此某个已配置平台
新上线的模型(例如 opencode go 的 Muse Spark 1.2 Contributor)不会出现在
dsh 里,除非手动写进 settings.yaml。本插件把这个"手动写入"自动化。
工作机制
DSH 启动后,插件等待 startupDelayMs(默认 5s),然后执行一次刷新:
- 从设置 seam 读取
llm-pi-ai.providers——所有你已配置的模型商。 - 每个 provider 自动选择数据源:
- models.dev 认识该 provider → 拉
https://models.dev/api.json对应节点 (无需凭据,含 context/output 容量); - 否则该 provider 有 OpenAI 兼容
baseURL→ 现场GET {baseURL}/models(有apiKeyEnv就带上); - 否则该 provider 是带内置兜底的已知 provider(当前为
opencode-go)→ 自动使用其稳定的 OpenAI 兼容/models地址,并在写入时补上api/baseURL; - 否则 → 跳过,不动该路由。
- models.dev 认识该 provider → 拉
- 追加式合并:你现有的
models条目原样不动(字段、顺序全部保持), 只把在线目录里新发现的 id 追加到末尾(在线目录内部的重复 id 只取第一个)。 - 为追加模型补全元数据,让 dsh 能接受并正常服务:
- 按 models.dev 的
reasoning_options推导reasoningEfforts(显式档位列表 优先;否则默认low/medium/high),思考等级可在 DSH 里调节; - 来源
modalities.input里的text/image输入模态会保留到追加模型上; 其余不支持的值(如video)会被丢弃,避免写入校验失败; - 未声明路由级
api/baseURL时,从 models.dev provider 条目推断 (npm客户端 → 线协议、providerapi→ baseURL)——内置目录之外的模型必需。
- 按 models.dev 的
- 通过
llm-pi-ai设置命名空间写入合并后的列表。
dsh-llm-pi-ai 每次请求都会重读配置,因此刷新后无需重启,新模型下次请求即可选。
新增的 provider 会在下次 DSH 启动时自动被纳入。
不是轮询器:只在 DSH 启动后刷一次,之后保持安静。
备份与恢复
插件在首次写入前会备份你的原始 models 列表,保证可以回到插件安装前的状态。
备份内容
每个被更新的 provider 会记录(默认 $DSH_HOME/model-catalog-refresh-backup.json):
hadExplicit:你原来是否有models字段(vs 使用内置目录);original:你的原始模型列表;lastWritten:插件最近一次写入的完整列表(用于检测你是否手动编辑过)。
自动恢复(尽力而为)
当 restoreOnDispose: true(默认)时,插件在销毁时(卸载/主机关闭)会尝试恢复
原始配置。只有当当前列表与 lastWritten 一致时才恢复——如果你在插件写入后手动
编辑过,自动恢复会跳过以避免覆盖你的修改。
注意:主机正常关闭时也会触发销毁;由于插件每次启动都会重新刷新,DSH 运行期间 目录始终最新,停止后回到原始——你不会感知到这个循环。
脚本兜底恢复(保证可恢复)
pnpm restore # 或:node scripts/restore.mjs
node scripts/restore.mjs --force # 即使手动编辑过也强制恢复脚本读取备份文件,用 yaml 包做 round-trip 解析,直接把原始配置写回 settings.yaml。
幂等——运行两次不会有副作用。只有当所有 provider 都恢复成功时才删除备份文件;若有
跳过则保留,以便用 --force 重试。
配置项(均可选,不写死 provider)
| 字段 | 默认 | 说明 |
| --- | --- | --- |
| modelsUrl | https://models.dev/api.json | models.dev 风格目录端点 |
| startupDelayMs | 5000 | DSH 启动后延迟多少毫秒执行一次性刷新 |
| timeoutMs | 30000 | 网络超时 |
| skipUnavailable | true | 跳过 models.dev 标记 available: false 的模型 |
| maxModels | 2000 | 每个 provider 的存储上限(安全阀)——只丢弃超额的追加条目,绝不截断你已有的条目(即使已超过上限) |
| refreshOpenAiCompatible | true | 对自建 OpenAI 兼容路由做现场 /models 刷新 |
| backupPath | $DSH_HOME/model-catalog-refresh-backup.json | 备份文件路径 |
| restoreOnDispose | true | 销毁时自动恢复原始配置 |
| proxyUrl | 空(自动探测) | 目录抓取代理。Node 的 fetch 不读 Windows 系统代理,本机走代理时请设为如 http://127.0.0.1:7890;留空则自动读 HTTPS_PROXY/HTTP_PROXY 环境变量;"direct" 强制直连 |
安装
[!NOTE] 使用前请确保已安装 DeepSeek Harness。
npm
dsh plugin --profile web add @dushayulll/dsh-model-catalog-refresh从源码构建
git clone https://github.com/dushayulll/dsh-model-catalog-refresh.git
cd dsh-model-catalog-refresh
pnpm install
pnpm build
dsh plugin --profile web add .修改源码后请重新执行 pnpm build。本地安装会继续链接到当前源码目录。
运行时注入(免重启)
开发或测试时,可跳过完整 profile 安装,直接注入本地包:
dev_inject_plugin → <本项目绝对路径>验证
检查组合配置、重启 DSH,确认模型目录已刷新:
dsh --profile web --dump-config
dsh webDSH 启动后,settings.yaml 中每个已配置 provider 应出现追加的新模型。
兼容性
- DSH / dsh-core:
0.1.0-rc.x(peer 依赖@deepseek-ai/cordis、@deepseek-ai/dsh-settings、@deepseek-ai/dsh-timeout) - Node.js:
^22.19.0 || >=24 - 形态:ESM、strict TypeScript
开发
pnpm install
pnpm build # tsc → lib/
pnpm test # vitest
pnpm verify # typecheck + test + verify:pack验证
下次 DSH 启动后,settings.yaml 中每个已配置 provider 应出现追加的新模型,例如:
llm-pi-ai:
providers:
opencode-go:
apiKeyEnv: OPENCODE_GO_API_KEY
models:
- id: deepseek-v4-flash # ← 原始条目,保持不动
name: DeepSeek V4 Flash
contextWindow: 1000000
maxTokens: 384000
- id: muse-spark-1.2-contributor # ← 自动追加
name: Muse Spark 1.2 Contributor
contextWindow: 1048576
maxTokens: 131072
input: [text, image] # ← 输入模态(不支持的一律丢弃)
reasoningEfforts: # ← 思考等级变为可调
off: null
minimal: minimal
low: low
medium: medium
high: high
xhigh: xhigh也可以用一份临时的 settings.yaml + 备份文件 dry-run 一遍恢复流程,确认行为符合预期。
卸载
dev_uninject_plugin(匹配包名@dushayulll/dsh-model-catalog-refresh)。- 如果自动恢复没有执行(比如进程被杀),运行:
pnpm restore
安全
- 不存储凭据:插件只读取
apiKeyEnv名称,在请求时经 dsh 的 credentials seam 或环境变量解析。 package.json的files白名单 +verify:pack确保源码、测试与本地数据不会被打进 发布的包。
