dsh-plugin-model-tuning 2.1.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +85 -234
  2. package/client.js +425 -1013
  3. package/cordis.patch.yml +10 -19
  4. package/index.js +20 -263
  5. package/package.json +6 -11
package/README.md CHANGED
@@ -1,72 +1,63 @@
1
1
  # dsh-plugin-model-tuning
2
2
 
3
- 「设置 → 模型调参」页面插件。页面分为**「模型参数」「用途」「绘图」**三个页签。
4
-
5
- > **v2.0 合并说明**:本插件现已并入原 `dsh-plugin-title-model`(标题生成独立路由)
6
- > 与原 `dsh-plugin-image-generation`(绘图模型配置、`generate_image` 工具、直接绘图面板)。
7
- > 三个曾经的包现在是一个包、一个设置命名空间(`model-tuning`)、一个 Config schema。
8
- > 原 `title-model` 与 `image-generation` 两个包已从本仓库移除;合并动机与决策记录见文末。
9
-
10
- ## 功能
11
-
12
- ### 模型参数
13
-
14
- - 按 provider 分组展示当前模型目录;
15
- - 为每个模型配置:
16
- - 可选推理档位(仅 `llm-pi-ai` 可编辑,其他 provider 只读展示);
17
- - 上下文窗口;
18
- - 最大输出 tokens;
19
- - 输入模态三态开关(见下);
20
- - 系统提示角色兼容开关:`自动` / `system` / `developer`(仅 `llm-pi-ai`,
21
- 写入模型条目的 `compat.supportsDeveloperRole`;遇到 kimi/DeepSeek 等
22
- 报 `role 'developer' is not allowed` 时选 `system`);
23
- - 思考格式兼容开关:`自动` / `自适应 thinking`(仅 `llm-pi-ai` 且路由 `api: anthropic-messages`,
24
- 写入模型条目的 `compat.forceAdaptiveThinking`;见下节「Anthropic 思考格式」。
25
- 该模型一个推理档位都没勾选时不显示——那时请求里根本没有 `thinking`);
26
- - 生图模型勾选(把该模型写入「绘图」页签的模型列表,见「绘图页签」);
27
- - 顶部搜索框按模型名 / ID / 描述 / provider 过滤;
28
- - 修改即时保存(`remote.settings.mutate`;模型目录来自 `remote.session.modelCatalog()`)。
29
-
30
- ### 用途(标题生成)
31
-
32
- 按「用途」组织的配置。目前含**标题生成**一项:
33
-
34
- - 默认**继承当前会话**已记录的 provider / model(与内置标题生成一致);
35
- - 也可指定独立的 provider / model,选项全部来自真实模型目录(不提供自由输入框,避免臆造 ID);
36
- - **标题请求预算也在本页配置**(目标词数 / 汉字数、输入字节上限、输出 token 上限、超时):
37
- 这些字段是 volatile 配置,写入后按需覆盖插件行的默认值;清空某一项即回到默认;
38
- - 每次生成都重新读取路由与预算,保存后下一次标题生成即生效,**不需要重启宿主**;
39
- - 生效范围是本 profile 之后生成的标题;已有标题、手动重命名、会话的对话模型都不受影响;
40
- - 不提供推理档位控件:标题策略不向标题请求传递 `reasoningEffort`,加一个不生效的控件会误导。
41
- 但这意味着**是否思考由所选模型自己决定**——推理模型会先思考再作答,需要更大的
42
- 「输出上限」(例如 1024)才能在预算内产出标题;直接作答的模型用默认的 64 就够。
43
- 例外:内置 DeepSeek 适配器对 `purpose === "session-title"` 强制关闭思考
44
- (`dsh-llm-deepseek` 里 `options.purpose === "session-title" ? "off"`),所以
45
- `deepseek-official` 的模型在默认预算下即可直接出标题;
46
- - 「宿主行未激活」提示只在标题 provider 注册失败(插件半区未启动)时出现。
47
-
48
- ### 绘图页签
49
-
50
- 独立配置绘图模型、`generate_image` / `list_image_models` 工具与「直接绘图」面板。
51
- 绘图模型不进入聊天模型列表,不改动现有会话存储或对话 provider。
52
-
53
- - 添加模型:填供应商 API 地址(默认 `https://api.openai.com/v1`)与 API Key,
54
- 点「获取模型列表」搜索并选择(只请求目录、不生成、不保存草稿 Key;模型 ID 可手填);
55
- - 也可在「模型参数」页勾选某模型的「生图模型」,自动按该 provider 的
56
- `baseURL + /images/generations` 与 `apiKeyEnv` 推导出一条配置(带 `source` 溯源标记);
57
- - 首个模型自动成为默认项;尺寸、质量、超时等高级参数按模型配置;
58
- - 直接绘图面板:短请求启动任务 + 轮询状态 + 取消,不经过聊天模型;
59
- - 协议:OpenAI Images(`POST`,解析 `data[].b64_json` 或 `data[].url`,1–4 张)。
60
-
61
- ## 配置结构(单一命名空间)
62
-
63
- profile 条目 id `model-tuning` 的 Config 字段(volatile,热更新即时生效):
3
+ 只补**官方没有的两块**:
4
+
5
+ 1. **官方「设置 → 模型」卡片里的兼容与推理补丁**(内嵌在官方 Models 页,不再有独立参数页);
6
+ 2. **「设置 → 绘图」页**:绘图模型配置 + `generate_image` / `list_image_models` 工具 + 直接绘图面板。
7
+
8
+ > **v3 边界收缩(2026-10,基线 dsh 0.2.1-rc.1)**:v2 合并进来的「标题生成路由」交还官方 `session-title-llm` 行,「模型参数」页交还官方 Models 页。官方已经能做的,本插件不再复制;官方没有的,见下面两节。重叠盘点记录见 [docs/PLUGIN-SCOPE-dsh-0.2.1-rc.1.md](../docs/PLUGIN-SCOPE-dsh-0.2.1-rc.1.md)。
9
+
10
+ > 兼容性:`engines.dsh` = `>=0.2.0-rc.2 <0.3.0-0`,已在 dsh 0.2.1-rc.3 上实测运行。
11
+
12
+ ## 1. 兼容与推理(官方 Models 页扩展)
13
+
14
+ 通过官方为仓库外插件留的 `settings.models.provider-card` 席位,在每张 pi-ai provider 卡片里追加一节「兼容与推理(插件补充)」。**这些控件官方 Models 页没有**:
15
+
16
+ | 控件 | 写入位置 | 解决什么 |
17
+ | --- | --- | --- |
18
+ | **系统提示角色** `自动 / system / developer` | 模型条目的 `compat.supportsDeveloperRole` | 网关报 `role 'developer' is not allowed`(Kimi、部分 DeepSeek 网关)时改发 `system` |
19
+ | **思考格式** `自动 / 自适应 thinking` | 模型条目的 `compat.forceAdaptiveThinking` | Claude Opus 4.6+ / Sonnet 5 等只接受 `thinking.type=adaptive`,预算式请求会被 400 `requires adaptive thinking` 拒绝 |
20
+ | **可选推理档位**(内置目录路由) | 路由的 `modelOverrides.<id>.reasoningEfforts` | 官方只给**手写路由**的模型显示推理档位;内置目录路由借用 `modelOverrides` 声明/关掉档位,写入时保留官方已存的每档 API 值 |
21
+ | **绘图模型** 勾选 | 本插件的 `models` / `defaultModel` | 把该 provider 下的模型接到 `generate_image`:自动复用 provider 的 `baseURL`(+ `/images/generations`)与 `apiKeyEnv`,并在「设置 → 绘图」生成一条配置(对应旧版「模型参数 → 生图模型」勾选) |
22
+
23
+ 说明:
24
+
25
+ - provider 卡片里只显示 **pi-ai** 家族;`llm-deepseek` 不出现这一节。
26
+ - 思考格式只在路由自己声明 `api: anthropic-messages` 时出现;推理档位只在**已安装目录路由**(`declared !== true`)出现——手写路由交给官方页面,避免两个编辑器抢同一字段。
27
+ - 写入走 provider 自己的 settings 命名空间(`llm-pi-ai`),下一次请求生效,无需重启。
28
+ - 「系统提示角色」的字段名与协议白名单由 `@deepseek-ai/dsh-llm-pi-ai` 决定;上游改名/收窄会在 `tests/adaptive-thinking.test.mjs` 的耦合守卫里失败,而不是在会话里变成 400。
29
+
30
+ ## 2. 绘图(generate_image)
31
+
32
+ 给模型一个扩散模型绘图工具;绘图配置不进入聊天模型列表、不改动会话存储或对话 provider。
33
+
34
+ **主要用法:在「设置 → 模型」里勾选。** 展开某个 pi-ai provider 卡片 → 「绘图模型(generate_image)」→ 勾上要用的模型。勾选会:
35
+
36
+ - 复用该 provider 的 `baseURL` 推导 `…/images/generations`,复用其 `apiKeyEnv` 凭据引用(不用重新填 Key);
37
+ - 在「设置 → 绘图」生成一条配置;第一个生成的配置自动成为默认;
38
+ - 取消勾选只移除由此勾选生成的配置(手工添加的条目不受影响)。
39
+
40
+ **「设置 → 绘图」页**用于查看和管理这些配置:
41
+
42
+ - 单选按钮切换默认绘图模型(`generate_image` 不带 `model` 参数时用它);
43
+ - 「手动添加端点」:给没有对应聊天模型的独立 Images 端点用(地址 + Key + 模型列表/手填模型 ID,高级参数在折叠区);
44
+ - 底部「直接绘图(可选)」:不经过聊天,直接提交提示词、轮询状态、取消。
45
+
46
+ 聊天中由助手调用:
47
+
48
+ - `list_image_models`:列出配置 ID、上游模型 ID 与默认参数;
49
+ - `generate_image`:按配置发起 OpenAI Images 请求(1–4 张),原图逐字节保留;当前聊天模型声明了图像输入时,预览也进模型上下文。
50
+
51
+ 协议:OpenAI Images(`POST`,解析 `data[].b64_json` 或 `data[].url`)。凭据通过 dsh 凭据服务保存为引用(`apiKeyEnv`),不写明文。
52
+
53
+ ## 配置结构
54
+
55
+ profile 条目 id `model-tuning` 的 Config(volatile,热更新即时生效):
64
56
 
