🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

模型开关与思考强度 Salty-Mocha/dsh-model-controls-mac

DeepSeek 客户端
Salty-Mocha14 天前有提交已提供中文文档扫描:未发现敏感能力兼容 / 相关生态

按模型和供应商启停模型,并为第三方供应商配置思考强度档位

30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/17 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/Salty-Mocha/dsh-model-controls-mac.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 14 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🟢 扫描:未发现敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。

扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

按模型、按服务商分别开关,外加第三方思考强度规则,适用于 DeepSeek Harness(DSH)桌面应用。非官方,不改动 app.asar。

README

由 DeepSeek 最新模型翻译生成
dsh-model-controls — 模型开关 + 思考强度 平台支持 | 平台 | 状态 | | macOS | ✅ 在 macOS 上开发、安装并验证(DSH 桌面版,Electron)。这是参考平台。 | | Windows | ⚠️ 已适配但未实测。工具改用 os.homedir() 解析主目录(即 %USERPROFILE%\.dsh\profiles\desktop),临时目录用 os.tmpdir(),并自动探测 %LOCALAPPDATA%\Programs\… / %ProgramFiles% 下常见的 app.asar 位置;探测不到就用 --asar <路径> 显式指定。 | | Linux | ⚠️ 已适配但未实测。app.asar 候选位置包括 /opt、/usr/lib、/usr/share、~/.local/share;都不匹配时用 --asar <路径>。 | 插件本体(lib/)是跑在 DSH 自带运行时里的普通 JavaScript,与平台无关;与平台相关的只有工具里的路径探测,所以工具都支持 --profile 和 --asar 覆盖。
展开完整文档(README 剩余 1 节)
dsh-model-controls — 模型开关 + 思考强度

平台支持

| 平台 | 状态 |
| macOS | ✅ 在 macOS 上开发、安装并验证(DSH 桌面版,Electron)。这是参考平台。 |
| Windows | ⚠️ 已适配但未实测。工具改用 os.homedir() 解析主目录(即 %USERPROFILE%\.dsh\profiles\desktop),临时目录用 os.tmpdir(),并自动探测 %LOCALAPPDATA%\Programs\… / %ProgramFiles% 下常见的 app.asar 位置;探测不到就用 --asar <路径> 显式指定。 |
| Linux | ⚠️ 已适配但未实测。app.asar 候选位置包括 /opt、/usr/lib、/usr/share、~/.local/share;都不匹配时用 --asar <路径>。 |

插件本体(lib/)是跑在 DSH 自带运行时里的普通 JavaScript,与平台无关;与平台相关的只有工具里的路径探测,所以工具都支持 --profile 和 --asar 覆盖。客户端半是普通 JavaScript;真正可能随 DSH 版本变化的是它用到的内部接缝(modelCatalog、configForms、settings.models.provider-card 插槽)。

给 DSH 的 设置 → 模型 页面加上「每个模型一个开关、每个供应商一个总开关」:停用后该模型不会再出现在输入框右下角的模型选择器(以及 /model 弹窗)里,配置完整保留,随时可重新启用。

同时给第三方(自定义 baseURL)供应商补上「思考强度」:按「模型 ID / API 协议 / baseURL」正则声明档位与线上映射,规则只写回用户没覆盖过的字段(详见下面的「思考强度(规则层写回)」)。

现在长这样

开关面板挂在 设置 → 模型 每个供应商卡片里:

┌ 设置 → 模型 ─────────────────────────────────────────────────────┐ │ myrouter-ds [自定义] ● [编辑] [删除] │ │ ┌───────────────────────────────────────────────────────────┐ │ │ │ API 密钥 / 自定义设置(显示名称、API 地址、API 协议…) │ │ │ │ ───────────────────────────────────────────────────── │ │ │ │ 模型开关 已启用 1 / 2 个模型 [●━] │ │ │ │ deepseek-v4.1-flash [●━] │ │ │ │ glm-5.3-flash [━○] │ │ │ └───────────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────────┘

- 位置:插件客户端半注册进模型页自己的 settings.models.provider-card 插槽;模型页本体(编译后的页面包)不动。
- 供应商总开关:一键启用/停用该供应商下所有模型。
- 每个模型一行开关:关掉后该模型不再出现在选择器里,配置完整保留。
- 取舍:模型行没有扩展插槽,所以开关在卡片内的面板里,不能再贴到每个模型行内。

