Merge pull request #3079 from deepseek-harness/worktree/3077-model-selector-names-only

fix(web): hide model selector descriptions
This commit is contained in:
Yichen Jiang
2026-08-25 22:02:18 +08:00
committed by GitHub
6 changed files with 14 additions and 24 deletions
@@ -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-model-selection/README.md
README.md: 929d23ad4af1fe41e1cc7398ef432e73ca2a7a94
README.zh.md: 23e786d9e490b0739498a3e83703b42ebc345cbd
README.md: 1cefc8b0b0a569f6bc20a0fedab692710b39df43
README.zh.md: 272110006f58a5db70a439e78629a1675d349abf
+1 -1
View File
@@ -2,7 +2,7 @@
English | [中文](README.zh.md)
Model selection plugin, browser half: TWO entries over ONE per-session directory owned by `ModelDirectoryResolver` (`ctx.modelDirectories`). For ordinary sessions, the `/model` popupSelect contribution (registered through `ctx.commandUi`) and the composer's named `conversation.input.model` seat both load the session's advisory directory through `session.models` and submit through `session.selectModel` via the same `ModelDirectory` instance. The compact composer trigger opens a two-level Model/Effort menu: models stay provider-grouped, while the selected exact model supplies its adapter-owned effort names, descriptions, and default. `/model` applies the selected model's default effort, and the composer can then choose any advertised effort.
Model selection plugin, browser half: TWO entries over ONE per-session directory owned by `ModelDirectoryResolver` (`ctx.modelDirectories`). For ordinary sessions, the `/model` popupSelect contribution (registered through `ctx.commandUi`) and the composer's named `conversation.input.model` seat both load the session's advisory directory through `session.models` and submit through `session.selectModel` via the same `ModelDirectory` instance. The compact composer trigger opens a two-level Model/Effort menu: models stay provider-grouped, while the selected exact model supplies its adapter-owned effort names and default. The menu renders model and effort names only; catalog descriptions remain available to other consumers. `/model` applies the selected model's default effort, and the composer can then choose any advertised effort.
The Host-reported provider/model/reasoning `ModelSelection` is the single selection fact, but it is echoed only when the exact provider/model pair remains in the advertised groups; an absent catalog row leaves the routable selection intact while the trigger prompts `Select model`, no stale row is synthesized, and no Effort row is shown until the user picks an advertised model. Directory loads and selections share a generation counter so an older response never overwrites a newer one; a connection reset drops every resident projection and repulls the Host-restored selection before display. Provider-local metadata failures list inline while usable groups stay selectable, and selection failures retain the prior selection and directory.
@@ -2,7 +2,7 @@
[English](README.md) | 中文
模型选择插件(浏览器侧):**两个入口共用一份会话级目录**,由 `ModelDirectoryResolver``ctx.modelDirectories`)持有。对于普通会话,`/model` popupSelect 贡献项(经 `ctx.commandUi` 注册)与 composer 的具名 `conversation.input.model` slot 都通过同一个 `ModelDirectory` 实例,经 `session.models` 加载会话的建议目录,并经 `session.selectModel` 提交。紧凑型 composer 触发器会打开两级 Model/Effort 菜单:模型仍按提供方分组,所选具体模型则提供由其适配器持有的推理强度名称、说明和默认值。`/model` 应用所选模型的默认推理强度,composer 随后可以选择任一已公布的推理强度。
模型选择插件(浏览器侧):**两个入口共用一份会话级目录**,由 `ModelDirectoryResolver``ctx.modelDirectories`)持有。对于普通会话,`/model` popupSelect 贡献项(经 `ctx.commandUi` 注册)与 composer 的具名 `conversation.input.model` slot 都通过同一个 `ModelDirectory` 实例,经 `session.models` 加载会话的建议目录,并经 `session.selectModel` 提交。紧凑型 composer 触发器会打开两级 Model/Effort 菜单:模型仍按提供方分组,所选具体模型则提供由其适配器持有的推理强度名称和默认值。菜单只呈现模型与推理强度名称;目录中的说明仍可供其他消费方使用。`/model` 应用所选模型的默认推理强度,composer 随后可以选择任一已公布的推理强度。
Host 报告的 `ModelSelection` 是唯一的选择事实,其中包含提供方、模型与推理(reasoning)强度;但只有当该提供方/模型对仍在已公布分组中时才会回显。目录行缺席时,可路由的选择保持不变,但触发器会提示 `Select model`;系统不会合成陈旧行,且在用户选择已公布的模型之前不会显示 Effort 行。目录加载与选择共享一个代次计数器,旧响应不会覆盖新结果;连接重置会丢弃所有常驻目录投影,并在显示前重新拉取 Host 恢复的选择。各提供方的元数据获取失败会内联列出,同时可用分组仍可选择;选择失败会保留先前的选择和目录。
@@ -207,15 +207,6 @@
white-space: nowrap;
}
.description {
overflow: hidden;
color: var(--dsw-alias-label-tertiary);
font-size: 12px;
line-height: 18px;
text-overflow: ellipsis;
white-space: nowrap;
}
.check {
display: grid;
place-items: center;
@@ -33,7 +33,6 @@ interface EffortChoice {
key: string
effort: string | undefined
label: string
description?: string
}
/**
@@ -97,7 +96,6 @@ export function ModelSelect(
key: `effort:${effort.id}`,
effort: effort.id,
label: effort.name,
...effort.description === undefined ? {} : { description: effort.description },
})),
], [reasoning, t])
const busy = state.status === 'selecting'
@@ -303,9 +301,6 @@ export function ModelSelect(
>
<span className={css.optionCopy}>
<span className={css.modelName}>{model.name}</span>
{model.description !== undefined && (
<span className={css.description}>{model.description}</span>
)}
</span>
<span className={css.check}>
{selected ? <IconCheckOutline16 /> : null}
@@ -346,9 +341,6 @@ export function ModelSelect(
>
<span className={css.optionCopy}>
<span className={css.modelName}>{level.label}</span>
{level.description !== undefined && (
<span className={css.description}>{level.description}</span>
)}
</span>
<span className={css.check}>
{effectiveEffort === level.effort ? <IconCheckOutline16 /> : null}
@@ -36,7 +36,12 @@ function state(overrides: Partial<ModelDirectoryState> = {}): ModelDirectoryStat
groups: [{
id: 'deepseek-official',
name: 'DeepSeek',
models: [{ id: 'deepseek-v4-flash', name: 'DeepSeek-V4-Flash', reasoning }],
models: [{
id: 'deepseek-v4-flash',
name: 'DeepSeek-V4-Flash',
description: 'Fast catalog description',
reasoning,
}],
}],
failures: [],
status: 'ready',
@@ -48,7 +53,7 @@ function state(overrides: Partial<ModelDirectoryState> = {}): ModelDirectoryStat
afterEach(cleanup)
describe('ModelSelect reasoning effort', () => {
it('renders adapter metadata and submits the effort as part of the session selection', async () => {
it('renders effort names without descriptions and submits the effort as part of the session selection', async () => {
const directory = createSnapshotStore<ModelDirectoryState>(state())
const select = vi.fn(async (selection: ModelSelection) => {
directory.set(state({ current: selection }))
@@ -69,7 +74,8 @@ describe('ModelSelect reasoning effort', () => {
fireEvent.click(trigger)
fireEvent.click(screen.getByRole('menuitem', { name: /推理等级/ }))
expect(screen.getAllByRole('menuitemradio').map(item => item.textContent))
.toEqual(['Off', 'High', 'MaxLargest budget'])
.toEqual(['Off', 'High', 'Max'])
expect(screen.queryByText('Largest budget')).toBeNull()
fireEvent.click(screen.getByRole('menuitemradio', { name: /Max/ }))
await waitFor(() => {
@@ -133,6 +139,7 @@ describe('ModelSelect reasoning effort', () => {
fireEvent.click(screen.getByRole('menuitem', { name: /模型/ }))
expect(screen.queryByRole('menuitemradio', { name: 'removed-model' })).toBeNull()
expect(screen.getByRole('menuitemradio', { name: 'DeepSeek-V4-Flash' })).toBeTruthy()
expect(screen.queryByText('Fast catalog description')).toBeNull()
})
it('shows loading until the catalog and Session projection are both ready', async () => {