65
57
  ```yaml
66
58
  - id: model-tuning
67
59
  name: dsh-plugin-model-tuning
68
60
  config:
69
- # ── 绘图(原 image-generation 命名空间字段原样保留) ──
70
61
  models:
71
62
  - id: my-art
72
63
  name: 我的绘图模型
@@ -76,155 +67,30 @@ profile 条目 id `model-tuning` 的 Config 字段(volatile,热更新即时
76
67
  apiKeyEnv: IMAGE_API_KEY
77
68
  timeoutSeconds: 300
78
69
  defaultModel: my-art
79
- # ── 标题生成(原 title-model 的 mode/provider/model 加 title 前缀) ──
80
- titleMode: inherit # inherit | custom
81
- # titleProvider: tofu-gpt # custom 时必填
82
- # titleModel: gpt-5 # custom 时必填
83
- # ── 标题预算(volatile:可在「用途」页改;这里是未改时的默认值) ──
84
- targetWords: 5
85
- targetCjkCharacters: 10
86
- maxInputBytes: 4096
87
- maxOutputTokens: 64
88
- timeoutMs: 60000
89
- ```
90
-
91
- ## 它替换了什么(标题行)
92
-
93
- 宿主自带一行标题生成 provider(`@deepseek-ai/dsh-session-title-first-prompt-llm`)。
94
- `ctx.sessionTitle.register()` **只允许一个 provider,第二次注册直接抛错**,所以本包的
95
- `cordis.patch.yml` 显式替换该行:
96
-
97
- ```yaml
98
- - id: session-title-llm
99
- disabled: true # 必须先摘掉原行,否则 boot 时重复注册会失败
100
- - insert:
101
- - id: model-tuning
102
- name: dsh-plugin-model-tuning
103
- config: { targetWords: 5, targetCjkCharacters: 10, maxInputBytes: 4096, maxOutputTokens: 64, timeoutMs: 60000 }
104
70
  ```
