dsh-model-metadata
DSH 插件:按模型名在运行时查一次目录,把你在自定义网关上声明的模型该有的能力元数据补上——上下文长度、输出上限、推理等级、能否看图;插件自己不写你的设置文档。
安装
dsh plugin --profile web add dsh-model-metadata
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
dsh-model-metadata




已发布到 npm(dsh-model-metadata),源码在 github.com/pgjh/dsh-model-metadata。
English — Fills in the missing capability metadata of models you declared yourself on a
custom gateway (context window, output cap, reasoning levels, can it see images). Every
model is looked up by name at runtime; no DSH file is touched, and your settings
document changes only when you press 写入 yourself. The fused controls follow the Settings
page's language (Simplified Chinese, English).
一句话:你在 DSH 里接自己的网关时,模型往往只写了个名字。这个插件按模型名去目录里查一次,把上下文长度、输出上限、推理等级、能不能看图补上。
这是怎么回事
接自定义网关时,设置里一般只写 id(DSH 0.2.1 起存在当前 profile 的配置里,旧版本是 settings.yaml):
llm-pi-ai:
providers:
my-gateway: # 你给这个网关起的名字
api: openai-responses
baseURL: https://gateway.example/v1
models:
- id: my-gateway/gpt-4o
name: gpt-4o
- id: my-gateway/claude-sonnet-4-5
name: claude-sonnet-4-5
问题是 DSH 查元数据的方式:它拿网关名 + 模型 id 原样去内置目录里对,而 my-gateway 当然不在目录里。于是这两个模型被当成"什么都不支持":
- 上下文按 256K 算 → 长对话被提前压缩,或者反过来爆掉;
- 没有推理等级 → 模型选择器写着「当前模型未提供推理等级。」;
- 只能收文字 → 发图片直接被拒。
但 gpt-4o、claude-sonnet-4-5 这些名字,目录里其实都有。差的只是按名字查一次。
插件做的事
1. 按模型名查:取 id 里最后一个 / 后面的名字(my-gateway/gpt-4o → gpt-4o),按"官方路由 → 内置目录 → opencode → models.dev"的顺序查(详见下面「哪些名字认得出」),查到之后,就把这个模型该有的上下文长度、输出上限、推理等级、图片支持补上去。名字的写法差一点也没关系:deepseek-v41-flash、deepseek-v4.1-flash、"DeepSeek-V41-Flash" 算同一个名字,显示名和 -exp 之类的后缀也能对上。
2. 只补缺的:你在设置里亲手写过的字段,它不动。反过来,它读不到这些声明时也绝不猜,并在日志里说明原因(enrichment off (…)):这时候"你有没有声明"是它看不见的事实,而"借用"会把你亲手钉住的 64K 覆盖成目录里的 272K。声明从哪来跟 DSH 版本走:0.2.1 起是当前 profile 的配置(通过 DSH 的 settings 服务读取,settings.yaml 已被 DSH 自己改名成 settings.yaml.imported);更早的版本读 $DSH_HOME/settings.yaml。旧文件不存在、没有 YAML 解析器、或者你正编辑到一半 YAML 语法坏了,都算"读不到"。
3. 界面上给你两个开关:推理等级、视觉。DSH 官方界面没有这两个控件,这里是唯一的图形入口;改完点「写入」固定下来,不点就一直跟着目录走。写入是按行的:双击只写一次,也不会把别的行还没写入的改动丢掉;只读的部署会直接说明写不了。这两个控件和结论行跟随设置页的语言(简体中文 / English)。
4. 目录数据自己更新:启动、打开界面、以及按天(每小时检查一次是否过期)各更新一次 models.dev,所以新模型不用你手动管;数据没变时只确认一次,不重新下载。
安装
装插件用的是 pnpm(和 npm 一个意思),先确认有:
corepack enable pnpm # Node 自带;或者 npm i -g pnpm
然后三种方式选一种(web 是浏览器版的 profile 名;桌面版换成 desktop):
方式 · 命令
npm 包(推荐) · dsh plugin --profile web add dsh-model-metadata
GitHub 仓库 · dsh plugin --profile web add github:pgjh/dsh-model-metadata
本地源码 · dsh plugin --profile web add /path/to/checkout
桌面版(npm / GitHub / 本地源码同上,只改 profile) · dsh plugin --profile desktop add …
命令会把包装好,并自动挂进 DSH 的插件列表,不用你手改配置文件。装完重启一次(用你启动 dsh 的方式:直接跑 dsh web 的就重跑一遍;交给 systemd 的就 systemctl --user restart <你的服务名>;Docker 里就重启容器)。
桌面版(DeepSeek Harness Desktop)是另一个 profile。 它不读webprofile 的插件,所以只按上面的--profile web装,浏览器里有控件、桌面版没有——这不是插件没生效,而是装错了地方。桌面版的 profile 叫desktop,由 Electron 应用独占:先用应用菜单里的 Manage dsh Command… 装好它自带的dsh命令,完全退出桌面版,再执行dsh plugin --profile desktop add dsh-model-metadata(更新时把add换成update),然后重新打开桌面版。用 npm 全局安装的dsh改不了这个 profile;必须用桌面版装出来的那条命令。
之后记住这条界线:界面上的改动刷新页面就行,逻辑上的改动要重启。
还有一种不用 pnpm 的"复制文件"装法:node install-plugin.mjs --apply。这个文件也在 npm 包里(装好之后在包的目录里一样能跑),它不经过dsh plugin。它写在 DSH home 的cordis.patch.yml里,对所有 profile 生效,所以别和上面三种混用,否则插件会被装两遍。
用法
界面:设置 → 模型 → 你的网关卡片 → 编辑 → 自定义设置 → 模型目录
每个模型行里(名称下面、"容量"上面)会多出两行:
- 推理等级:菜单里挑一个(跟随自动匹配 / 关闭推理 / 低·中·高 / 自定义…)。选「自定义…」可以填
low, high, max,写法和设置里一样。 - 视觉:跟随自动匹配 / 开启(能看图)/ 关闭(只收文字)。
- 下面那行是结论,告诉你查到了什么:
自动匹配:anthropic · 200K / 输出 64K · 有推理等级 · 视觉
写「无匹配」就是这个名字哪里的目录都没有,需要你自己填。
- 新加的行自己会出结论:卡片开着时点「添加模型」、输入完 id、或保存后重新打开这张卡,插件都会重新问一次目录,不用关掉设置再进来(更不用重启 dsh)。
- 改动之后才会出现「写入」按钮:只写这一行的两个字段,其它内容原样保留。写入是按行做的——双击只写一次,写完那一行仍留着写入结果,别的行还没写入的改动也不会跟着消失。
- 只读的部署(设置页自己就不让改)点「写入」会得到「这张卡片是只读的,无法写入」,而不是一个看不出原因的失败。
- 控件和结论行的文字跟随设置页的语言:设置页是简体中文就用中文,是 English 就用英文。
容量为什么不在这个界面里改
官方那一行的「容量」折叠已经管上下文和输出上限了,再开两个框只会让你纠结哪个算数。插件只告诉你这两个值的真实来源(你自己声明的 → 目录里查到的 → 网关默认);而官方输入框里的灰字永远只是网关默认值(比如 256K),认不出 gpt-4o 其实是 128K。要改就用同一行的「容量」。
目录数据什么时候更新
时机 · 说明
启动 dsh · 默认检查一次;本地数据不到 15 分钟就跳过(DSH_PI_AI_CATALOG_REFRESH_ON_START=stale 改成按天判断,off 则不在启动时检查)
打开 dsh 界面 · 数据超过 6 小时就后台更新(DSH_PI_AI_CATALOG_REFRESH_OPEN_HOURS,0 = 不按这个时机更新)。这个时机是界面数据路由被请求时触发的,所以 DSH_PI_AI_CATALOG_PANEL=off 会让它一起消失(见下表)
按天(进程常驻时的那条路) · 插件每小时看一次本地数据的年龄,超过 24 小时(DSH_PI_AI_CATALOG_REFRESH)就后台更新;0 = 关掉所有自动更新(总开关)。这条是给"一直不重启、也不打开设置页"的部署准备的:以前没有它,这种进程会一直用最初那份数据
手动 · node lib/refresh-snapshot.mjs,立刻生效、不用重启(--help 列出 --out / --url / --timeout-ms / --settings;--settings 会顺带打印"你配的模型里这份数据覆盖到了哪些")
一次检查不一定等于一次下载:请求会带上本地数据里存的 ETag,models.dev 回一个没有内容的 304 就说明数据没变——这时只把本地文件的时间戳重新盖一次,不重新下载。下载失败也不会被反复重试:自动触发的两次尝试之间至少隔 5 分钟,所以网络不通时反复打开界面不会变成一连串下载请求(手动跑 refresh-snapshot.mjs 不受这条限制)。
数据存在 $DSH_HOME/models-dev-snapshot.json(2026-11 时约 1.4 MB、8926 行,随 models.dev 数据量增长;机器上只此一份,所有 profile 共用)。放这里是有意的:更新插件会替换整个插件目录,数据若跟着插件走就会被一起丢掉、下次启动还得重下一遍;放在 DSH home 里,更新插件完全不会碰它,也不用等下载。装好第一次启动时如果还没有数据,它会自己下载一份(约 6 MB,几秒钟)。想换位置就用 DSH_PI_AI_CATALOG_SNAPSHOT 指到别处。
开关(环境变量,按需)
变量 · 默认 · 取值 / 作用
DSH_PI_AI_CATALOG_FALLBACK · full · full = 容量 + 推理等级 + 图片都补;context = 容量和图片照补,推理那一半关掉(等价于把 DSH_PI_AI_CATALOG_FALLBACK_LEVELS 设成 off;图片要一起关就用 DSH_PI_AI_CATALOG_FALLBACK_INPUT=off);off = 插件完全不干活
DSH_PI_AI_CATALOG_FALLBACK_LEVELS · on · on = 任何匹配到的来源都能声明推理等级;bundled = 只有 DSH 自带目录(pi-ai 目录、官方 DeepSeek 路由自己的目录)能,models.dev 只补容量;`
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:7,最后更新 2026-11-04