两个组成部分

| 部分 | 位置 | 作用 |
| bundle @local/dsh-model-toggle | profile 清单依赖(link:)+ dsh.profile.bundles | 一个包、两个半。清单依赖是它出现在「设置 → 插件」、由插件管理器启停的原因。 |
| host 半 lib/index.js | 同包 | 拥有设置命名空间 model-toggle(disabled: ["provider/model"],volatile,写入 profile 的 cordis.patch.yml);窄包装 sessionController.modelCatalog(),把停用模型从模型选择器目录里剔除;并跑思考强度规则层。 |
| client 半 lib/client.js | 同包,dsh.client + exports["./client"] | window.__ModuleLoader__ 形式的 bundle,注册进 settings.models.provider-card;用 ctx.configForms.get("model-toggle") 读写停用集合,用 configForms.describe() 读每个供应商的 models;只在命名空间被服务时注册,插件停用即无痕。 |
| bundle patch cordis.patch.yml | 同包 | 插入 model-toggle 行;profile 自己的 cordis.patch.yml 只保留设置覆盖。 |

因为 bundle 层在进程启动时组装、客户端模块元数据也在进程内缓存,安装或改客户端代码后需要重启一次 DSH;之后在「设置 → 插件」里启停是热生效的。app.asar 不动,签名与 ElectronAsarIntegrity 保持有效。

思考强度(规则层写回)

问题:第三方供应商的模型在 DSH 里没有强度可选,因为目录元数据来自适配器,而第三方模型没有声明 reasoningEfforts。

做法(对齐 ZCode 的分层规则,但用 DSH 自己的机制,见 docs/design-notes.md §八/§九):规则匹配后,把 pi-ai 原生的 reasoningEfforts / compat 写回 llm-pi-ai.providers.<供应商>.models[]。

- pi-ai 本来就用这个字段同时决定「目录里显示哪些档位」和「请求里发什么值 / 发到哪个字段」,所以界面和请求天然一致,而且写进 cordis.patch.yml 后重启仍在。
- 不拦请求、不包 resolveModelInfo、不改 pi-ai 库。

配置

cordis.patch.yml 里 model-toggle 那一行的 config rules: # 按顺序求值,后面的规则逐字段覆盖前面的
- match: { provider: "^myrouter-grok$" }
levels: [off, low, medium, high]
map: { off: null, low: low, medium: medium, high: high }
- match: { baseUrl: "myrouter-anthropic\\.com" } # 命中供应商站点
levels: [off, high]
map: { off: null, high: high } # off=不发任何字段;high=发 "high"
compat: { thinkingFormat: deepseek } # 可选:钉住线上字段家族
overrides: # 单模型规格,优先级最高(下一步的界面会写这里)
"myrouter/deepseek-v4.1-flash": { levels: [off, medium], map: { off: null, medium: medium } }
fallback: false # 未命中任何规则的模型怎么办;默认 false = 不给强度行

- match:provider / model / api / baseUrl,都是正则,全部满足才命中;不写就是不限制。
- levels + map:map 里没写的档位按同名映射,off 默认映射到 null(= 不发)。也可以直接写 efforts: { off: null, high: high }。
- compat:可选,按键合并;可用项就是适配器暴露的那些(thinkingFormat、supportsReasoningEffort、supportsThinkingTokenBudget、thinkingTokenBudgetField、maxTokensField …),写错协议不接受会由 llm-pi-ai 明确报错。
- fallback: true 等价于两档兜底 { levels: [off, high], map: { off: null, high: high } }。

注意:ZCode 的 .* 兜底是「显示 Off/On 但什么都不发」的占位符(map: "{}")。DSH 里没法表达这种惰性档位(非 off 档必须写明发什么值),所以 fallback 默认关闭——没写规则的陌生模型就是没有强度行。要占位效果可以显式写:

fallback: { levels: [off, high], map: { off: null, high: high }, compat: { supportsReasoningEffort: false } }
(supportsReasoningEffort 只有 openai-completions 协议接受;openai-responses / anthropic-messages 没有等价开关。)

谁拥有哪个字段(「手动改过的就不再跟规则」)