105
71
 
106
- - **顺序即语义**:`disabled` 必须排在 `insert` 之前,否则两行会同时注册。
107
- - `config` 与 base 的数值逐项相同:**未在「用途」页改动预算时**,删掉本包的 `config:` 块也不改变标题行为;
108
- 页面写入的用户层值会覆盖这些默认值。
109
- - 注册时沿用原 provider id(`session-title-llm`)与原 cadence(`first-prompt`),会话日志里的标题归因不变。
110
- - 标题请求的提示词组装、取消与结果校验沿用宿主共享策略
111
- (`@deepseek-ai/dsh-session-title-llm` 的 `generateSessionTitleWithLlm`);
112
- 本插件决定**路由**与**预算**(提示词目标词数 / 汉字数、输入字节上限、输出 token 上限、超时)。
113
- - 卸载本 bundle 会同时移除 `disabled` 与 `insert` 两条 patch,宿主自带 provider 自动恢复。
114
-
115
- ## 模块解析(重要)
116
-
117
- `@deepseek-ai/dsh-session-title-llm` 由**运行本插件的那个部署**提供,而不是从本包目录解析。
118
- 原因:本包在工作区里是 `link:` 依赖,若在包内安装该依赖,会连带把 `@deepseek-ai/dsh-llm` 等
119
- peer 装成与部署不同的版本,形成重复模块图。`index.js` 用宿主自身入口锚点
120
- `createRequire(process.argv[1])` 定位并动态 `import()` 该包。
121
-
122
- ## 输入模态
123
-
124
- harness 的请求模态是**闭合集合 `text | image`**:`dsh-llm` 的 `ModelModalityMap` 与
125
- `dsh-llm-pi-ai` 的 `MODALITY_GATE` 都只有这两个成员。**视频没有配置项可开**。
126
-
127
- | 选项 | 写入值 | 生效语义 |
128
- | --- | --- | --- |
129
- | `自动` | 删除该字段 | 交由模型条目 → 已安装目录条目 → 路由 `defaultInput`(默认 `[text]`)解析。空数组 `[]` 与「不存在」等价。 |
130
- | `纯文本` | `["text"]` | 显式声明。附图在发送前被拒,`read_image` 同样拒绝。 |
131
- | `文本 + 图像` | `["text", "image"]` | 贴图、`read_image`、MCP 结果图全部可用。 |
132
-
133
- - 字段名按 namespace 区分:`llm-pi-ai` 写模型条目的 `input`,`llm-deepseek` 写 `inputModalities`;
134
- - 内置目录 provider 走 `modelOverrides.<id>.input`;
135
- - `llm-deepseek` 从「文本 + 图像」切走会连 `imagePixelBudget` / `imageMaxBytes` / `imageDetail` 一起删除;
136
- - 保存即生效,无需重启 `dsh web`。
137
-
138
- > 注意:网关是否真收图像无法从配置读出。开「文本 + 图像」前建议先对端点实测一次。
139
- > 「系统提示角色」开关依赖 DSH 适配层 `dsh-llm-pi-ai` 透传 `compat.supportsDeveloperRole`
140
- >(`0.1.0-rc.6` 默认不透传,需按本仓库 `deepseek-harness` 的 catalog.ts 补丁同步,或等上游合入)。
72
+ v2 的标题字段(`titleMode` / `titleProvider` / `titleModel` 与四个预算字段)已从 schema 移除;Loader 的配置校验保留未知键,所以旧 profile 仍能启动,多余字段被忽略。
141
73
 
