diff --git a/ui/src/ui/chat-model-select-state.ts b/ui/src/ui/chat-model-select-state.ts index 5dbab89c576..d05122f42d1 100644 --- a/ui/src/ui/chat-model-select-state.ts +++ b/ui/src/ui/chat-model-select-state.ts @@ -6,7 +6,7 @@ import { normalizeChatModelOverrideValue, resolvePreferredServerChatModelValue, } from "./chat-model-ref.ts"; -import { normalizeLowercaseStringOrEmpty } from "./string-coerce.ts"; +import { pushUniqueTrimmedSelectOption } from "./select-options.ts"; import type { ModelCatalogEntry } from "./types.ts"; type ChatModelSelectStateInput = Pick< @@ -65,16 +65,7 @@ function buildChatModelOptions( const options: ChatModelSelectOption[] = []; const addOption = (value: string, label?: string) => { - const trimmed = value.trim(); - if (!trimmed) { - return; - } - const key = normalizeLowercaseStringOrEmpty(trimmed); - if (seen.has(key)) { - return; - } - seen.add(key); - options.push({ value: trimmed, label: label ?? trimmed }); + pushUniqueTrimmedSelectOption(options, seen, value, (trimmed) => label ?? trimmed); }; for (const entry of catalog) { diff --git a/ui/src/ui/chat/session-controls.ts b/ui/src/ui/chat/session-controls.ts index 976ae65ff60..42fcb41b679 100644 --- a/ui/src/ui/chat/session-controls.ts +++ b/ui/src/ui/chat/session-controls.ts @@ -8,6 +8,7 @@ import { } from "../chat-model-select-state.ts"; import { refreshVisibleToolsEffectiveForCurrentSession } from "../controllers/agents.ts"; import { loadSessions } from "../controllers/sessions.ts"; +import { pushUniqueTrimmedSelectOption } from "../select-options.ts"; import { parseAgentSessionKey } from "../session-key.ts"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "../string-coerce.ts"; import { @@ -146,24 +147,17 @@ function buildThinkingOptions( const options: ChatThinkingSelectOption[] = []; const addOption = (value: string, label?: string) => { - const trimmed = value.trim(); - if (!trimmed) { - return; - } - const key = normalizeLowercaseStringOrEmpty(trimmed); - if (seen.has(key)) { - return; - } - seen.add(key); - options.push({ - value: trimmed, - label: + pushUniqueTrimmedSelectOption( + options, + seen, + value, + (trimmed) => label ?? trimmed .split(/[-_]/g) .map((part) => (part ? part[0].toUpperCase() + part.slice(1) : part)) .join(" "), - }); + ); }; for (const label of listThinkingLevelLabels(provider)) { diff --git a/ui/src/ui/select-options.ts b/ui/src/ui/select-options.ts new file mode 100644 index 00000000000..b27867189b0 --- /dev/null +++ b/ui/src/ui/select-options.ts @@ -0,0 +1,24 @@ +import { normalizeLowercaseStringOrEmpty } from "./string-coerce.ts"; + +export type SelectOption = { + value: string; + label: string; +}; + +export function pushUniqueTrimmedSelectOption( + options: SelectOption[], + seen: Set, + value: string, + labelForValue: (trimmed: string) => string, +) { + const trimmed = value.trim(); + if (!trimmed) { + return; + } + const key = normalizeLowercaseStringOrEmpty(trimmed); + if (seen.has(key)) { + return; + } + seen.add(key); + options.push({ value: trimmed, label: labelForValue(trimmed) }); +}