规则的产物写进 llm-pi-ai 的配置层,和用户在模型页里的修改是同一层,所以插件在 model-toggle.managed 里记下「这个字段是我写的、写的是什么」:

- 用户层里没有该字段、插件也没写过 → 规则填。
- 用户层里的值等于插件上次写的 → 还是插件的,规则变化时继续跟着更新。
- 用户层里的值不等于插件写的(用户手改过)→ 释放该字段,规则以后不再碰它(对齐 ZCode 的 "When you manually change a setting, that setting becomes manually managed")。
- 插件写过的值被删掉 → 同样视为手改,释放。
- 规则不再声明某字段(比如规则被删了)→ 插件清掉自己填的值,且不留所有权记录,之后加回规则可以重新接管。

compat 按键判定归属:模型页回写时会把 schema 默认值(chatTemplateKwargs、chatTemplateArgs 等)一起带回来,这些额外键不算用户手改,规则仍会继续管理自己那几个键。

已验证

- 纯逻辑:node tools/test-rules.mjs — 55/55(匹配、分层覆盖、档位校验、所有权与释放、compat 键级归属、幂等)。
- 端到端:node --expose-internals tools/verify-rules.mjs — 17/17。它自己搭一个隔离 profile(/tmp/dsh-test/rules,结构复刻真实 profile:条目由 insert 层挂载、profile patch 作为用户层)并启动打包运行时,覆盖:规则写回落到用户配置层、目录里出现 reasoning.efforts、陌生模型没有强度行、第二次读目录不重写、规则改动会更新自己拥有的字段、用户手改的值不被覆盖且被记为 released、fallback 只作用于未释放的模型、停用过滤不受影响、重启后全部保持。
需要磁盘上存在从 app.asar 抽出的运行时(默认系统临时目录下的 dsh-test/runtime2,可用 DSH_TEST_RUNTIME 覆盖;先用 node tools/extract-runtime.mjs 生成)。
- 安装器:node tools/test-manage.mjs — 14/14(临时 profile 上验证 link 依赖 + bundle 选择 + 保留已保存设置 + 幂等 + uninstall 干净)。
- 运行时抽取:node tools/extract-runtime.mjs —— 只读地从打包 app 里把运行时树复制到临时目录(约 317 MiB),供下面两个端到端脚本使用;--asar / --out / --only / --list 可控,绝不回写 app.asar。
- 请求体预演:node --expose-internals tools/probe-request-body.mjs <patch> [档位] — 离线启动真实供应商配置、把 fetch 换成桩,打印每个模型在「未选档」与「选了某档」时实际会发出去的 JSON。不出网、用假 key。加规则前先跑一遍,就能看出规则会不会改变默认请求体。
- 旧的整页覆盖路线(patch-page.mjs)已弃用,仅保留用于回档或对比。

预演与回档

关键结论(离线抓真实请求体验证过):在 openai-completions 路由上,加规则本身是惰性的 —— 没选档时请求体与加规则前逐字节相同,只有选了档才多一个 reasoning_effort。但在 openai-responses 路由上不是:只要模型声明了档位,pi-ai 在没选档时也会发 reasoning: { effort: "none" }(判据是 thinkingLevelMap.off !== null,而 DSH 的 off: null 会被解析成"键缺席")。所以 responses 路由要不要开规则要想清楚。

回档三档(详见 docs/design-notes.md 的「回档」表):

整包回退到加规则之前(连带插件写回的 reasoningEfforts / managed 一起消失)
cp ~/.dsh/profiles/desktop/cordis.patch.yml.bak-before-reasoning-rules-<时间戳> \
~/.dsh/profiles/desktop/cordis.patch.yml
只删 rules: 里的某一条 → 插件下次 reconcile 会自动清掉它给该供应商写的 reasoningEfforts(它写的、现在没人声明 = 干净清除)。只想临时不用某个模型 → 在选择器里选「供应商默认」或「关」即可,不用改配置。

注意写回发生在下一次读目录时(打开模型选择器,或重启 DSH):插件必须先写、才能记下"这些字段是我写的",人预先写上反而会被当成手改而永久释放。

安装 / 卸载 / 启停

插件是一个 profile bundle。manage.mjs 负责把它登记进去,之后由插件管理器接管。