142
- ## Anthropic 思考格式(自适应 vs 预算式)
74
+ ## 从 v2 升级
143
75
 
144
- 「模型参数」页的**思考格式**开关解决的是这一条报错:
76
+ 1. **标题生成**:v2 会禁用官方 `session-title-llm` 行并换上自己的 provider;v3 不再动组合,官方行恢复。需要独立标题模型时,在 profile 的 `cordis.patch.yml` 直接覆盖官方行(字段与官方一致):
145
77
 
146
- ```
147
- 400 {"error":{"message":"claude-opus-5-5 requires adaptive thinking; omit thinking or use
148
- thinking.type=adaptive and output_config.effort","type":"invalid_request_error"}}
149
- ```
150
-
151
- - **原因**:pi-ai 只有在模型的 `compat.forceAdaptiveThinking === true` 时才发
152
- `thinking: {type:"adaptive"}` + `output_config: {effort:"…"}`;否则发旧的预算式
153
- `thinking: {type:"enabled", budget_tokens:N}`。只接受自适应思考的模型(Claude Opus 4.6 及更新、
154
- Sonnet 5、Fable 5、Kimi K3 等)会直接 400 拒掉预算式请求。
155
- - **为什么手写路由会中招**:pi-ai 内置目录给它自己带的模型 ID 标了这个标记,
156
- 而 `dsh-llm-pi-ai` 只在「模型 ID 命中该 provider 自己的目录条目」时才继承目录 `compat`
157
- (`resolveModelCompat` 要求 `base.api === api`)。手写路由(例如 `providers.ironman-claude`
158
- 这种目录里不存在的 key)没有任何目录条目可继承,`claude-opus-5-5` 这类目录里其实认识、
159
- 但挂在 `anthropic` 名下的 ID 也一样继承不到——于是请求退化成预算式。
160
- - **怎么修**:在该模型的「思考格式」里选**自适应 thinking**,页面把
161
- `compat.forceAdaptiveThinking: true` 写进模型条目(与 `系统提示角色` 同一套写法),
162
- 下一次请求即生效,无需重启。Claude 4.5 及更早只认预算式,保持「自动」。
163
- - **另一条路(不动插件)**:把这条路由改成目录里已有的 key(例如 `providers.anthropic`
164
- 只覆盖 `baseURL` / `apiKeyEnv`,用 `models:` 收窄到要用的几个 ID),模型 ID 因此命中目录条目,
165
- 自适应标记、`supportsTemperature` 等兼容位都会自动继承。代价是 provider ID 变了,
166
- 老会话里记录的路由名会对不上,所以通常仍是逐个模型打勾更省事。
167
-
168
- > **已知边界**:思考强度选 `off` 时,`dsh-llm-pi-ai` 会把声明里 `off: null` 的那一项**移出**
169
- > `thinkingLevelMap`,pi-ai 因此发 `thinking: {type:"disabled"}`(只有把 `off` 钉成 `null` 才会
170
- > 整个省略该参数——那是内置目录条目的写法),本开关管不到这一段。若网关连 `disabled` 也拒绝,
171
- > 把该模型的「可选推理档位」全部取消(写成 `reasoningEfforts: false`,即视为无推理能力),
172
- > 请求里就完全不会出现 `thinking`。
173
-
174
- > **耦合点**:字段名 `forceAdaptiveThinking` 与「只在该协议的白名单内」都由上游决定
175
- > ——`dsh-llm-pi-ai` 的 `anthropic-messages` compat 门(`0.1.7-alpha.2` 起已含该字段,
176
- > `884f7b9c41` 于 2026-08-18 引入)会拒收白名单外的字段,pi-ai 的
177
- > `dist/api/anthropic-messages.js` 是唯一读它的地方。`tests/adaptive-thinking.test.mjs`
178
- > 在有 `DSH_TEST_DEPLOY_ROOT` 时直接问该部署的 pi-ai 要请求体,上游改名会在这里失败而不是在会话里变成 400。
179
-
180
- ## dsh 0.2.1(alpha)适配(v2.1)
181
-
182
- - **标题 helper 换了 API。** 0.2.1-alpha 系列删掉了 `generateSessionTitleWithLlm`,改成
183
- `executeSessionTitleLlm(ctx, config, request, providerId, prepared)`:提示词、输入包装、推理档位选择
184
- 与输出解析都交还给提供方。本插件按宿主实际导出择一:有新 API 就走新 API(提示词与解析规则复刻官方
185
- `session-title-first-prompt-llm`,推理档位取路由最低档),否则回落旧 helper,0.1.7–0.2.0 不受影响。
186
- 2.0.x 在 0.2.1 上会因为找不到旧导出而整行激活失败(绘图与设置页一起没了)。
187
- - **标题注册失败不再拖垮整个插件。** `apply` 里标题路由单独兜底:失败只打一条 warn、不注册标题提供方,
188
- 绘图工具与设置页照常。
189
- - **与官方「会话标题刷新」(可选目录里的 `session-titles-bundle`)互斥。** 两者都要独占
190
- `ctx.sessionTitle.register()`,后注册的一方失败——本插件这边表现为上面那条 warn。二选一。
191
- - **推理档位与官方 Models 页写的是同一个字段。** 0.2.1-alpha.4 起官方 Models 页可以给手工声明的 pi-ai
192
- 模型编辑 `reasoningEfforts`,并允许每一档发送自定义 API 值(如 `high → deep`)。本页勾选档位时保留
193
- 已存的值,只有新加的档位才默认用档位名;`off` 的已存值也原样保留。
194
-
195
- ## 与 DSH 版本的耦合点(0.1.7-alpha.2)
196
-
197
- - **provider 目录必须取 `llm.listConfigurableProviders()`**(返回 `LlmConfigurableProvider`
198
- 含 `settingsNs` / `settingsPath` / `declared`)。`llm.listProviders()` 返回的
199
- `LlmProviderInfo { id, name }` 没有这些字段,用错会让整页控件被禁用。
200
- - 绘图 Remote 面板走 `ctx.connection.rpc.call('/api', 'imageGeneration/<method>', { args })`
201
- (浏览器半区)× `TypertRemoteService`(宿主半区)。
202
- - 标题 helper `@deepseek-ai/dsh-session-title-llm` 需 `>=0.1.6-alpha.2`;
203
- `@deepseek-ai/schemastery` 需 `^3.18.4`(`volatile()` 链式方法 3.18.4 才有)。
204
-
205
- ## 测试
206
-
207
- ```sh
208
- node --test tests/*.test.mjs # 全部(title-provider 需要 DSH_TEST_DEPLOY_ROOT)
209
- # 或分开:
210
- node --test tests/title-route.test.mjs # 标题路由解析与 Config schema(纯函数)
211
- node --test tests/title-purpose.test.mjs # 用途页读写规划 + locale 回归
212
- node --test tests/image-link.test.mjs # 生图链接写入规划(纯函数)
213
- node --test tests/image.test.mjs # 绘图传输/工具/Remote(本地 HTTP,不外联)
214
- node --test tests/adaptive-thinking.test.mjs # 思考格式开关:白名单 + 写入规划(+ 部署耦合守卫)
215
- DSH_TEST_DEPLOY_ROOT=<隔离部署> node --test tests/title-provider.test.mjs # 真 helper + 假 ctx
216
- ```
78
+ ```yaml
79
+ - id: session-title-llm
80
+ name: '@deepseek-ai/dsh-session-title-first-prompt-llm'
81
+ config:
82
+ targetWords: 5
83
+ targetCjkCharacters: 10
84
+ maxInputBytes: 4096
85
+ maxOutputTokens: 4096
86
+ timeoutMs: 60000
87
+ provider: your-provider # 成对出现;省略两者即继承会话路由
88
+ model: your-model
89
+ ```
217
90
 
