fix(web): address model image settings review

This commit is contained in:
kingwl committed 2026-09-15 15:13:56 +08:00
1 parent 3df6f92d03
commit 41e591b3e4
9 files changed
+15 -11

No files matched your search

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-09-14-model-image-input-settings.md
2026-09-14-model-image-input-settings.md: b418fe46496aa6ed40b427e30f5340b24a6b8da0
2026-09-14-model-image-input-settings.zh.md: 0cc777bc9b8f942184524c9c6c0774acd9642956
2026-09-14-model-image-input-settings.md: ef328400332aa58c02a450ead0195eff124c5fdf
2026-09-14-model-image-input-settings.zh.md: 70ec427b138026124cad2ffdb1fc5f60597abe8a
@@ -16,6 +16,8 @@ The shared field replaces one drafted row and preserves unrelated metadata. Sele
## Alternatives considered
**Keep `input` editable only in the settings document.** The [earlier pi-ai modality decision](../../archived/architecture/2026-08-12-pi-ai-route-default-input-modalities.md) kept this field outside the model-list editor. That leaves users who add custom vision models through the UI unable to enable their image input there. Per-row editing supplies that configuration while the default choice preserves catalog inheritance.
**A two-state switch.** Treating an absent pi-ai declaration as disabled would misrepresent inherited vision support and encourage overwriting catalog defaults. The explicit Default choice preserves the adapter's existing resolution rules.
**Keep image limits when disabling DeepSeek images.** This leaves a configuration that the adapter refuses to save. Clearing the image-specific limits makes the selected text-only state valid while preserving unrelated model fields.
@@ -16,6 +16,8 @@ Status: implemented
## 考虑过的替代方案
**仅允许在设置文档中编辑 `input`。** [早期 pi-ai 输入模态决策](../../archived/architecture/2026-08-12-pi-ai-route-default-input-modalities.md)将该字段留在模型列表编辑器之外。这使通过 UI 添加自定义视觉模型的用户无法在同一界面启用图片输入。逐行编辑提供了该配置,而默认选项保留模型目录继承。
**两态开关。** 将缺省的 pi-ai 声明视为禁用,会错误表达继承的视觉能力,并促使用户覆盖模型目录的默认值。显式「默认」选项保留适配器现有的解析规则。
**禁用 DeepSeek 图片时保留图片限制。** 这会留下适配器拒绝保存的配置。清除图片专属限制,使选择的仅文本状态有效,同时保留无关模型字段。
@@ -221,11 +221,13 @@ describe.skipIf(MODE === 'record')('web e2e: first-run DeepSeek credential setup
expect(savedDefaults).toContain('id: deepseek-flash')
expect(savedDefaults).toContain('inputModalities:')
expect(savedDefaults).toContain('- text')
expect(savedDefaults).toContain('- image')
expect(savedDefaults).toContain('systemPromptUpdate: in-history')
await expect(scaffold.ctx.llm.resolveModelInfo('deepseek-official', 'deepseek-flash')).resolves.toMatchObject({
name: 'Configured Flash', inputModalities: ['text'], systemPromptUpdate: 'in-history',
})
await expect(scaffold.ctx.llm.resolveModelInfo('deepseek-official', 'deepseek-v4-flash-vision-exp')).resolves.toMatchObject({
inputModalities: ['text', 'image'],
})
await deepSeek.locator('xpath=ancestor::li').getByRole('button', { name: '编辑' }).click()
await settings.getByText('自定义设置').click()
for (let index = 0; index < 4; index++) {
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-settings-models/README.md
README.md: ac6b33a4d90eeb0164c1c0afb19ff57ca24775a6
README.zh.md: 5f780520adeaa4af0f133484af4ed9c377890c5d
README.md: a26cd22f8785f8f2c948ac74560ff85d80097577
README.zh.md: 82b9e031b477aa83c59acdfbade38f8282adefbd
+1 -1
View File
@@ -39,7 +39,7 @@ The collapsed 自定义设置 fold carries the curated extras: `baseURL` for bot
The DeepSeek card edits the shared `llm-deepseek` endpoint, credentials, and model catalog without a protocol selector. When Cordis YAML selects Messages, the public endpoint placeholder is `https://api.deepseek.com/anthropic`. Saving the card preserves protocol configuration.
Expand **Customized settings → Model options → Image input** to declare whether the model supports images. **Supported** writes text and image input; **Not supported** writes text only. **Default** removes the explicit declaration: DeepSeek defaults to text only, while pi-ai inherits the installed model catalog or provider default. DeepSeek stores this choice in `inputModalities`; pi-ai stores it in `input`. Selecting text only or default for DeepSeek also removes `imagePixelBudget` and `imageMaxBytes`, which its adapter rejects without image input. Declare support only for models that can actually process images.
Expand **Customized settings → Model options → Image input** to declare whether the model supports images. **Supported** writes text and image input; **Not supported** writes text only. DeepSeek's **Default (text only)** removes `inputModalities`; an absent declaration means text only. Pi-ai's **Use default** removes `input` and inherits the installed model catalog or provider default. Selecting **Not supported** or **Default (text only)** for DeepSeek also removes `imagePixelBudget` and `imageMaxBytes`, which its adapter rejects without image input. Declare support only for models that can actually process images.
### Adding and deleting providers
@@ -39,7 +39,7 @@ kind: "package-reference"
`llm-deepseek` 的 DeepSeek 卡片编辑共用的端点、凭据和模型目录,不提供协议选择器。Cordis YAML 选择 Messages 时,官方端点占位符为 `https://api.deepseek.com/anthropic`;保存卡片不会改写协议配置。
展开**自定义设置 → 模型选项 → 图片输入**,声明模型是否支持图片。选择**支持**会写入文本和图片输入;选择**不支持**会写入仅文本。选择**默认**会移除显式声明:DeepSeek 默认为仅文本,pi-ai 则继承已安装模型目录或提供方的默认值。DeepSeek 将此选项存入 `inputModalities`,pi-ai 存入 `input`。DeepSeek 切为仅文本或默认时,还会移除 `imagePixelBudget` 和 `imageMaxBytes`,因为适配器在没有图片输入时拒绝这些限制。仅为实际能够处理图片的模型声明支持。
展开**自定义设置 → 模型选项 → 图片输入**,声明模型是否支持图片。选择**支持**会写入文本和图片输入;选择**不支持**会写入仅文本。DeepSeek 的**默认(仅文本)**会移除 `inputModalities`;缺省的声明表示仅文本。Pi-ai 的**使用默认值**会移除 `input`,继承已安装模型目录或提供方的默认值。DeepSeek 选择**不支持**或**默认(仅文本)**时,还会移除 `imagePixelBudget` 和 `imageMaxBytes`,因为适配器在没有图片输入时拒绝这些限制。仅为实际能够处理图片的模型声明支持。
### 新增与删除提供方
@@ -164,8 +164,6 @@ export function ModelListEditor(props: ModelListEditorProps): ReactNode {
const [candidates, setCandidates] = useState<readonly LlmDiscoveredModel[] | undefined>(undefined)
const [picked, setPicked] = useState<ReadonlySet<string>>(new Set())
const [candidateQuery, setCandidateQuery] = useState('')
// Rows carry an id and a name; capacities are the exception, so they stay
// folded until asked for rather than crowding every row with four inputs.
const [expanded, setExpanded] = useState<ReadonlySet<number>>(new Set())
// Capacities are edited as text, so a field's keystrokes are held here rather
// than re-derived from the parsed count on every change — that would rewrite
@@ -432,8 +432,8 @@
}
/* Model list, shared with the pi-ai provider form: one bordered
entry per model, id and display name on the row, capacities behind the
row's own disclosure. The rules use this stylesheet's token vocabulary —
entry per model, id and display name on the row, capacities and image input
behind the row's own disclosure. The rules use this stylesheet's token vocabulary —
`--dsw-alias-border-subtle`, `--dsw-alias-text-tertiary`, and
`--dsw-alias-text-primary` are undefined here and would resolve to their
light-mode literals. */