cd dsh-model-controls
node tools/manage.mjs status # 查看当前状态
node tools/manage.mjs install # 加 link 依赖 + bundles 选择 + 建软链
然后重启一次 DSH

重启后 设置 → 插件 里会出现 @local/dsh-model-toggle,在那里启用/停用:停用会同时去掉 host 半和面板,启用即恢复,都不需要再重启。开关状态存在 profile 的 cordis.patch.yml 里,两种情况都不丢。

卸载 / 回档:

node tools/manage.mjs uninstall # 去掉 link 依赖和 bundle 选择

manage.mjs 写之前会备份 profile 清单;从旧版升级时它会清掉 cordis.patch.yml 里手写的 insert: 块,同时保留已保存的设置。旧的整页覆盖路线已弃用但保留:node tools/patch-page.mjs check|install|revert。

测试按钮

插件面板 v1 只做启用/停用,没有带回旧的「测试」。旧的整页补丁里那个测试本身也没有真正接线(host 侧从未应答探测请求),所以这次没有移植。需要的话再加:客户端用 ctx.remote.llm.discoverModels(settingsNs, { provider, baseURL, api, apiKey }) 直接探测。

已验证内容

- host 半(隔离启动打包运行时):命名空间可写、modelCatalog() 过滤、写入 cordis.patch.yml、重启后仍生效、卸载后还原服务方法。
- 思考强度规则层:见上面「已验证」小节的 55/55 与 17/17。
- client 半(离线静态校验 + 桩模块物化):包 dsh.client.platform=web、exports["./client"] 指向 lib/client.js、bundle id 与包名一致、window.__ModuleLoader__.load 形式、node --check 通过;apply(ctx) 注册进 settings.models.provider-card 并渲染出该供应商的模型。
- bundle 组装:用 profile 副本跑 dsh --profile <copy> --dump-config,生成唯一一条 model-toggle 行并套用设置覆盖。

已知限制

- 安装或改客户端代码后需要重启一次;之后在「设置 → 插件」里启停是热生效的。DSH 升级不再需要重打页面补丁,但升级后如果插件用到的内部接缝变了,条目会「未能激活」,需要适配。
- 开关在供应商卡片内的面板里,不再贴在每个模型行内——模型行没有扩展插槽。
- 做不到 ZCode 那种「用户往请求体里塞任意字段」:DSH 只能决定值,字段家族由枚举 compat.thinkingFormat 选定(证据见 docs/design-notes.md §九)。
- 只为「配置里声明了模型」的供应商提供开关(模型列表来自设置文档的 models)。
- 思考强度规则层同样只管理声明了 models 列表的供应商:完全依赖 pi-ai 内置目录的路由不碰(否则会把内置目录冻结进用户配置)。
- 规则写回会把整条 models 数组写进 cordis.patch.yml(设置 API 的数组是整体替换)。对「模型本来就声明在用户配置里」的供应商,这只是补上字段;只有模型来自更低层时才等于把它物化一份。
- defaultEffort(打开模型时的默认档位)没有接线:DSH 的这个字段是路由级的 reasoning,由插件代填会影响整条供应商。所以默认是「供应商默认」(不发字段),你自己选档。
- 停用当前会话正在使用的模型会让输入框变成不可用,直到你另选一个模型。

设计说明

内部接缝、文件:行号 证据、取舍与失败模式都记在 docs/design-notes.md;思考强度的方案来自 zai-org/ZCode(Apache-2.0)的调研,笔记在 docs/zcode-reasoning-effort.md。

免责声明

这是一个非官方社区项目,与 DeepSeek、Z.ai 均无隶属或背书关系,两家官方也没有参与或审核本项目。「DeepSeek Harness」「ZCode」等名称归各自所有者,此处仅用于说明本项目与什么集成。

它从外部改造一个已发布的桌面应用(不修改签名的 app.asar),因此上游更新仍可能破坏它依赖的内部接缝。请自行评估风险。

许可

MIT,见 LICENSE。
预览分享卡片长什么样 ↓Salty-Mocha/dsh-model-controls-mac
分享 · DeepSeek Harness Hub
Salty-Mocha/dsh-model-controls-mac

按模型和供应商启停模型,并为第三方供应商配置思考强度档位

回到顶部