218
- - `title-provider.test.mjs` 用**假 ctx + 真共享策略**(只 mock `ctx.llm.stream`)验证唯一注册、
219
- 继承/指定路由、首条消息选择、辅助请求记录、失败与取消路径。`tests/_host.mjs` 要求
220
- `DSH_TEST_DEPLOY_ROOT` 指向隔离的 0.1.7-alpha.2 部署。
221
- - `adaptive-thinking.test.mjs` 的前半段是纯函数(开关只出现在 `anthropic-messages` 路由、
222
- 写入落在模型条目的 `compat` 上,目录路由落到 `modelOverrides`);后半段只在有
223
- `DSH_TEST_DEPLOY_ROOT` 时运行,把该部署的 pi-ai 拦在假 `fetch` 前,直接读出请求体,
224
- 证明「打勾 → `thinking.type=adaptive` + `output_config.effort`,不打勾 → 预算式」。
225
- - **这些测试不是实机验证**。实机验收:标题从会话日志读 `session/title-llm-request` 的 `route`
226
- 与最终 `session/title` 的 `source.model`;绘图确认「模型参数」勾选 → 绘图页出现条目 →
227
- 直接绘图面板出图;思考格式在模型下拉里选一档后看会话日志里那次请求的请求体。
91
+ 官方可选组合包「随对话更新的标题」也不再与本插件互斥。
92
+ 2. **模型参数**:上下文窗口、最大输出、输入模态、模型列表、API Key、模型发现都在官方「设置 → 模型」页;本插件只保留上表的三项官方缺口。
93
+ 3. **绘图**:配置键(`models` / `defaultModel`)与命名空间都没变,升级后原配置继续生效;「在模型行勾选生图模型」的入口已恢复,只是位置从旧「模型参数」页移到了官方「设置 → 模型」的 provider 卡片里。
228
94
 
