diff --git a/packages/client/ui-agent-preset/README.i18n.yaml b/packages/client/ui-agent-preset/README.i18n.yaml
index b1314b349e..a7377027a2 100644
--- a/packages/client/ui-agent-preset/README.i18n.yaml
+++ b/packages/client/ui-agent-preset/README.i18n.yaml
@@ -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-agent-preset/README.md
-README.md: 0f1daeaa6014d4c3c88e6a69ff90cf1ecacdbaf7
-README.zh.md: 08e25d9e98b83a94a434248bb3dff60da1cc31ba
+README.md: c4c7df4e6fbe0479cac4767247c1b10fd65aad77
+README.zh.md: 84c02977ec18f89c06311b570428f92c2b459fb3
diff --git a/packages/client/ui-agent-preset/README.md b/packages/client/ui-agent-preset/README.md
index 0f1daeaa60..c4c7df4e6f 100644
--- a/packages/client/ui-agent-preset/README.md
+++ b/packages/client/ui-agent-preset/README.md
@@ -26,6 +26,8 @@ Options and the current default both come from one `agentPreset.list` call. The
A locally authored preset is exactly as privileged as the plugins it names, so the list marks `user` rows rather than presenting every preset as shipped and vetted.
+Preset files publish one unlocalized `name` and `description`, which Web uses for every `user` row and unknown `system` row. For the four shipped ids (`standard`, `code`, `minimal`, and `cordis`), Web resolves both fields from its active locale only when the roster marks the row `system`; an identically named `user` preset keeps its file metadata.
+
The row re-reads on `settings/changed` for its own namespace and on `connection/reset`: the roster is a live directory and the default is a settings field, so an external edit or a reconnect can both move it.
## The management section
diff --git a/packages/client/ui-agent-preset/README.zh.md b/packages/client/ui-agent-preset/README.zh.md
index 08e25d9e98..84c02977ec 100644
--- a/packages/client/ui-agent-preset/README.zh.md
+++ b/packages/client/ui-agent-preset/README.zh.md
@@ -26,6 +26,8 @@ chip 以部署默认值打开,其选择是**暂存**的——该界面先于
本地创作的 preset 的权限恰好等于它所引用的插件,因此列表会标注 `user` 行,而不是把每个 preset 都呈现为随附且已审核的。
+preset 文件提供一套未国际化的 `name` 与 `description`,Web 将其用于所有 `user` 行和未知的 `system` 行。对于四个随附 id(`standard`、`code`、`minimal` 与 `cordis`),只有名单将该行标记为 `system` 时,Web 才会从当前 locale 解析这两个字段;同名的 `user` preset 仍使用其文件元数据。
+
本行在自身命名空间的 `settings/changed` 以及 `connection/reset` 时重新读取:名单是一个活动目录,默认值是一项设置,外部编辑与重新连接都可能改变它。
## 管理分区
diff --git a/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx b/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
index 82688dd7c2..517a856e9a 100644
--- a/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
+++ b/packages/client/ui-agent-preset/src/client/AgentPresetLabel.tsx
@@ -15,6 +15,7 @@ import { IconThinkOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
// Type-only: pulls the ui-conversation SlotMap merge (the header actions).
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
import type { AgentPresetSettingsState } from './settings-store.ts'
+import { presetDisplayText } from './locales.ts'
import css from './AgentPresetLabel.module.css'
/** Registration-side business face for the header label. */
@@ -53,10 +54,11 @@ export function AgentPresetLabel({
if (preset === undefined) return null
const option = options.find(entry => entry.id === preset)
+ const text = option === undefined ? undefined : presetDisplayText(option, t)
return (
-
+
- {option?.name ?? preset}
+ {text?.name ?? preset}
)
}
diff --git a/packages/client/ui-agent-preset/src/client/AgentPresetRow.tsx b/packages/client/ui-agent-preset/src/client/AgentPresetRow.tsx
index ba875b0b95..eab363122c 100644
--- a/packages/client/ui-agent-preset/src/client/AgentPresetRow.tsx
+++ b/packages/client/ui-agent-preset/src/client/AgentPresetRow.tsx
@@ -8,7 +8,7 @@ import { useEffect, useState } from 'react'
import type { SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client'
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
import type { AgentPresetSettingsState } from './settings-store.ts'
-import type { AgentPresetSettingsKey } from './locales.ts'
+import { presetDisplayText, type AgentPresetSettingsKey } from './locales.ts'
import { PresetMenu } from './PresetMenu.tsx'
import css from './AgentPresetRow.module.css'
@@ -52,11 +52,11 @@ export function AgentPresetRow({ load, select, useAgentPreset, t }: AgentPresetR
// every session shares the host composition — the row simply does not exist.
if (state.status === 'unavailable') return null
const busy = state.status === 'loading' || state.status === 'saving'
- // The metadata name is what every other surface shows — the id is the
- // addressing, not the label. A preset that names itself nothing falls back
- // to its id, which is then all there is to say about it.
+ // Every preset surface applies the same display-copy rule. The id remains
+ // addressing rather than a label, except where no display name exists.
const chosen = state.options.find(option => option.id === state.currentValue)
- const label = state.currentValue === '' ? t('loading') : (chosen?.name ?? state.currentValue)
+ const chosenText = chosen === undefined ? undefined : presetDisplayText(chosen, t)
+ const label = state.currentValue === '' ? t('loading') : (chosenText?.name ?? state.currentValue)
const description: string = state.error ?? t('description')
return (
@@ -69,7 +69,7 @@ export function AgentPresetRow({ load, select, useAgentPreset, t }: AgentPresetR
options={state.options}
selectedId={state.currentValue}
label={label}
- userTrustLabel={t('userTrust')}
+ t={t}
buttonClassName={css.selector}
chevronClassName={css.chevron}
disabled={busy || !state.writable || state.options.length === 0}
diff --git a/packages/client/ui-agent-preset/src/client/AgentPresetSeat.tsx b/packages/client/ui-agent-preset/src/client/AgentPresetSeat.tsx
index 8e18471fbc..f4357870bb 100644
--- a/packages/client/ui-agent-preset/src/client/AgentPresetSeat.tsx
+++ b/packages/client/ui-agent-preset/src/client/AgentPresetSeat.tsx
@@ -19,6 +19,7 @@ import { IconChevronDownOutline14, IconThinkOutline16, Menu } from '@deepseek-ai
// Type-only: pulls the ui-conversation SlotMap merge (the hero seat).
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
import type { AgentPresetSeatState } from './seat-store.ts'
+import { presetDisplayText } from './locales.ts'
import css from './AgentPresetSeat.module.css'
/** Registration-side business face for the hero chip. */
@@ -57,22 +58,26 @@ export function AgentPresetSeat({ load, select, useAgentPresetSeat, t }: AgentPr
if (state.options.length === 0 || state.current === '') return null
const chosen = state.options.find(option => option.id === state.current)
+ const chosenText = chosen === undefined ? undefined : presetDisplayText(chosen, t)
return (
- {row.description ?? t('noDescription')}
+ {text.description ?? t('noDescription')}
{row.broken === undefined
? null
: {row.broken}}
@@ -231,7 +240,7 @@ export function AgentPresetSection(props: AgentPresetSectionProps): ReactNode {
type="button"
className={css.iconButton}
data-tip={t('view')}
- aria-label={`${t('view')}: ${row.name ?? row.id}`}
+ aria-label={`${t('view')}: ${text.name}`}
onClick={() => { void props.view(row.id) }}
>
@@ -243,7 +252,7 @@ export function AgentPresetSection(props: AgentPresetSectionProps): ReactNode {
type="button"
className={css.iconButton}
data-tip={state.hasDocument ? t('openLocation') : t('showLocation')}
- aria-label={`${state.hasDocument ? t('openLocation') : t('showLocation')}: ${row.name ?? row.id}`}
+ aria-label={`${state.hasDocument ? t('openLocation') : t('showLocation')}: ${text.name}`}
onClick={() => { void props.openLocation(row.id) }}
>
@@ -256,7 +265,7 @@ export function AgentPresetSection(props: AgentPresetSectionProps): ReactNode {
data-tip={row.broken !== undefined
? t('brokenNoCopy')
: state.authorable ? t('duplicate') : t('duplicateUnavailable')}
- aria-label={`${t('duplicate')}: ${row.name ?? row.id}`}
+ aria-label={`${t('duplicate')}: ${text.name}`}
onClick={() => { props.beginCopy(row.id) }}
>
@@ -267,7 +276,7 @@ export function AgentPresetSection(props: AgentPresetSectionProps): ReactNode {
type="button"
className={`${css.iconButton} ${css.iconDanger}`}
data-tip={t('delete')}
- aria-label={`${t('delete')}: ${row.name ?? row.id}`}
+ aria-label={`${t('delete')}: ${text.name}`}
onClick={() => { props.confirmDelete(row.id) }}
>
@@ -325,7 +334,7 @@ export function AgentPresetSection(props: AgentPresetSectionProps): ReactNode {
{ props.closeView() }}
- title={state.view === null ? '' : `${t('view')} · ${state.view.title}`}
+ title={state.view === null ? '' : `${t('view')} · ${viewedTitle}`}
closeLabel={t('close')}
description={t('composition')}
className={css.dialog as string}
diff --git a/packages/client/ui-agent-preset/src/client/PresetMenu.tsx b/packages/client/ui-agent-preset/src/client/PresetMenu.tsx
index 2a6bc6ea28..4b78d8ce6e 100644
--- a/packages/client/ui-agent-preset/src/client/PresetMenu.tsx
+++ b/packages/client/ui-agent-preset/src/client/PresetMenu.tsx
@@ -11,6 +11,7 @@
import { IconChevronDownOutline14, Menu } from '@deepseek-ai/dsh-client-ui-primitives'
import type { AgentPresetOption } from './settings-store.ts'
+import { presetDisplayText, type AgentPresetSettingsKey } from './locales.ts'
/** What one surface passes to the shared picker. */
export interface PresetMenuProps {
@@ -20,8 +21,8 @@ export interface PresetMenuProps {
selectedId: string
/** Text on the button; the surfaces word a pending roster differently. */
label: string
- /** Suffix marking a locally authored preset in the menu. */
- userTrustLabel: string
+ /** Active Web locale lookup. */
+ t: (key: AgentPresetSettingsKey) => string
/** Class for the trigger button, owned by the calling surface. */
buttonClassName: string | undefined
/** Class for the chevron, owned by the calling surface. */
@@ -42,22 +43,22 @@ export interface PresetMenuProps {
* @returns the menu and its trigger.
*/
export function PresetMenu({
- options, selectedId, label, userTrustLabel, buttonClassName, chevronClassName,
+ options, selectedId, label, t, buttonClassName, chevronClassName,
disabled, open, onOpenChange, onSelect,
}: PresetMenuProps) {
return (