dsh-model-fit
Đã xác minhdsh-model-fit · v0.2.3 · MIT · Giao diện web
模型能力管理:为手写模型设置图片输入与推理强度、线路系统消息角色(可一键继承目录模型的精确能力)。
Cài đặt
dsh plugin add dsh-model-fit Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.
Thẻ
Readme
dsh-model-fit
模型能力管理 —— 为 DSH 的自定义(手动添加)模型设置「图片输入」与「推理强度」、为每条线路设置「系统消息角色」,并支持一键继承目录模型的图片输入与思考等级(含线上取值),解决手动添加模型时无法配置推理强度、以及最新模型不显示图片输入的问题。
- 包名 / 行 ID:
dsh-model-fit/model-fit - 当前版本:
0.2.3 - 类型:DSH Web Profile Bundle(正式插件,非动态调试插件)
- 依赖:
zod@^4(真实 dependency,随插件自动安装) ——lib/typert.host.js直接import { z } from 'zod',而 DSH 的 typert 校验要求 schema 必须是 zod v4(判据是内部标记_zod)。声明为 dependency 才能保证解析到 v4,详见下方 0.1.10 变更记录。@deepseek-ai/cordis、@deepseek-ai/schemastery、@deepseek-ai/dsh-typert-protocol、@earendil-works/pi-ai(peer,运行时由 DSH 安装目录级联解析;范围统一为*,跟随运行时、不写死上界,详见下方 0.2.1 变更记录)
为什么做这个插件
DSH 的模型供应方有两类:内置(自带完整目录,含推理强度/图片能力)和手动添加(只填 Provider ID/地址/协议,模型列表自行填写)。
手动添加的模型有两个痛点:
- 推理强度 —— 界面无法为手写模型选择推理等级,模型不显示 reasoning 能力。
- 图片输入 —— 较新模型(如
glm-5.3、deepseek-v4-flash-vision-exp等)在模型选择器里不显示图片输入,导致model-unavailable: ... does not accept image input。
本插件直接把这些能力写入 llm-pi-ai 设置命名空间的模型配置(input、reasoningEfforts),运行时由 pi-ai 适配器解析生效,因此请求时图片/推理真正可用。(compat 只由线路级「系统消息角色」写入 supportsDeveloperRole;「继承自…」不写 compat,原因见 0.2.3 变更记录。)
功能总览
1. 全模型平铺列表
- 不再按供应商选择 —— 所有供应商的所有模型平铺展示,每个模型卡片上显示所属供应商徽章(如
ocgo-01)。 - 顶部统计:
N 个供应商 · N 个模型。 - 卡片两行布局(允许换行,模型名永不截断)。
2. 图片输入开关
- 每个模型一个「图片」复选框,勾选 =
input: ['text','image'],取消 =input: ['text']。 - 选中后模型选择器会显示图片能力、请求可携带图片。
3. 推理强度等级
- 每个模型一组等级 pill:
off / high / max(主力)+ 更多(minimal / low / medium / xhigh)。 - 点击切换开关;选中的等级显示为品牌色描边。
- 线上值可编辑:选中某个等级后,pill 内出现一个小输入框,可直接改真实请求串(例如
high↔ 等价的high/其它字符串)。 - 工具条提供 「全部收起 / 全部展开」 一键切换所有行的等级显示;收起后每行仍保留「更多…」单独展开。
4. 一键继承(核心)
- 每个模型的「继承自…」按钮打开选择弹窗,列出所有有模型的目录供应商(无模型供应商自动隐藏)。
- 选择一个来源模型后,插件通过运行时 RPC
modelCapability/source读取其能力,并覆盖到当前模型仅两项:- 图片输入模态(
input) - 思考等级(
reasoningEfforts,含线上取值)
- 图片输入模态(
- 不继承
compat(0.2.3 起):目录条目的compat里混着 DSH 只允许目录自己设置的开关(withhold,如supportsMidConvoSystemMessages),抄进配置会被dsh-llm-pi-ai的设置校验整条拒绝(一处违规 → 整次保存作废)。目标模型已有的compat原样保留,不受继承影响。 - 若目录无该模型精确条目(如自定义的
deepseek-v4-flash-vision-exp),会自动按同族模型(deepseek-v4-flash)或等级名继承,并在提示里注明。
5. 批量操作
- 批量开视觉:把所有
vision/omni命名的模型自动设为支持图片。 - 批量开推理:把所有尚无推理配置的模型设为
off/high/max。 - 清空能力:清空当前所有模型的
input / reasoningEfforts / compat(还原为未设置)。
6. 搜索与过滤
- 搜索框:同时匹配模型名 / 模型 id / 供应商名。
- 「只看已设置」:只显示已配置能力(图片/推理/compat 任一)的模型。
7. 跨供应商一次保存
- 底部保存条统计:
将修改 N 个模型(M 个供应商)。 - 点「保存」把所有有变更的供应商合并成一次
settings.mutate(多个 ops + 同一个expectedRevision,原子提交)。 - 「撤销修改」一键还原到打开时的基线。
- 保存成功/失败以绿/红横幅提示。
8. 原生 UI 风格
- 完全复用官方主题变量
var(--dsw-alias-*)(卡片、边框、文字、品牌色、状态色),自动适配浅色/深色主题。 - 卡片式布局、pill 徽章、ghost/主按钮,与 DSH「模型」原生设置页同一套视觉语言。
9. 线路系统消息角色(compat.supportsDeveloperRole)
- 在模型列表上方按线路列出「系统消息角色」下拉:
自动(交给 pi-ai 推断)/强制 system/强制 developer。 - 写入的是
providers.<id>.compat.supportsDeveloperRole,即线路级默认值;pi-ai 合并顺序是模型 compat > 线路 compat > 安装目录条目 > 自身探测,所以单个模型自己写了同名字段时以模型为准(界面上会提示)。 - 用途:某些中转/上游只认
system,而 DSH 对推理模型默认发 OpenAI 的developer角色,会间歇性 422(错误形如unknown variant 'developer')。选「强制 system」就写false,从源头绕开,不必手改settings.yaml。 - 「自动」= 删除该字段(
compat里只剩这一个键时整块删除,不留空的compat: {}),交回 pi-ai 按 baseURL/协议推断。 - 只收这个字段的协议(
openai-completions/openai-responses/azure-openai-responses/openai-codex-responses)才可编辑;其它协议的线路(如anthropic-messages)下拉置灰并给出原因 —— 线路级写了协议不认的 compat 字段会被设置层整条拒绝,所以这里提前拦掉。
工作原理(架构)
浏览器端(client/client.js)
├─ connection.remote.settings.describe() 读取 llm-pi-ai 原始配置(含每个供应商的 models)
├─ connection.remote.session.modelCatalog() 读取目录(供“继承”选择来源)
├─ connection.remote.settings.mutate(ns, ops, revision) 跨供应商一次保存
└─ connection.rpc.call("/api","modelCapability/source",{args:{request}})
│
▼
主机端(lib/index.js + lib/typert.host.js)
└─ ModelCapabilityService.source(request)
├─ this.ctx.llm.resolveModelInfo(provider, model) → inputModalities + 推理等级 ids
└─ @earendil-works/pi-ai/providers/all 目录 → thinkingLevelMap(线上取值) + compat(仅诊断)
- 主机暴露一个 typert 主机端点
modelCapability/source(严格 manifest,lib/typert.host.js),浏览器端通过网关调用。 - 设置读写走官方 Remote 命名空间
ctx.remote.settings(describe/mutate),与官方「模型」设置页同一条写入路径,因此写入即时生效、无沙箱 realm 序列化问题。 - 目录来源走官方
ctx.remote.session.modelCatalog()(与模型选择器同源),拿不到时该依赖可选降级,页面照常渲染。 - 写入的数据位于
llm-pi-ai设置命名空间:模型级providers.<id>.models[]的input/reasoningEfforts/compat,以及线路级providers.<id>.compat.supportsDeveloperRole(系统消息角色),都由 pi-ai 适配器在运行时解析生效。 - 所有写入都是
settings.mutate的路径操作(set深路径会自动创建中间对象,unset精确删叶子),模型能力与线路角色会合并进同一次 mutate、共用同一个expectedRevision,因此只改角色时不会顺带重写没变化的模型列表。
依赖的服务(client 端 inject)
| 服务 | 用途 | 必需 |
|---|---|---|
slots |
注册 settings.section 设置分区 |
是 |
connection |
connection.rpc 调用主机 modelCapability/source |
是 |
remote + remote.settings |
设置命名空间的读写(describe / mutate) |
是 |
remote.session |
modelCatalog() 提供“继承自…”的目录来源 |
否(缺失则来源列表为空) |
⚠️ 注意:
ctx.connection不提供api。历史上曾有connection.api.settings/llm这层封装,0.1.5 起已移除;若继续访问connection.api.settings,settings.section会在渲染时抛TypeError: Cannot read properties of undefined (reading 'settings'),被 slot 错误边界吞掉,表现为整页空白。这正是 0.1.8 及更早版本的故障点。
目录结构
dsh-model-fit/
├── package.json # 包描述 + dsh.bundle.patch + dsh.client 声明
├── cordis.patch.yml # 向 profile 插入行:model-fit
├── lib/
│ ├── index.js # host 端 ModelCapabilityService(source:读取来源能力)
│ └── typert.host.js # 手写 typert 主机 manifest(modelCapability/source)
└── client/
└── client.js # 设置页 section UI(纯浏览器,__ModuleLoader__ 格式)
安装 / 卸载 / 还原
插件作为 profile bundle 安装,改动 profile 的
package.json与dsh.profile.bundles,需重启 dsh web 生效。
# 安装(首次/更新)
dsh plugin --profile web add dsh-model-fit
# 重启 dsh web 生效
# 卸载(完全还原)
dsh plugin --profile web remove dsh-model-fit
# 重启 dsh web 后插件行消失、UI 分区消失
还原说明:
- 卸载插件只移除 UI 与行;已写入的模型能力数据(
input/reasoningEfforts/compat)会保留在settings.yaml,且仍正常生效(无害)。 - 若想连数据一起清掉,先在插件里「清空能力」并保存,或手动编辑
llm-pi-ai配置。
使用流程(快速上手)
- 打开 设置 → 模型能力管理。
- 在列表里找到目标模型(供应商徽章标识归属,如
ocgo-01)。 - 需要图片 → 勾选「图片」;需要推理 → 点选对应等级(可改线上值)。
- 或点「继承自…」,选一个目录中的同模型,一键带出图片输入 + 思考等级(不含
compat)。 - 底部点「保存」。绿色横幅即成功。
- 回到「模型」页/模型选择器确认该模型已显示图片与推理强度。
已知限制
- 继承时若目录没有该模型的精确条目(如自造的
*-vision-exp),会按同族/等级名继承并提示 —— 这是目录数据缺失所致,非插件 bug。 - 无模型的目录供应商在“继承”弹窗中不显示(无来源可继承)。
- 继承不写
compat(0.2.3 起,见变更记录):若来源上游需要特定兼容开关(如 DeepSeek 系的thinkingFormat: 'deepseek'、maxTokensField: 'max_tokens')才能跑通,请在配置里手写 —— 只有 DSH 允许写的字段(offer)能写,目录专有字段(withhold)写了会被设置层整条拒绝。另一个办法是直接在等级 pill 的小输入框调整线上取值。 - 「自动」不显示 pi-ai 实际推断出的角色:推断逻辑(
detectCompat)在 pi-ai 内部且未导出,浏览器端算不出来。经验上自定义线路(baseURL 不含任何已知厂商特征)会被推断为developer,所以想稳妥就显式选「强制 system」。
变更记录
0.2.3
修复:「继承自…」把目录条目的 compat 整体抄进配置,命中 DSH 的目录专有开关 → 设置层整条拒绝,保存全废(连其它线路的改动一起)。现在继承只写「图片输入 + 思考等级」。
- 现象:从目录条目继承后点「保存」,红条报
保存失败: llm-pi-ai: provider "cmd-01" model "moonshotai/Kimi-K3" sets compat "supportsMidConvoSystemMessages", which is not configurable here: pi-ai's installed catalog sets it for the vendors that need it, so name that provider as the route instead - 根因:
client.js的inheritTo原样patch.compat = { ...s.compat }。pi-ai 目录的compat里混着 DSH 的 withhold(目录专有、不许写进配置)字段;dsh-llm-pi-ai的assertOfferedCompatFields(lib/index.js:522)命中即抛PiAiCatalogError,而写入闸ctx.on("internal/config") → assertServiceable(:2556)跑的是整份配置,所以一处违规 = 整次保存作废(原子写,什么都不落盘)。 - 命中面(实测内置目录):1495 个模型里 628 个(42%) 的 compat 至少含一个「写不进去」的字段;
moonshotai.kimi-k3会带进 2 个 ——supportsMidConvoSystemMessages、supportsMidConvoToolAdditions。 - 改法:继承只写
input+reasoningEfforts;compat一律不继承,目标模型原有 compat 原样保留。主机端modelCapability/source仍返回compat(仅诊断),代码路径与 typert 清单未改 → 不需要重启dsh web,刷新页面即生效。 - 验证(两段都是真实调用,不是推理):
- 客户端:
verify-inherit-nocompat.mjs(工作区,非本包)用最小 React 桩驱动真实 client.js 走完「点继承 → 选moonshotai.kimi-k3→ 点保存」,抓真正会发出的 ops。0.2.2 的 client.js 抓到 Kimi 条目带compat且含 2 个被拒字段(FAIL);0.2.3 抓到input: ['text','image']、reasoningEfforts: {off,low,high,max}、无 compat(PASS),deepseek 条目手写的 compat 一字未动。 - 服务端:直接对运行中的 DSH 打真实 HTTP RPC
settings/mutate。用旧载荷 → 返回与截图逐字相同的拒绝;用新载荷 →ok,落盘input+reasoningEfforts,compat未写入。
- 客户端:
0.2.2
修复:0.2.1 放开 peer 后插件终于能加载了,但它的 Typert 清单还是 0.1.x 旧契约 —— 一激活就把整棵插件树带崩,聊天记录都看不到。
- 现象:0.2.1 之后重启
dsh web,界面起来但整个聊天记录都看不到;把dsh-model-fit从 profile 的dsh.profile.bundles里手工摘掉才恢复。 - 根因:
lib/typert.host.js里两处 strict codec 用的是 0.1.x 的裸schema字段:
0.2.x 的契约要求codec: { mode: 'strict', typeSymbol: '…:request', schema: sourceRequestSchema } // 旧create是工厂函数(网关按codec.create().parse(value)调用,registry 把create()的结果缓存为 schema):
判据在const X$schema = () => (X$schema$value ??= z.…) // 官方生成物同形 codec: { mode: 'strict', typeSymbol: '…', create: X$schema } // 新dsh-typert-loader的requireStrictCodec:typeof codec.create !== "function"→ 抛has no create() factory;dsh-typert-registry的validateCodec同样要求create。 - 为什么是全局故障而不是只挂一个插件:loader 的
apply()里await Promise.all(flush(...)),把注册失败汇成AggregateError抛出 → 这个核心 entry 挂载失败 → 整棵插件树加载失败。清单错误在这个架构里不是局部故障。 - 为什么之前一直没暴露:0.1.x→0.2.x 的 peer 范围把整个 bundle 挡在门外(
incompatible-version),插件根本没机会激活 —— 那道检查意外地掩盖了清单的旧契约。0.2.1 放开 peer 后掩盖消失,真实不兼容立刻显形。这也是"放开 peer"必须配一次清单复验的原因。 - 改法与验证:
- 两处 codec 改为
create: () => <schema>(惰性工厂,与官方生成物同形)。 - 用 loader 自己导出的校验器
validateTypertManifest('dsh-model-fit', TYPERT)验证通过 —— 正是当初抛错的那道闸。 - 复刻
typert-registry的validateCodec/ wire 名 / segment 名规则逐条检查通过,并确认清单里不再残留死掉的schema字段。 - 按真实调用路径
codec.create().parse(value)实测:参数解析、结果解析、结果null、非法输入被拒;_zodv4 标记在位(zod 4.6.5)。 - 顺带核对同期其它 API 面:
TypertRemoteService构造函数逐字未变、ctx.llm.resolveModelInfo仍在、settings.mutate的{op:'set'|'unset', path}契约未变、clientinject的 4 个名字与同 profile 正常工作插件一致、client/client.js语法 OK。
- 两处 codec 改为
- ⚠️ 教训:peer 范围是"声明",不是"兼容性证明"。 放开它只解决"被误拦",同时撤掉那道意外保护 —— 以后每次 DSH 大版本升级,都要用官方校验器把 typert 清单重新验一遍,而不是只看"插件能不能加载"。
0.2.1
修复:DSH 升到 0.2.0-rc.1 后插件被整个拦在门外(插件页显示「异常」,incompatible-version)。
- 现象:profile 里
dsh-model-fit被判不兼容 ——[email protected] 与 DSH 0.2.0-rc.1 不兼容(要求 @deepseek-ai/dsh-typert-protocol ^0.1.1-rc.2)。真实后果不只是警告:整个 bundle 被跳过,它那层 patch 不加载,modelCapability服务不存在,「一键继承」直接失效。 - 根因:
peerDependencies里写死的^0.1.1-rc.2规范化后是>=0.1.1-rc.2 <0.2.0-0—— 0.x 的 caret 只允许 patch 位浮动。而 DSH 0.2.0-rc.1 自带的@deepseek-ai/dsh-typert-protocol是 0.2.0-rc.1,正好落在上界之外。这个范围从首个 commit 就写死了(当时运行时是 0.1.x),随 DSH 升到 0.2 才引爆。 - 排查要点:
- 判定发生在启动时:
dsh-app-boot的loadProfileDirectory对每个 bundle 跑evaluatePluginCompatibility,不通过就整包跳过(记入skippedBundles),不是只打一条警告。 - 它只看名字为
@deepseek-ai/dsh或@deepseek-ai/dsh-*的 peer,用semver.satisfies(运行版本, range, { includePrerelease: true })比。 peerDependenciesMeta.optional: true不救场:那段检查完全不读peerDependenciesMeta,标了 optional 照样拦。
- 判定发生在启动时:
- 同时确认 API 其实没变(所以是过期声明,不是真不兼容):插件对 protocol 的全部用法只有
TypertRemoteService(lib/index.js的 import 与super(ctx, 'modelCapability'));0.2.0-rc.1 仍从包根导出它,构造函数体与 0.1.1-rc.2 逐字一致;且 profile 与插件node_modules里的 protocol 都指向运行时那一份,不存在双实例。 - 改法:
@deepseek-ai/dsh-typert-protocol与@earendil-works/pi-ai的 peer 范围统一改成"*"(与同作者的dsh-provider-info、同 profile 的dsh-icon-custom/dsh-notify-p一致)。host 提供的依赖跟随运行时,不再写死上界 —— 以后升到 0.5.0 / 1.0.0 也不会再被拦。- 顺带修掉一个同类隐患:
@earendil-works/pi-ai原写^0.84.3,而运行时实际解析到 0.85.1,同样早已落在范围外(只因它不是 dsh 系 peer 才没被拦)。
- 顺带修掉一个同类隐患:
- 验证方式:
- 直接调用 DSH 自己的判定函数,对
0.1.10 / 0.2.0-rc.1 / 0.2.5 / 0.5.0 / 1.0.0 / 2.0.0-rc.1 / 1.0.0-beta.3全部 PASS。 - 复现启动时的组合逻辑:profile 的 10 个 bundle 全部成层、
skippedBundles为空,dsh-model-fit正常贡献出model-fit行。 - 单独
import lib/index.js,确认在当前运行时 protocol 下加载正常(TypertRemoteService、inject = ['llm'])。
- 直接调用 DSH 自己的判定函数,对
- ⚠️ 改完需重启
dsh web(bundle 在启动时组合,改 peer 不会热生效)。
0.2.0
新增:线路级「系统消息角色」—— 不用再手改 settings.yaml 绕开 developer 422。
- 背景:DSH 对声明了
reasoningEfforts的模型,会把系统提示词以 OpenAI 的developer角色发出(@earendil-works/pi-ai/dist/api/openai-completions.js里useDeveloperRole = model.reasoning && compat.supportsDeveloperRole)。部分中转/上游只认system,会返回 422invalid_request_error(DeepSeek 官方原文:messages[0].role: unknown variant 'developer'),而 422 不在 DSH 的自动重试名单里,所以表现为「整轮随机失败」。此前的对策是手写一行:providers: cmd-01: compat: supportsDeveloperRole: false - 现在在「设置 → 模型能力管理」页的模型列表上方,按线路给出下拉:
自动/强制 system/强制 developer,写入同一条线路级compat.supportsDeveloperRole,保存后即时生效。 - 实现要点:
- 读:
remote.settings.describe()→namespaces[llm-pi-ai].user.providers.<id>.compat.supportsDeveloperRole(true→ developer,false→ system,缺失 → 自动)。 - 写:
remote.settings.mutate('llm-pi-ai', ops, revision),op 为{op:'set', path:['providers',id,'compat','supportsDeveloperRole'], value:false|true};选「自动」用{op:'unset', …},当compat里只有这一个键时改成整块unset ['providers',id,'compat'],避免在settings.yaml里留下空的compat: {}。 - 与原有的模型能力保存合并成同一次 mutate、同一个
expectedRevision:只改角色时不再多写一份没变化的models数组;底部保存条拆成「N 个模型能力 · M 条线路角色」,撤销同时回滚两者。 - 按协议门控:只有
openai-completions/openai-responses/azure-openai-responses/openai-codex-responses收这个字段;线路api是别的协议(如anthropic-messages)时下拉置灰并说明原因 —— 线路级写协议不认的 compat 字段会被dsh-llm-pi-ai的assertOfferedCompatFields/resolveModelCompat整条拒绝,不是静默忽略。 - 纯 client 端改动:host 服务、typert manifest、依赖、profile 全部未动。
- 读:
- 验证方式(不触碰真实配置):
- 用真实的
applyPathOp(dsh-settings/lib/index.js)语义回放四种选择生成的 ops,确认set建中间对象、unset删叶子、models等其它字段完好、对没有compat的线路unset是无操作。 - 用桩
React.createElement/useState直接执行组件函数,断言线路块渲染出的select数量/选中值/禁用态/提示文案,以及点「保存」后真正发出的 ops 内容与 mutate 次数(1 次、revision 透传、模型 op 与角色 op 数量符合预期)。 - 远端通道确认:
dsh-api-settings-controller的settings/mutate严格 schema 明确接受{op:'unset', path:string[]}与布尔value。
- 用真实的
- ⚠️ 改完需重启
dsh web(插件是 link 安装、client bundle 在启动时打包,没有 HMR)。
0.1.10
修复:别人安装后 dsh web 直接起不来(parameter codec is not backed by a zod v4 schema)。
- 根因:
lib/typert.host.js里import { z } from 'zod',但package.json从未声明过zod(连dependencies字段都没有)。于是 zod 从哪来完全靠就近解析碰运气:dsh plugin --profile web add装到对方 profile 后,解析命中 profile 里被其它包 hoist 上来的 zod v3 → schema 没有 v4 的内部标记_zod→ typert-loader 校验失败。 - 后果特别重:这是 boot 阶段的 manifest 校验,失败会让整个 dsh 起不来(不是单个插件降级)。报错形如:
Error: dsh: plugin tree failed to load: failed to apply loader entry typert-loader … - typert-loader: dsh-model-fit invocation "dsh-model-fit#modelCapability/source" parameter codec is not backed by a zod v4 schema - 排查要点:DSH 的判据在
dsh-typert-loader/lib/index.js的requireStrictCodec:if (typeof schema !== 'object' || schema === null || !('_zod' in schema) || typeof schema.parse !== 'function') throw new Error(`… is not backed by a zod v4 schema`)_zod是 zod v4 独有的内部标记,zod v3 没有 —— 所以这条报错的唯一含义就是「拿到 v3 了」。 - 改法:
package.json补"dependencies": { "zod": "^4.4.3" },与 DSH 官方包(dsh-goal/dsh-llm/dsh-commands等同样手写typert.host.js的包)以及同作者的dsh-provider-info一致。 - 验证方式:在复刻了对方环境的临时工程里(顶层 hoist 一个 zod v3),分别安装
0.1.9与0.1.10:0.1.9:manifest 看到的 zod =3.25.76,_zod= false → REJECT(复现同一报错)0.1.10:manifest 看到的 zod = 自带的4.x,_zod= true → ACCEPT(顶层那个 v3 原封不动仍在)
- ⚠️ 教训:写了
typert.host.js就必须把zod声明成 dependency;且本地开发时若node_modules里残留一个 zod 软链,会完全掩盖这个 bug(本地能跑、别人装了就崩)。验证必须在干净/敌意环境里做。
0.1.9
修复:设置 → 模型能力管理 整页空白。
- 根因:client 端仍在访问
connection.api.settings/connection.api.llm,但ctx.connection从 0.1.5 起只提供rpc(不提供api)。组件首次渲染即抛TypeError: Cannot read properties of undefined (reading 'settings'),被 slot 错误边界([data-slot-error="settings.section"])吸收,页面只剩空白,且控制台仅有一条 console error。 - 改法:改用官方 Remote 命名空间 ——
remote.settings.describe/mutate读写llm-pi-ai,remote.session.modelCatalog()读取“继承自…”的目录来源(可选依赖,缺失时降级为空列表而非崩溃)。 - 行为不变:图片开关、推理等级、一键继承、批量操作、跨供应商一次保存、撤销修改均照旧;已验证保存后
settings.yaml真实写入且模型选择器生效。
0.1.8
- 模型卡片两行布局、名称不再截断;等级线上取值可编辑;“全部收起/展开”。
License
MIT