229
95
  ## 安装 / 卸载
230
96
 
@@ -233,38 +99,23 @@ dsh plugin --profile web add "link:D:\program\dsh-plugins\dsh-plugin-model-tunin
233
99
  dsh plugin --profile web remove dsh-plugin-model-tuning
234
100
  ```
235
101
 
236
- 装/卸后**重启 profile** 生效(composition 在进程启动时组树;patch 层 live 重载只对 config 变更生效)。
237
- 卸载后:宿主自带标题 provider 恢复;绘图配置在用户 settings 里的段落成为未注册命名空间的普通文本,
238
- 不再被读取;已有图片附件与共享凭据不会被删除。
102
+ 装/卸后重启 profile 生效(组合在进程启动时组树)。卸载后:官方 Models 页少一节「兼容与推理」;绘图页消失、`generate_image` 工具下线;已存绘图配置留在 settings 里成为未注册命名空间的数据,不删除任何图片附件或共享凭据。
239
103
 
240
- ## 移动端
104
+ ## 与 dsh 版本的耦合点
241
105
 
242
- 「容量字段」的「下拉框 + 自定义输入」在**所有视口**都上下堆叠(1.1.1 起)。
106
+ - 基线:**dsh 0.2.1-rc.1**(本机实测)。官方 `settings.models.provider-card` 席位自 0.1.2-alpha 存在,`plugins.row.config` 自 0.1.6;但本包只按 rc 线验证。
107
+ - 依赖宿主包:`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-typert-protocol`、`@deepseek-ai/schemastery`。
108
+ - 绘图 Remote:浏览器 `ctx.connection.rpc.call('/api', 'imageGeneration/<method>')` × 宿主 `TypertRemoteService`。
243
109
 
244
- ## v2 合并决策记录(2026-10)
110
+ ## 测试与验证
245
111
 
246
- **合并了什么**:`dsh-plugin-title-model`(宿主侧标题路由)与 `dsh-plugin-image-generation`
247
- (绘图工具/面板)并入本包。9 包 → 7 包。
248
-
249
- **为什么**:
250
-
251
- 1. **UI 早已同居**。「用途」页与「生图模型」勾选本来就在本页,旧结构下同一个页面要跨三个包、
252
- 两个外部命名空间(`title-model`、`image-generation`)读写,任何一处 schema 变更都要双包同步,
253
- 还有专门的跨包契约测试守着同步——这是分布式单体,不是解耦。
254
- 2. **卸载粒度论点不成立**。单 profile 部署下不存在「只要绘图不要调参」的场景;且旧结构下卸载
255
- image-generation 会让调参页的生图勾选静默降级,粒度本来就是假的。
256
- 3. **数据迁移可控**。绘图 `models`/`defaultModel` 字段名原样保留;标题 `mode/provider/model`
257
- 改为 `titleMode/titleProvider/titleModel`(一次性迁移 cordis.patch.yml 中的配置块)。
258
-
259
- **没合并谁**:`model-search`(占输入栏 slot,崩溃自动回退内置菜单,独立价值明确)、
260
- `computer-use`(原生运行时)、`read-image-preview`(通用图像卡片,刻意为任何图像工具设计)、
261
- `mcp-ui` / `shell-selector`(功能域不同)保持独立。
112
+ ```sh
113
+ node --test tests/*.test.mjs
114
+ ```
262
115
 
263
- **迁移指引**(从旧结构升级时):
116
+ - `image.test.mjs`:绘图传输、工具 schema、Remote 方法与热配置(本地 HTTP,不外联);
117
+ - `image-link.test.mjs`:模型行「绘图」勾选的推导与增量写入(端点/凭据复用、默认项、取消勾选只删自己创建的条目);
118
+ - `reasoning-efforts.test.mjs`:推理档位写入规划,不覆盖官方已存 API 值;
119
+ - `adaptive-thinking.test.mjs`:思考格式开关的写入规划 + 对已部署 pi-ai 的请求体耦合守卫(需要 `DSH_TEST_DEPLOY_ROOT`,跳过时不算失败)。
264
120
 
265
- 1. `cordis.patch.yml` 里原 `- id: image-generation` 块的 `config:` 内容(models、defaultModel)
266
- 原样搬进 `- id: model-tuning` 块;
267
- 2. 原用户 settings 里 `title-model:` 段的 `mode/provider/model` 若为 custom,改写到
268
- `model-tuning:` 段的 `titleMode/titleProvider/titleModel`;
269
- 3. 从 profile 移除 `dsh-plugin-image-generation` 与 `dsh-plugin-title-model` 两个 bundle;
270
- 4. 重启 profile。
121
+ 这些测试不是实机验证。实机验证放在隔离 profile(见 [docs/DEVELOPMENT.md](../docs/DEVELOPMENT.md#隔离测试-profile不要动桌面端的-profile)):确认官方 Models 卡片出现「兼容与推理」、开关写入后会话日志里的请求体变化、绘图页能出图。**不要用桌面端正在运行的 profile 做验证。**