@lynn123411/dsh-model-submenu 0.3.5 → 0.3.10
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.
- package/DETAILS.md +60 -4
- package/README.md +12 -11
- package/lib/client.js +754 -631
- package/lib/client.js.map +1 -1
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +18 -17
- package/src/client/EffortSlider.tsx +159 -0
- package/src/client/EffortTint.tsx +61 -0
- package/src/client/ModelMenuBridge.tsx +203 -0
- package/src/client/ModelOptions.module.css +372 -0
- package/src/client/ModelPicker.tsx +10 -4
- package/src/client/ModelPickerHost.tsx +146 -0
- package/src/client/ModelRow.tsx +55 -96
- package/src/client/index.ts +65 -28
- package/src/client/level-color.ts +51 -0
- package/src/client/locales.ts +12 -33
- package/src/client/picker-state.ts +55 -0
- package/src/client/selection.ts +43 -17
- package/src/client/slider.ts +51 -0
- package/src/client/ModelSubmenu.module.css +0 -509
- package/src/client/ModelSubmenu.tsx +0 -429
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["css","IconCheckOutlineRegular","getItem","useId","useRef","useState","useMemo","rankByName","isMobileDevice","Modal","css","Input","IconSearchOutlineRegular","Tag","ShortcutKeys","useSyncExternalStore","useState","useRef","useId","useMemo","Tag","css","useCallback","useAnchoredPosition","IconFlatListOutlineRegular","StateDot","IconChevronDownOutlineRegular","createPortal","MenuSurface","Toast","IconWarningOutlineRegular"],"sources":["../src/client/icons.tsx","../src/client/ModelRow.tsx","../src/client/favorites.ts","../src/client/model-facts.ts","../src/client/rows.ts","../src/client/selection.ts","../src/client/ModelPicker.tsx","../src/client/effort-memory.ts","../src/client/ModelSubmenu.tsx","../src/client/facts-source.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * The one glyph this plugin draws itself.\n *\n * The shared icon library carries no star, so the favorite mark is defined here:\n * a five-point star whose outline and fill use the same path, which keeps the\n * hover-only outline and the standing filled state identical in geometry.\n */\n\n/**\n * Render the favorite star.\n * @param props.filled - draw the solid star; otherwise the outline.\n * @param props.size - square edge in pixels, matching the shared icon set's default.\n * @param props.className - extra class for colour and placement.\n * @returns the inline SVG.\n */\nexport function StarIcon({ filled, size = 14, className }: {\n readonly filled: boolean\n readonly size?: number | undefined\n readonly className?: string | undefined\n}) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth={filled ? 0 : 1.6}\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className={className}\n >\n <path d=\"M12 3.2l2.7 5.6 6.1.85-4.45 4.3 1.08 6.05L12 17.1l-5.43 2.9 1.08-6.05L3.2 9.65l6.1-.85z\" />\n </svg>\n )\n}\n","/**\n * One pickable model, as both surfaces render it.\n *\n * The menu row is one button that spans the whole width — name, favorite mark,\n * and the check for the model in use all live inside it, so hovering any part of\n * the row (including the star) highlights the row and clicking any part picks\n * the model. The picker row keeps the same shape but lifts the star out into its\n * own control, because favouriting there must not switch the model.\n */\n\nimport type { ReactNode } from 'react'\nimport { IconCheckOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives'\nimport { StarIcon } from './icons.tsx'\nimport css from './ModelSubmenu.module.css'\n\n/** How one row shows its favorite mark: part of the row, or a control of its own. */\nexport type StarMode = 'static' | 'interactive'\n\n/** Props shared by both row shapes. */\nexport interface ModelRowProps {\n /** The model's catalog name. */\n readonly name: string\n /** Optional catalog badge shown beside the name. */\n readonly badge?: ReactNode | undefined\n /** Whether this row is the model in use. */\n readonly selected: boolean\n /** Whether a selection is in flight, which locks the row. */\n readonly busy: boolean\n /** How the favorite mark behaves on this row. */\n readonly star: StarMode\n /** Whether the model is favorited right now. */\n readonly favorited: boolean\n /** The metadata line's text; undefined in the menu. */\n readonly meta?: string | undefined\n /** Localized accessible name for the star control. */\n readonly starLabel?: string | undefined\n /** Whether the star is a Tab stop right now (the picker's roving highlight). */\n readonly starTabStop?: boolean\n /** Tab order of the row itself; the picker keeps rows out of it so ↑/↓ own the walk. */\n readonly rowTabIndex?: number\n /** Pick this row. */\n readonly onPick: () => void\n /** The row took the keyboard, so its star becomes reachable. */\n readonly onFocusRow?: (() => void) | undefined\n /** Toggle this row's favorite; absent when the star is part of the row. */\n readonly onToggleFavorite?: (() => void) | undefined\n /** Extra row content, such as the picker's disabled reason. */\n readonly children?: ReactNode\n}\n\n/**\n * Render one model row.\n * @param props - the row's content and behaviour.\n * @returns the row element.\n */\nexport function ModelRow({\n name, badge, selected, busy, star, favorited, meta, starLabel,\n starTabStop = false, rowTabIndex, onPick, onFocusRow, onToggleFavorite, children,\n}: ModelRowProps) {\n const copy = (\n <>\n <span className={css.rowCopy}>\n <span className={css.rowName}>{name}</span>\n {badge}\n {meta !== undefined && meta !== '' && <span className={css.rowMeta}>{meta}</span>}\n </span>\n </>\n )\n const mark = favorited ? <StarIcon filled className={css.star} /> : null\n\n // The menu's row is one target: the star and the check sit inside the button,\n // so they inherit its hover fill and its click.\n if (star === 'static') {\n return (\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n tabIndex={rowTabIndex}\n className={css.rowPick}\n title={name}\n disabled={busy}\n onClick={onPick}\n onFocus={onFocusRow}\n data-selected={selected ? '' : undefined}\n data-favorited={favorited ? '' : undefined}\n >\n {copy}\n {mark !== null && <span className={css.starStatic} aria-hidden=\"true\">{mark}</span>}\n <span className={css.check} aria-hidden={!selected}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n {children}\n </button>\n )\n }\n\n return (\n <div\n className={css.row}\n data-selected={selected ? '' : undefined}\n data-favorited={favorited ? '' : undefined}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n tabIndex={rowTabIndex}\n className={css.rowPick}\n title={name}\n disabled={busy}\n onClick={onPick}\n onFocus={onFocusRow}\n >\n {copy}\n </button>\n <button\n type=\"button\"\n className={css.starButton}\n aria-pressed={favorited}\n aria-label={starLabel}\n tabIndex={starTabStop ? 0 : -1}\n disabled={busy}\n onClick={onToggleFavorite}\n >\n <StarIcon filled={favorited} className={css.star} />\n </button>\n <span className={css.check} aria-hidden={!selected}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n {children}\n </div>\n )\n}\n","/**\n * The favorite-model table the picker keeps in the browser.\n *\n * One browser-wide key holds `{ provider, model }` rows: the provider route key\n * and the model id are the catalog's own identity, so a favorite survives a\n * display-name change and never collides across providers. A value that cannot\n * be read or does not parse reads as an empty table — a privacy-mode browser or\n * a hand-edited row must never keep the menu from opening. Rows whose provider\n * leaves the catalog are kept, so restoring the provider restores the star.\n */\n\nimport type { ModelRef } from './rows.ts'\n\n/** One favorited model, identified the way the catalog identifies it. */\nexport type FavoriteModel = ModelRef\n\n/** The single browser-wide storage key holding the whole table. */\nexport const FAVORITES_KEY = 'dsh-model-submenu.favorites'\n\n/** The part of `Storage` this module uses; absent or throwing reads mean \"none\". */\nexport type FavoritesStorage = Pick<Storage, 'getItem' | 'setItem'>\n\n/**\n * Read the table, keeping only rows that name both halves.\n * @param storage - browser storage, or undefined when the browser withholds it.\n * @returns the stored favorites in stored order; empty when unreadable.\n */\nexport function readFavorites(storage: FavoritesStorage | undefined): FavoriteModel[] {\n const raw = getItem(storage)\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return []\n }\n if (!Array.isArray(parsed)) return []\n return parsed.filter((row): row is FavoriteModel => typeof row === 'object' && row !== null\n && typeof (row as FavoriteModel).provider === 'string'\n && typeof (row as FavoriteModel).model === 'string')\n}\n\n/**\n * Add or remove one model, writing the whole table back.\n * @param storage - browser storage, or undefined when writes are unavailable.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns the table after the change, whether or not the write landed.\n */\nexport function toggleFavorite(\n storage: FavoritesStorage | undefined,\n provider: string,\n model: string,\n): FavoriteModel[] {\n const current = readFavorites(storage)\n const next = isFavorite(current, provider, model)\n ? current.filter((row) => row.provider !== provider || row.model !== model)\n : [...current, { provider, model }]\n try {\n storage?.setItem(FAVORITES_KEY, JSON.stringify(next))\n } catch {\n // A full quota or a locked-down browser loses the star, not the menu.\n }\n return next\n}\n\n/**\n * @param favorites - the table to search.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns whether that exact pair is favorited.\n */\nexport function isFavorite(\n favorites: readonly FavoriteModel[],\n provider: string,\n model: string,\n): boolean {\n return favorites.some((row) => row.provider === provider && row.model === model)\n}\n\n/**\n * Stable-partition a catalog so favorited rows lead, each part keeping the\n * catalog's own order.\n * @param rows - the catalog in its display order.\n * @param favorited - predicate answering whether one row is favorited.\n * @returns a new list; the input order when nothing is favorited.\n */\nexport function orderWithFavorites<T>(\n rows: readonly T[],\n favorited: (row: T) => boolean,\n): readonly T[] {\n const starred = rows.filter(favorited)\n if (starred.length === 0) return rows\n return [...starred, ...rows.filter((row) => !favorited(row))]\n}\n\nfunction getItem(storage: FavoritesStorage | undefined): string | null {\n try {\n return storage?.getItem(FAVORITES_KEY) ?? null\n } catch {\n return null\n }\n}\n","/**\n * What the settings document knows about one model, for the picker's metadata\n * line.\n *\n * The Host's model catalog carries only a name and a reasoning list; context\n * window and accepted modalities live in each provider's settings profile,\n * which the settings mirror already holds in the browser. This module joins\n * the two by the identity both agree on: the catalog's provider route key and\n * model id are exactly the settings profile's provider key and model id.\n *\n * Every field is answered independently. A provider whose profile lists no\n * models (an OAuth route such as the Kimi subscription, or the account\n * provider) answers `unknown` rather than guessing the route default, because\n * the line's rule is to omit what cannot be asserted.\n */\n\n/** Accepted-modality answer for one model. */\nexport type ImageAnswer = 'yes' | 'no' | 'unknown'\n\n/**\n * The model knowledge a shipped adapter carries for its own account route.\n *\n * The account route has no `models` list on purpose: the account listing\n * supplies the catalog and settings only carry per-model overrides. The same\n * adapter family ships a default catalog for its API-key route, and the account\n * route serves the same models, so those entries answer what the account\n * profile cannot. Ids and facts mirror the adapter's own table.\n */\nconst FAMILY_DEFAULTS: Readonly<Record<string, readonly {\n readonly id: string\n readonly contextWindow: number\n readonly images: boolean\n}[]>> = {\n 'deepseek-account': [\n { id: 'deepseek-flash', contextWindow: 1_000_000, images: true },\n { id: 'deepseek-v4-pro', contextWindow: 1_000_000, images: false },\n ],\n}\n\n/** The metadata the settings document can answer for one model. */\nexport interface ModelFacts {\n /** Exact advertised capacity, or undefined when the model declares none. */\n readonly contextWindow: number | undefined\n /** Whether the model accepts images; `unknown` means the document is silent. */\n readonly images: ImageAnswer\n}\n\n/** One provider directory row, as the Host's LLM directory reports it. */\nexport interface ConfigurableProviderRow {\n readonly provider: string\n readonly settingsNs: string\n readonly settingsPath: readonly string[]\n}\n\n/** One settings namespace view, as the describe answer carries it. */\nexport interface NamespaceRow {\n readonly ns: string\n readonly value: unknown\n}\n\n/** What one provider's profile may carry, across both adapter families. */\ninterface ProfileView {\n readonly models?: readonly Record<string, unknown>[]\n readonly defaultContextWindow?: unknown\n readonly defaultInput?: unknown\n}\n\ntype Record_ = Record<string, unknown>\n\n/**\n * Build the fact lookup from the settings answer.\n * @param providers - provider directory rows giving each route's settings address.\n * @param namespaces - the describe answer's namespace views.\n * @returns a lookup answering both fields for one provider and model.\n */\nexport function buildModelFacts(\n providers: readonly ConfigurableProviderRow[],\n namespaces: readonly NamespaceRow[],\n): (provider: string, model: string) => ModelFacts {\n const byName = new Map(namespaces.map((row) => [row.ns, row.value]))\n const profiles = new Map<string, ProfileView>()\n for (const row of providers) {\n const section = byName.get(row.settingsNs)\n const profile = readPath(section, row.settingsPath)\n if (isRecord(profile)) profiles.set(row.provider, profile as ProfileView)\n }\n return (provider, model) => {\n const profile = profiles.get(provider)\n const entry = profile?.models === undefined\n ? undefined\n : profile.models.find((candidate) => candidate.id === model)\n if (profile !== undefined && entry !== undefined) {\n const window = typeof entry.contextWindow === 'number' && entry.contextWindow > 0\n ? entry.contextWindow\n : undefined\n return { contextWindow: window, images: imageAnswer(entry, profile) }\n }\n // A route with no model list of its own (the account route) still serves its\n // adapter family's models; a declared override there wins over the default.\n const override = readOverride(profile, model)\n if (override !== undefined) {\n const window = typeof override.contextWindow === 'number' && override.contextWindow > 0\n ? override.contextWindow\n : undefined\n return {\n contextWindow: window,\n images: Array.isArray(override.inputModalities) ? containsImage(override.inputModalities) : 'unknown',\n }\n }\n const family = FAMILY_DEFAULTS[provider]?.find((candidate) => candidate.id === model)\n return family === undefined\n ? { contextWindow: undefined, images: 'unknown' }\n : { contextWindow: family.contextWindow, images: family.images ? 'yes' : 'no' }\n }\n}\n\n/**\n * Read one model entry's accepted image modalities.\n *\n * The two adapter families disagree about an omission. The Messages family\n * names the field `inputModalities`, and leaving it out means text only. The\n * pi-ai family names it `input`, and an empty or absent list defers to the\n * route's `defaultInput`; with no route default the answer stays unknown.\n */\nfunction imageAnswer(entry: Record_, profile: ProfileView): ImageAnswer {\n if (Array.isArray(entry.inputModalities)) return containsImage(entry.inputModalities)\n const defaultInput = Array.isArray(profile.defaultInput) ? profile.defaultInput : undefined\n if (Array.isArray(entry.input)) {\n if (entry.input.length > 0) return containsImage(entry.input)\n return defaultInput === undefined ? 'unknown' : containsImage(defaultInput)\n }\n return defaultInput === undefined ? 'no' : containsImage(defaultInput)\n}\n\n/** One model's declared override, when the route keeps a `modelOverrides` table. */\nfunction readOverride(profile: ProfileView | undefined, model: string): Record_ | undefined {\n const overrides = (profile as Record_ | undefined)?.modelOverrides\n if (!isRecord(overrides)) return undefined\n const entry = overrides[model]\n return isRecord(entry) ? entry : undefined\n}\n\nfunction containsImage(modalities: readonly unknown[]): ImageAnswer {\n return modalities.includes('image') ? 'yes' : 'no'\n}\n\n/**\n * Abbreviate one capacity the way the metadata line shows it.\n * @param tokens - exact advertised capacity in tokens.\n * @returns e.g. `1M ctx`, `1.5M ctx`, `272k ctx`, or `512 ctx` below a thousand.\n */\nexport function formatContextWindow(tokens: number): string {\n if (tokens >= 1_000_000) return `${trimNumber(tokens / 1_000_000)}M ctx`\n if (tokens >= 1_000) return `${Math.round(tokens / 1_000)}k ctx`\n return `${tokens} ctx`\n}\n\n/**\n * Build the metadata line's segments.\n * @param input.providerName - the provider's display name, omitted inside that provider's own tab.\n * @param input.facts - what the settings document answered.\n * @param input.thinks - whether the catalog advertises reasoning levels for this model.\n * @param input.effortLabel - the localized word for the reasoning segment.\n * @param input.imageLabel - the localized word for the image segment.\n * @returns the segments to join; an empty list means show no line.\n */\nexport function metaSegments(input: {\n readonly providerName?: string\n readonly facts: ModelFacts\n readonly thinks: boolean\n readonly effortLabel: string\n readonly imageLabel: string\n}): readonly string[] {\n const segments: string[] = []\n if (input.providerName !== undefined) segments.push(input.providerName)\n if (input.facts.contextWindow !== undefined) segments.push(formatContextWindow(input.facts.contextWindow))\n if (input.thinks) segments.push(input.effortLabel)\n if (input.facts.images === 'yes') segments.push(input.imageLabel)\n return segments\n}\n\nfunction trimNumber(value: number): string {\n const rounded = Math.round(value * 10) / 10\n return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1)\n}\n\nfunction readPath(value: unknown, path: readonly string[]): unknown {\n let cursor = value\n for (const key of path) {\n if (!isRecord(cursor)) return undefined\n cursor = cursor[key]\n }\n return cursor\n}\n\nfunction isRecord(value: unknown): value is Record_ {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","/**\n * Catalog flattening, tab derivation, and query matching for the picker.\n *\n * The model catalog groups models by provider; the picker shows one flat list\n * with a tab per provider, so both surfaces read from these rows. Matching\n * delegates to the shell's own ranker, which is why a query behaves the same\n * here as in the built-in menu: case-insensitive, ordered subsequence, prefix\n * hits first.\n */\n\nimport type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client'\n\n/** One provider group of the shared catalog. */\nexport type ProviderGroup = ModelDirectoryState['groups'][number]\n\n/** One model inside a provider group. */\nexport type CatalogModel = ProviderGroup['models'][number]\n\n/** One flat catalog row, carrying the provider identity beside the model. */\nexport interface ModelRow extends ModelRef {\n readonly providerName: string\n /** The model id inside its provider, the other half of a selection. */\n readonly model: string\n /** The catalog entry itself, for name and reasoning metadata. */\n readonly entry: CatalogModel\n}\n\n/** A provider and one of its models: the pair every selection and favorite names. */\nexport interface ModelRef {\n readonly provider: string\n readonly model: string\n}\n\n/** One picker tab. */\nexport interface PickerTab {\n readonly id: string\n readonly label: string\n}\n\n/** The tab id standing for every provider. */\nexport const ALL_TAB = '*'\n\n/**\n * Flatten the catalog to one row per model.\n * @param groups - the shared directory's provider groups, in display order.\n * @returns the rows in catalog order.\n */\nexport function flattenGroups(groups: readonly ProviderGroup[]): readonly ModelRow[] {\n return groups.flatMap((group) => group.models.map((model) => ({\n provider: group.id,\n providerName: group.name,\n model: model.id,\n entry: model,\n })))\n}\n\n/**\n * Build the picker's tabs: the all-tab, then one per provider that has a model.\n * @param groups - the shared directory's provider groups.\n * @param allLabel - localized label for the all-tab.\n * @returns the tabs in catalog order.\n */\nexport function pickerTabs(groups: readonly ProviderGroup[], allLabel = 'All'): readonly PickerTab[] {\n return [\n { id: ALL_TAB, label: allLabel },\n ...groups.filter((group) => group.models.length > 0).map((group) => ({ id: group.id, label: group.name })),\n ]\n}\n\n/**\n * @param rows - the flat catalog.\n * @param tab - the tab id; the all-tab keeps every row.\n * @returns the rows the tab shows, in their current order.\n */\nexport function rowsForTab(rows: readonly ModelRow[], tab: string): readonly ModelRow[] {\n return tab === ALL_TAB ? rows : rows.filter((row) => row.provider === tab)\n}\n\n/** One row handed to the shell's ranker, carrying both searchable keys. */\nexport interface SearchCandidate {\n readonly name: string\n readonly label: string\n readonly row: ModelRow\n}\n\n/**\n * Shape rows as the shell's ranker candidates: the model name is the name, the\n * provider display name is the second key, so a query reaches either.\n * @param rows - the rows to search.\n * @returns candidates in row order.\n */\nexport function searchCandidates(rows: readonly ModelRow[]): readonly SearchCandidate[] {\n return rows.map((row) => ({ name: row.entry.name, label: row.providerName, row }))\n}\n\n/**\n * Read the reasoning metadata the catalog advertises for one model.\n * @param groups - the shared directory's provider groups.\n * @returns the metadata, or undefined when that model advertises none.\n */\nexport function reasoningOf(\n groups: readonly ProviderGroup[],\n): (provider: string, model: string) => CatalogModel['reasoning'] {\n return (provider, model) => groups\n .find((group) => group.id === provider)\n ?.models.find((candidate) => candidate.id === model)\n ?.reasoning\n}\n\n/**\n * Filter rows by a query over the model name and the provider name.\n * @param rows - the rows to search.\n * @param query - the typed text; an empty or blank query keeps every row.\n * @param rank - the shell's own ranker, so this search behaves like every other one.\n * @returns the matching rows.\n */\nexport function searchRows(\n rows: readonly ModelRow[],\n query: string,\n rank: (items: readonly SearchCandidate[], query: string) => readonly SearchCandidate[],\n): readonly ModelRow[] {\n const trimmed = query.trim()\n if (trimmed === '') return rows\n return rank(searchCandidates(rows), trimmed).map((match) => match.row)\n}\n","/**\n * When the composer menu writes a selection.\n *\n * Both gestures are immediate: clicking a level submits it, clicking a model\n * submits it. The only quiet path is clicking the model already in use — that\n * closes the menu without a write. A model click also restores the level this\n * browser last used for that model, so switching away and back never silently\n * resets the effort.\n */\n\nimport type { ModelReasoning } from '@deepseek-ai/dsh-api-session-controller/types'\n\n/** One complete selection, as the directory's `select` takes it. */\nexport interface Selection {\n readonly provider: string\n readonly model: string\n readonly reasoningEffort?: string\n}\n\n/** One segment of the reasoning row. */\nexport interface EffortChoice {\n readonly key: string\n readonly effort: string | undefined\n readonly label: string\n}\n\n/**\n * Build the segments for one model's reasoning row.\n * @param reasoning - the catalog's reasoning metadata, undefined when the model has none.\n * @param providerDefaultLabel - the localized label for the \"follow the provider\" segment.\n * @returns the segments in catalog order; the provider-default one leads when the model declares no default.\n */\nexport function effortChoices(\n reasoning: ModelReasoning | undefined,\n providerDefaultLabel: string,\n): readonly EffortChoice[] {\n if (reasoning === undefined) return []\n return [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined, label: providerDefaultLabel }]\n : [],\n ...reasoning.efforts.map((level) => ({\n key: level.id,\n effort: level.id as string | undefined,\n label: level.name,\n })),\n ]\n}\n\n/**\n * The selection a level click submits.\n * @param live - the selection in force right now.\n * @param effort - the clicked level, undefined meaning the provider default.\n * @returns the selection to submit, or null when the level already is the live one.\n */\nexport function planEffortCommit(live: Selection, effort: string | undefined): Selection | null {\n if (sameEffort(live.reasoningEffort, effort)) return null\n return {\n provider: live.provider,\n model: live.model,\n ...effort === undefined ? {} : { reasoningEffort: effort },\n }\n}\n\n/**\n * The selection a model click submits.\n * @param live - the selection in force right now, null before a first selection resolves.\n * @param provider - the clicked model's provider.\n * @param model - the clicked model id.\n * @param reasoningOf - the catalog's reasoning metadata for one provider and model.\n * @param remembered - the level this browser last used for the target model, if any.\n * @returns the selection to submit, or null when the click changes nothing.\n */\nexport function planModelCommit(\n live: Selection | null,\n provider: string,\n model: string,\n reasoningOf: (provider: string, model: string) => ModelReasoning | undefined,\n remembered?: string | undefined,\n): Selection | null {\n if (live !== null && sameModel(live, provider, model)) return null\n const offered = reasoningOf(provider, model)\n // The target model's own memory is restored, so switching away and back never\n // silently resets the effort.\n const carried = offered !== undefined\n && remembered !== undefined\n && offered.efforts.some((level) => level.id === remembered)\n return {\n provider,\n model,\n ...carried ? { reasoningEffort: remembered } : {},\n }\n}\n\n/**\n * @param live - one selection.\n * @param provider - the provider to compare.\n * @param model - the model id to compare.\n * @returns whether both name the same model.\n */\nexport function sameModel(live: Selection, provider: string, model: string): boolean {\n return live.provider === provider && live.model === model\n}\n\n/**\n * @param liveEffort - the level in force, undefined meaning the provider default.\n * @param effort - the level in question.\n * @returns whether they name the same level.\n */\nexport function sameEffort(liveEffort: string | undefined, effort: string | undefined): boolean {\n return liveEffort === effort\n}\n","/**\n * The model picker: the centered dialog opened from the menu's last row.\n *\n * It is the one place every provider is visible at once — a search field, a tab\n * per provider with a model, and one flat list with each model's metadata line.\n * Favorites lead the list and can be toggled from a row's star without\n * selecting that row. A click commits at once; a rejected commit keeps the\n * dialog open so the user can retry or pick another model.\n */\n\nimport { useEffect, useId, useMemo, useRef, useState } from 'react'\nimport {\n IconSearchOutlineRegular,\n Input,\n Modal,\n ShortcutKeys,\n rankByName,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { ModelRow } from './ModelRow.tsx'\nimport { isFavorite, orderWithFavorites } from './favorites.ts'\nimport type { ModelFacts } from './model-facts.ts'\nimport { metaSegments } from './model-facts.ts'\nimport {\n ALL_TAB,\n flattenGroups,\n pickerTabs,\n reasoningOf,\n rowsForTab,\n searchRows,\n type CatalogModel,\n type ModelRow as CatalogRow,\n type PickerTab,\n} from './rows.ts'\nimport { Tag, isMobileDevice } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelFactsLookup } from './facts-source.ts'\nimport type { Selection } from './selection.ts'\nimport { planModelCommit } from './selection.ts'\nimport css from './ModelSubmenu.module.css'\n\n/** Props the seat hands the picker. */\nexport interface ModelPickerProps {\n /** Whether the dialog is showing. */\n readonly open: boolean\n /** Resolve a catalog badge's localized text for the active language. */\n readonly resolveText: (text: NonNullable<CatalogModel['badge']>['text']) => string\n /** The shared directory snapshot. */\n readonly state: ModelDirectoryState\n /** The selection in force, null before a first selection resolves. */\n readonly live: Selection | null\n /** The metadata lookup for the current settings answer. */\n readonly facts: ModelFactsLookup\n /** The favorite table right now. */\n readonly favorites: readonly { readonly provider: string; readonly model: string }[]\n /** Whether a selection is in flight. */\n readonly busy: boolean\n /** Submit one selection. */\n readonly onPick: (selection: Selection) => void\n /** Toggle one model's favorite. */\n readonly onToggleFavorite: (provider: string, model: string) => void\n /** Reload the catalog after a failure. */\n readonly onReload: () => void\n /** Close the dialog, optionally returning focus. */\n readonly onClose: () => void\n}\n\n/**\n * Render the picker.\n * @param props - the catalog, the live selection, and the picker's verbs.\n * @returns the dialog; nothing while closed.\n */\nexport function ModelPicker({\n open, resolveText, state, live, facts, favorites, busy, onPick, onToggleFavorite, onReload, onClose, t,\n}: ModelPickerProps & PropsLocale<'modelSubmenu'>) {\n const id = useId()\n const searchRef = useRef<HTMLInputElement | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [query, setQuery] = useState('')\n const [tab, setTab] = useState(ALL_TAB)\n const [highlight, setHighlight] = useState(0)\n const tabRefs = useRef(new Map<string, HTMLButtonElement>())\n\n const tabs = useMemo(() => pickerTabs(state.groups, t('picker.all')), [state.groups, t])\n const reason = useMemo(() => reasoningOf(state.groups), [state.groups])\n const rows = useMemo(() => orderWithFavorites(\n rowsForTab(flattenGroups(state.groups), tab),\n (row) => isFavorite(favorites, row.provider, row.model),\n ), [state.groups, tab, favorites])\n // Search runs inside the favorite partition, never across it: a query must not\n // pull an unstarred model above a starred one, because favorites lead the list\n // whether or not a query is typed.\n const visible = useMemo(() => orderWithFavorites(\n searchRows(rows, query, rankByName),\n (row) => isFavorite(favorites, row.provider, row.model),\n ), [rows, query, favorites])\n\n useEffect(() => {\n if (!open) return\n setQuery('')\n setTab(ALL_TAB)\n setHighlight(0)\n if (listRef.current !== null) listRef.current.scrollTop = 0\n // 粗指针设备不自动聚焦文本输入:移动端弹键盘会顶起布局,宿主座位也这样守。\n const frame = requestAnimationFrame(() => {\n if (!isMobileDevice()) searchRef.current?.focus()\n })\n return () => { cancelAnimationFrame(frame) }\n }, [open])\n\n useEffect(() => {\n setHighlight((current) => visible.length === 0 ? 0 : Math.min(current, visible.length - 1))\n }, [visible.length])\n\n useEffect(() => {\n const row = listRef.current?.querySelector<HTMLElement>(`[data-row-index=\"${highlight}\"]`)\n row?.scrollIntoView({ block: 'nearest' })\n }, [highlight])\n\n if (!open) return null\n\n const activeRow = visible[highlight]\n const activeId = activeRow === undefined ? undefined : `${id}-row-${highlight}`\n const onSearchKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n if (visible.length === 0) return\n setHighlight((current) => {\n const next = current + (event.key === 'ArrowDown' ? 1 : -1)\n return (next + visible.length) % visible.length\n })\n return\n }\n if (event.key === 'Enter' && activeRow !== undefined && !busy) {\n event.preventDefault()\n pick(activeRow)\n }\n }\n const pick = (row: CatalogRow) => {\n const selection = planModelCommit(live, row.provider, row.model, reason)\n if (selection === null) {\n onClose()\n return\n }\n onPick(selection)\n }\n /** Move to another tab and hand it the keyboard, in one step. */\n const goTab = (next: PickerTab | undefined) => {\n if (next === undefined || next.id === tab) return\n setTab(next.id)\n setHighlight(0)\n tabRefs.current.get(next.id)?.focus()\n }\n const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n const index = tabs.findIndex((candidate) => candidate.id === tab)\n if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {\n event.preventDefault()\n const step = event.key === 'ArrowRight' ? 1 : -1\n goTab(tabs[((index === -1 ? 0 : index) + step + tabs.length) % tabs.length])\n return\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n goTab(tabs[event.key === 'Home' ? 0 : tabs.length - 1])\n }\n }\n\n const failures = state.failures.filter((failure) => tab === ALL_TAB || failure.id === tab)\n const failed = state.error !== null && state.status === 'error'\n const loading = state.status === 'loading'\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={t('picker.title')}\n closeLabel={t('picker.close')}\n className={css.pickerDialog ?? ''}\n contentClassName={css.pickerContent ?? ''}\n >\n <div className={css.pickerSearch}>\n <Input\n ref={searchRef}\n className={css.pickerSearchInput ?? ''}\n type=\"text\"\n role=\"searchbox\"\n aria-label={t('picker.search')}\n aria-controls={`${id}-list`}\n aria-activedescendant={activeId}\n placeholder={t('picker.search')}\n icon={<IconSearchOutlineRegular size={14} />}\n value={query}\n readOnly={busy}\n onChange={(event) => { setQuery(event.target.value) }}\n onKeyDown={onSearchKeyDown}\n data-modal-autofocus=\"\"\n />\n </div>\n <div className={css.pickerTabs} role=\"tablist\" aria-label={t('picker.title')}>\n {tabs.map((entry) => (\n <button\n key={entry.id}\n ref={(node) => {\n if (node === null) tabRefs.current.delete(entry.id)\n else tabRefs.current.set(entry.id, node)\n }}\n type=\"button\"\n role=\"tab\"\n id={`${id}-tab-${entry.id}`}\n aria-selected={entry.id === tab}\n aria-controls={`${id}-list`}\n tabIndex={0}\n className={css.pickerTab}\n onClick={() => {\n setTab(entry.id)\n setHighlight(0)\n }}\n onKeyDown={onTabKeyDown}\n onFocus={() => {\n if (entry.id !== tab) {\n setTab(entry.id)\n setHighlight(0)\n }\n }}\n >\n {entry.label}\n </button>\n ))}\n </div>\n <div\n ref={listRef}\n id={`${id}-list`}\n className={css.pickerList}\n role=\"menu\"\n aria-label={t('picker.title')}\n >\n {loading && <div className={css.notice}>{t('status.loading')}</div>}\n {failed && (\n <div className={css.notice}>\n <span>{t('status.failed', { message: state.error ?? '' })}</span>\n <button type=\"button\" className={css.retry} onClick={onReload}>{t('action.reload')}</button>\n </div>\n )}\n {failures.map((failure) => (\n <div className={css.notice} key={failure.id}>\n <span>{t('status.providerFailed', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={onReload}>{t('action.reload')}</button>\n </div>\n ))}\n {visible.length === 0 && !loading && !failed && (\n <div className={css.notice}>{state.groups.length === 0 ? t('status.empty') : t('picker.searchEmpty')}</div>\n )}\n {visible.map((row, index) => (\n <div key={`${row.provider}/${row.model}`} data-row-index={index} id={`${id}-row-${index}`}>\n <ModelRow\n name={row.entry.name}\n badge={row.entry.badge === undefined\n ? undefined\n : <Tag tone={row.entry.badge.tone} className={css.rowBadge}>{resolveText(row.entry.badge.text)}</Tag>}\n selected={live?.provider === row.provider && live.model === row.model}\n busy={busy}\n star=\"interactive\"\n favorited={isFavorite(favorites, row.provider, row.model)}\n meta={metaLine({\n row,\n facts: facts(row.provider, row.model),\n providerName: tab === ALL_TAB ? row.providerName : undefined,\n thinks: row.entry.reasoning !== undefined,\n effortLabel: t('meta.effort'),\n imageLabel: t('meta.images'),\n })}\n starLabel={isFavorite(favorites, row.provider, row.model)\n ? t('picker.unfavorite', { model: row.entry.name })\n : t('picker.favorite', { model: row.entry.name })}\n starTabStop={index === highlight}\n rowTabIndex={-1}\n onPick={() => { pick(row) }}\n onFocusRow={() => { setHighlight(index) }}\n onToggleFavorite={() => { onToggleFavorite(row.provider, row.model) }}\n />\n </div>\n ))}\n </div>\n <div className={css.pickerFooter}>\n <span className={css.footerHint}>\n <ShortcutKeys keys={['↑', '↓']} />\n <span>{t('picker.hintNavigate')}</span>\n <span className={css.footerDot}>·</span>\n <ShortcutKeys keys={['Enter']} />\n <span>{t('picker.hintSelect')}</span>\n <span className={css.footerDot}>·</span>\n <ShortcutKeys keys={['Esc']} />\n <span>{t('picker.hintClose')}</span>\n </span>\n </div>\n </Modal>\n )\n}\n\nfunction metaLine(input: {\n readonly row: CatalogRow\n readonly facts: ModelFacts\n readonly providerName: string | undefined\n readonly thinks: boolean\n readonly effortLabel: string\n readonly imageLabel: string\n}): string {\n return metaSegments({\n ...input.providerName === undefined ? {} : { providerName: input.providerName },\n facts: input.facts,\n thinks: input.thinks,\n effortLabel: input.effortLabel,\n imageLabel: input.imageLabel,\n }).join(' · ')\n}\n\n","/**\n * The per-model reasoning level this browser last chose.\n *\n * The Host stores one level per session, so switching models away and back\n * forgets what was picked for the first one. This module keeps that memory\n * beside the favorite table, keyed the same way: provider route key plus model\n * id. Remembering the provider default removes the row, so \"follow the\n * provider\" stays distinguishable from \"remembered a level\".\n */\n\n/** One remembered reasoning level. */\nexport interface RememberedEffort {\n readonly provider: string\n readonly model: string\n readonly effort: string\n}\n\n/** The single browser-wide storage key holding the whole memory. */\nexport const EFFORTS_KEY = 'dsh-model-submenu.efforts'\n\n/** The part of `Storage` this module uses; absent or throwing reads mean \"none\". */\nexport type EffortStorage = Pick<Storage, 'getItem' | 'setItem'>\n\n/**\n * Read the memory, keeping only rows naming both halves and a level.\n * @param storage - browser storage, or undefined when the browser withholds it.\n * @returns the remembered rows; empty when unreadable.\n */\nexport function readEfforts(storage: EffortStorage | undefined): RememberedEffort[] {\n const raw = getItem(storage)\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return []\n }\n if (!Array.isArray(parsed)) return []\n return parsed.filter((row): row is RememberedEffort => typeof row === 'object' && row !== null\n && typeof (row as RememberedEffort).provider === 'string'\n && typeof (row as RememberedEffort).model === 'string'\n && typeof (row as RememberedEffort).effort === 'string'\n && (row as RememberedEffort).effort !== '')\n}\n\n/**\n * @param memory - the rows to search.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns the level last chosen for that exact model, or undefined.\n */\nexport function effortFor(\n memory: readonly RememberedEffort[],\n provider: string,\n model: string,\n): string | undefined {\n return memory.find((row) => row.provider === provider && row.model === model)?.effort\n}\n\n/**\n * Remember one model's level, or forget it when the choice is the provider default.\n * @param storage - browser storage, or undefined when writes are unavailable.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @param effort - the chosen level, undefined meaning the provider default.\n * @returns the memory after the change, whether or not the write landed.\n */\nexport function rememberEffort(\n storage: EffortStorage | undefined,\n provider: string,\n model: string,\n effort: string | undefined,\n): RememberedEffort[] {\n const rest = readEfforts(storage).filter((row) => row.provider !== provider || row.model !== model)\n const next = effort === undefined ? rest : [...rest, { provider, model, effort }]\n try {\n storage?.setItem(EFFORTS_KEY, JSON.stringify(next))\n } catch {\n // A full quota or a locked-down browser loses the memory, not the menu.\n }\n return next\n}\n\nfunction getItem(storage: EffortStorage | undefined): string | null {\n try {\n return storage?.getItem(EFFORTS_KEY) ?? null\n } catch {\n return null\n }\n}\n","import { useCallback, useEffect, useId, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconChevronDownOutlineRegular,\n IconFlatListOutlineRegular,\n IconWarningOutlineRegular,\n MenuSurface,\n StateDot,\n Tag,\n Toast,\n useAnchoredPosition,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelDirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { ModelPicker } from './ModelPicker.tsx'\nimport { ModelRow } from './ModelRow.tsx'\nimport type { FactsSource } from './facts-source.ts'\nimport {\n isFavorite,\n orderWithFavorites,\n readFavorites,\n toggleFavorite,\n type FavoriteModel,\n type FavoritesStorage,\n} from './favorites.ts'\nimport { effortFor, readEfforts, rememberEffort, type RememberedEffort } from './effort-memory.ts'\nimport type { EffortChoice, Selection } from './selection.ts'\nimport { reasoningOf } from './rows.ts'\nimport { effortChoices, planEffortCommit, planModelCommit } from './selection.ts'\nimport css from './ModelSubmenu.module.css'\n\ntype ModelSubmenuProps = ModelSelectInjected & { locked: boolean } & PropsLocale<'modelSubmenu'> & {\n /** The live settings-derived metadata the picker's line reads. */\n readonly factsSource: FactsSource\n}\n\ntype ProviderGroup = ModelDirectoryState['groups'][number]\ntype CatalogModel = ProviderGroup['models'][number]\n\n/** Unplaced portal card: hidden but laid out at a fixed origin so offsetWidth/offsetHeight are real. */\nconst MEASURE_STYLE = {\n visibility: 'hidden',\n left: 0,\n top: 0,\n} as const\n\nconst cls = (...parts: readonly (string | false | undefined)[]): string => parts.filter((part) => part !== false && part !== undefined).join(' ')\n\n/**\n * The composer's model seat (`conversation.input.model`), taken over from the\n * built-in occupant with a provider-scoped menu: one provider's models above,\n * the reasoning row as segments, the cache warning, and the door to the picker\n * that lists every provider.\n *\n * Every click commits at once: a model, a reasoning level, or the picker door.\n * Closing the menu never writes anything, and the picker reads the level the\n * Host already accepted, so its \"current\" reading is never stale.\n */\nexport function ModelSubmenu({ locked, available, directory, load, select, resolveText, t, factsSource }: ModelSubmenuProps) {\n const state = useSyncExternalStore((fn) => directory.subscribe(fn), () => directory.getSnapshot())\n const [open, setOpen] = useState(false)\n const [pickerOpen, setPickerOpen] = useState(false)\n const [favorites, setFavorites] = useState<readonly FavoriteModel[]>(() => readFavorites(storageOf()))\n const [memory, setMemory] = useState<readonly RememberedEffort[]>(() => readEfforts(storageOf()))\n const [toast, setToast] = useState<{ seq: number; text: string } | null>(null)\n const toastSeq = useRef(0)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const id = useId()\n\n const groups = state.groups\n const current = state.current\n const currentGroup = current === null ? undefined : groups.find((group) => group.id === current.provider)\n const currentModel = currentGroup?.models.find((model) => model.id === current?.model)\n const reasoning = currentModel?.reasoning\n const effectiveEffort = current?.reasoningEffort ?? reasoning?.defaultEffort\n /**\n * The trigger's caption. A model that advertises no levels still says so in\n * the same place: the blue caption beside the name reads 默认 rather than\n * disappearing, so the shape of the control never changes with the model.\n */\n const effortLabel = reasoning === undefined || effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find((level) => level.id === effectiveEffort)?.name ?? effectiveEffort\n const choices = useMemo(() => effortChoices(reasoning, t('effort.providerDefault')), [reasoning, t])\n const busy = state.status === 'selecting'\n const live = useMemo(() => selectionOf(state), [state])\n const reason = useMemo(() => reasoningOf(groups), [groups])\n /** Resolve one catalog badge to its localized text and tone, matching the host seat. */\n const badgeOf = (model: CatalogModel) => model.badge === undefined\n ? undefined\n : <Tag tone={model.badge.tone} className={css.rowBadge}>{resolveText(model.badge.text)}</Tag>\n const triggerBadge = currentModel?.badge === undefined\n ? null\n : <Tag tone={currentModel.badge.tone} className={css.triggerBadge}>{resolveText(currentModel.badge.text)}</Tag>\n const facts = useSyncExternalStore((fn) => factsSource.subscribe(fn), () => factsSource.getSnapshot())\n\n const menuRows = useMemo(() => currentGroup === undefined ? [] : orderWithFavorites(\n currentGroup.models,\n (model) => isFavorite(favorites, currentGroup.id, model.id),\n ), [currentGroup, favorites])\n\n const raiseToast = (text: string) => {\n toastSeq.current += 1\n setToast({ seq: toastSeq.current, text })\n }\n const reload = () => {\n load()\n }\n const submit = (selection: Selection, onDone: (() => void) | null, onRejected?: () => void) => {\n select(selection).then((result) => {\n if (result === undefined || result.ok) {\n // The Host accepted it, so this is now the level this model uses.\n remember(selection.provider, selection.model, selection.reasoningEffort)\n onDone?.()\n return\n }\n onRejected?.()\n raiseToast(result.error.code === 'session/writer-held'\n ? t('error.sessionInUse')\n : t('error.action', { message: `${result.error.code}: ${result.error.message}` }))\n })\n }\n /** Close the menu. Closing writes nothing: every choice already committed on click. */\n const closeMenu = useCallback((restoreFocus: boolean) => {\n setOpen(false)\n if (restoreFocus) queueMicrotask(() => { triggerRef.current?.focus() })\n }, [])\n\n useEffect(() => {\n if (!open) return\n const closeOutside = (event: MouseEvent) => {\n if (rootRef.current?.contains(event.target as Node) === true) return\n if (menuRef.current?.contains(event.target as Node) === true) return\n closeMenu(false)\n }\n document.addEventListener('mousedown', closeOutside)\n return () => {\n document.removeEventListener('mousedown', closeOutside)\n }\n }, [open, closeMenu])\n\n useEffect(() => {\n if (!open) return\n const frame = requestAnimationFrame(() => {\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled])')\n const first = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"]:not([disabled])')\n const target = checked ?? first ?? triggerRef.current\n target?.scrollIntoView({ block: 'nearest' })\n target?.focus()\n })\n return () => { cancelAnimationFrame(frame) }\n }, [open])\n\n const menuPos = useAnchoredPosition({\n open: open && available,\n anchorRef: triggerRef,\n panelRef: menuRef,\n side: 'top',\n align: 'end',\n gap: 8,\n margin: 12,\n layoutKey: `${state.status}:${String(menuRows.length)}:${String(choices.length)}`,\n })\n\n if (!available) return null\n\n const show = () => {\n setOpen(true)\n reload()\n }\n /** The picker door: the level already landed on click, so only the surface changes. */\n const openPicker = () => {\n setOpen(false)\n setPickerOpen(true)\n }\n /** Record one model's level, so switching away and back restores it. */\n const remember = (provider: string, model: string, effort: string | undefined) => {\n setMemory(rememberEffort(storageOf(), provider, model, effort))\n }\n const chooseModel = (provider: string, model: CatalogModel) => {\n const picked = planModelCommit(live, provider, model.id, reason, effortFor(memory, provider, model.id))\n if (picked === null) {\n setOpen(false)\n queueMicrotask(() => { triggerRef.current?.focus() })\n return\n }\n // A model click is the decision: close at once, and keep the menu open when\n // the host rejects it so the user can try another model.\n setOpen(false)\n submit(picked, () => { queueMicrotask(() => { triggerRef.current?.focus() }) }, () => {\n // The host refused it: put the menu back so the user can pick another.\n setOpen(true)\n })\n }\n const rowButtons = () => [...(menuRef.current?.querySelectorAll<HTMLButtonElement>('[role=\"menuitemradio\"]:not([disabled])') ?? [])]\n const moveFocus = (offset: number) => {\n const items = rowButtons()\n if (items.length === 0) return\n const active = items.findIndex((item) => item === document.activeElement)\n items[active === -1 ? offset > 0 ? 0 : items.length - 1 : (active + offset + items.length) % items.length]?.focus()\n }\n const onEffortKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n if (choices.length === 0 || live === null) return\n event.preventDefault()\n const index = choices.findIndex((choice) => choice.effort === effectiveEffort)\n const step = event.key === 'ArrowRight' ? 1 : -1\n const next = choices[((index === -1 ? 0 : index) + step + choices.length) % choices.length]\n if (next === undefined) return\n const pending = planEffortCommit(live, next.effort)\n if (pending !== null) submit(pending, null)\n }\n const onRootKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n closeMenu(true)\n return\n }\n if (!open) return\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n event.preventDefault()\n closeMenu(true)\n return\n }\n const focused = document.activeElement\n const rows = rowButtons()\n if (focused instanceof HTMLButtonElement && rows.includes(focused)) {\n event.preventDefault()\n focused.click()\n return\n }\n if (focused !== triggerRef.current) return\n event.preventDefault()\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled])')\n ;(checked ?? rows[0])?.focus()\n return\n }\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveFocus(event.key === 'ArrowDown' ? 1 : -1)\n }\n }\n /**\n * The keyboard leaving the seat closes the menu — but that is not one of the\n * four closing gestures that write a mark, so it closes without committing.\n * Otherwise clicking the notice text or a divider inside the menu, which moves\n * focus without unmounting it, would land a level nobody asked to commit.\n */\n const onBlur = (event: React.FocusEvent) => {\n if (pickerOpen) return\n if (event.relatedTarget instanceof Node\n && (rootRef.current?.contains(event.relatedTarget) === true || menuRef.current?.contains(event.relatedTarget) === true)) return\n setOpen(false)\n }\n const toggleFavoriteOf = (provider: string, model: string) => {\n setFavorites(toggleFavorite(storageOf(), provider, model))\n }\n\n const waiting = current === null && state.status === 'loading'\n const modelLabel = waiting ? t('trigger.loading') : currentModel?.name ?? (current === null ? t('trigger.fallback') : `${current.provider}/${current.model}`)\n const triggerAria = waiting\n ? t('trigger.loading')\n : current === null\n ? t('trigger.selectAria')\n : effortLabel === undefined\n ? t('trigger.aria', { model: modelLabel })\n : t('trigger.ariaEffort', { model: modelLabel, effort: effortLabel })\n const providerName = currentGroup?.name\n ?? state.failures.find((failure) => failure.id === current?.provider)?.name\n ?? current?.provider\n ?? ''\n const providerFailure = current === null ? undefined : state.failures.find((failure) => failure.id === current.provider)\n\n return (\n <div ref={rootRef} className={css.root} onKeyDown={onRootKeyDown} onBlur={onBlur}>\n <button\n ref={triggerRef}\n type=\"button\"\n className={css.trigger}\n aria-label={triggerAria}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? `${id}-menu` : undefined}\n title={effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`}\n disabled={locked}\n onClick={() => {\n if (open) closeMenu(false)\n else show()\n }}\n >\n <IconFlatListOutlineRegular className={css.triggerIcon} size={16} />\n {triggerBadge}\n <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\n {busy\n ? <StateDot state=\"ongoing\" />\n : <IconChevronDownOutlineRegular className={cls(css.chevron, open && css.chevronOpen)} />}\n </button>\n {open && createPortal((\n <MenuSurface\n ref={menuRef}\n id={`${id}-menu`}\n className={css.menu}\n style={menuPos ?? MEASURE_STYLE}\n role=\"group\"\n aria-label={t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n <div className={css.providerName} title={providerName}>{providerName}</div>\n {state.status === 'loading' && <div className={css.notice}>{t('status.loading')}</div>}\n {state.error !== null && state.status === 'error' && (\n <div className={css.notice}>\n <span>{t('status.failed', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {providerFailure !== undefined && (\n <div className={css.notice}>\n <span>{t('status.providerFailed', { name: providerFailure.name, message: providerFailure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n <div className={cls(css.groups, 'scrollable')} role=\"menu\" aria-label={t('menu.aria')}>\n {menuRows.map((model) => (\n <ModelRow\n key={model.id}\n name={model.name}\n badge={badgeOf(model)}\n selected={current !== null && currentGroup !== undefined && current.provider === currentGroup.id && current.model === model.id}\n busy={busy}\n star=\"static\"\n favorited={currentGroup !== undefined && isFavorite(favorites, currentGroup.id, model.id)}\n onPick={() => {\n if (currentGroup !== undefined) chooseModel(currentGroup.id, model)\n }}\n />\n ))}\n {menuRows.length === 0 && state.status === 'ready' && (\n <div className={css.notice}>{t('status.empty')}</div>\n )}\n </div>\n {choices.length > 0 && (\n <>\n <div className={css.divider} />\n <div className={css.effortRow}>\n <span className={css.effortHeading}>{t('menu.effort')}</span>\n <div className={css.effortTrack} role=\"radiogroup\" aria-label={t('menu.effort')} onKeyDown={onEffortKeyDown}>\n {choices.map((choice: EffortChoice) => (\n <button\n key={choice.key}\n type=\"button\"\n role=\"radio\"\n aria-checked={choice.effort === effectiveEffort}\n className={css.effortSegment}\n disabled={busy}\n onClick={() => {\n if (live !== null) {\n const pending = planEffortCommit(live, choice.effort)\n if (pending !== null) submit(pending, null)\n }\n }}\n >\n {choice.label}\n </button>\n ))}\n </div>\n </div>\n <div className={css.divider} />\n </>\n )}\n <p className={css.hint}>{t('menu.hint')}</p>\n <div className={css.divider} />\n <button type=\"button\" role=\"menuitem\" className={css.moreRow} onClick={openPicker}>\n <IconFlatListOutlineRegular className={css.moreIcon} size={16} />\n <span>{t('menu.more')}</span>\n </button>\n </MenuSurface>\n ), document.body)}\n <ModelPicker\n open={pickerOpen}\n resolveText={resolveText}\n state={state}\n live={live}\n facts={facts}\n favorites={favorites}\n busy={busy}\n t={t}\n onPick={(selection) => { submit(selection, () => { setPickerOpen(false) }) }}\n onToggleFavorite={toggleFavoriteOf}\n onReload={reload}\n onClose={() => {\n setPickerOpen(false)\n queueMicrotask(() => { triggerRef.current?.focus() })\n }}\n />\n {toast !== null && (\n <Toast\n key={toast.seq}\n text={toast.text}\n icon={<IconWarningOutlineRegular />}\n anchor={rootRef.current?.closest('[data-composer-card]') ?? null}\n onDone={() => {\n setToast(null)\n }}\n />\n )}\n </div>\n )\n}\n\n/** The selection in force, or null while the host has not resolved one. */\nfunction selectionOf(state: ModelDirectoryState): Selection | null {\n if (state.current === null) return null\n return state.current.reasoningEffort === undefined\n ? { provider: state.current.provider, model: state.current.model }\n : { provider: state.current.provider, model: state.current.model, reasoningEffort: state.current.reasoningEffort }\n}\n\n/** Isolate the browser's storage so a locked-down browser reads as \"no favorites\". */\nfunction storageOf(): FavoritesStorage | undefined {\n try {\n return globalThis.localStorage\n } catch {\n return undefined\n }\n}\n","/**\n * The browser's live answer to \"what does the settings document know about this\n * model?\".\n *\n * Two host answers meet here: the shared settings mirror (which the settings\n * page already keeps warm) and the LLM provider directory that says which\n * settings namespace holds each provider's profile. Both can change while the\n * page is open — a saved profile, a reconnected host — so the join is rebuilt\n * whenever the mirror or the directory reports a change, and readers subscribe\n * to the lookup itself.\n */\n\nimport type { ModelFacts } from './model-facts.ts'\nimport {\n buildModelFacts,\n type ConfigurableProviderRow,\n type NamespaceRow,\n} from './model-facts.ts'\n\n/** One lookup answering both metadata fields for a provider and model. */\nexport type ModelFactsLookup = (provider: string, model: string) => ModelFacts\n\n/** The mirror face this source reads; a subset of the settings provider's. */\nexport interface DescribeFace {\n getSnapshot(): { readonly view: { readonly namespaces: readonly NamespaceRow[] } | undefined }\n subscribe(listener: () => void): () => void\n ensure(): Promise<void>\n}\n\n/** One remote answer, as the gateway returns it. */\nexport interface DirectoryAnswer {\n readonly ok: boolean\n readonly value?: readonly ConfigurableProviderRow[]\n}\n\n/** A stable, subscribable lookup over the current settings answer. */\nexport interface FactsSource {\n /** @returns the lookup for the current answer; the identity changes on every rebuild. */\n getSnapshot(): ModelFactsLookup\n /** @param listener - called after each rebuild. @returns the disposer. */\n subscribe(listener: () => void): () => void\n}\n\nconst EMPTY: ModelFactsLookup = () => ({ contextWindow: undefined, images: 'unknown' })\n\n/**\n * Join the settings mirror with the provider directory.\n * @param deps.describe - the settings mirror's describe face.\n * @param deps.listProviders - reads the LLM provider directory once.\n * @returns the source, plus `start` which wires both reads and returns its disposer.\n */\nexport function createFactsSource(deps: {\n readonly describe: DescribeFace\n readonly listProviders: () => Promise<DirectoryAnswer>\n}): { readonly source: FactsSource; readonly start: () => () => void } {\n const listeners = new Set<() => void>()\n let providers: readonly ConfigurableProviderRow[] = []\n let lookup: ModelFactsLookup = EMPTY\n\n const rebuild = () => {\n const namespaces = deps.describe.getSnapshot().view?.namespaces ?? []\n lookup = providers.length === 0 || namespaces.length === 0\n ? EMPTY\n : buildModelFacts(providers, namespaces)\n for (const listener of [...listeners]) listener()\n }\n\n return {\n source: {\n getSnapshot: () => lookup,\n subscribe: (listener) => {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n },\n start: () => {\n const off = deps.describe.subscribe(rebuild)\n void deps.describe.ensure().catch(() => { /* a failed read leaves the empty lookup in place */ })\n void deps.listProviders().then(\n (answer) => {\n providers = answer.ok && answer.value !== undefined ? answer.value : []\n rebuild()\n },\n () => { /* the directory being unavailable leaves every model's facts unknown */ },\n )\n rebuild()\n return () => {\n off()\n listeners.clear()\n }\n },\n }\n}\n","/** Locale bundles for the composer model menu and the picker it opens. */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelSubmenu'\n\n/** Locale keys the menu and the picker render. */\nexport type ModelSubmenuLocaleKey =\n | 'trigger.fallback'\n | 'trigger.loading'\n | 'trigger.selectAria'\n | 'trigger.aria'\n | 'trigger.ariaEffort'\n | 'menu.aria'\n | 'menu.effort'\n | 'menu.more'\n | 'menu.hint'\n | 'effort.providerDefault'\n | 'status.loading'\n | 'status.empty'\n | 'status.failed'\n | 'status.providerFailed'\n | 'action.reload'\n | 'error.action'\n | 'error.sessionInUse'\n | 'picker.title'\n | 'picker.close'\n | 'picker.search'\n | 'picker.searchEmpty'\n | 'picker.all'\n | 'picker.favorite'\n | 'picker.unfavorite'\n | 'picker.hintNavigate'\n | 'picker.hintSelect'\n | 'picker.hintClose'\n | 'meta.effort'\n | 'meta.images'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The composer model menu's copy. */\n modelSubmenu: ModelSubmenuLocaleKey\n }\n}\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh: Record<ModelSubmenuLocaleKey, string> = {\n 'trigger.fallback': '选择模型',\n 'trigger.loading': '正在加载模型…',\n 'trigger.selectAria': '选择模型',\n 'trigger.aria': '选择模型,当前 {model}',\n 'trigger.ariaEffort': '选择模型,当前 {model},思考等级 {effort}',\n 'menu.aria': '模型与思考等级',\n 'menu.effort': '思考',\n 'menu.more': '更多模型…',\n 'menu.hint': '提示:切换模型或思考程度会使既有的提示词缓存失效。建议新建会话,避免额外的 token 消耗。',\n 'effort.providerDefault': '默认',\n 'status.loading': '正在加载模型…',\n 'status.empty': '没有可用的模型。',\n 'status.failed': '模型列表加载失败:{message}',\n 'status.providerFailed': '{name} 加载失败:{message}',\n 'action.reload': '重新加载',\n 'error.action': '模型操作失败:{message}',\n 'error.sessionInUse': '当前会话已被占用,可能是其他正在运行的 DSH 导致的(如其他 dsh web、桌面端),请退出其他正在运行的 DSH 后重试。',\n 'picker.title': '切换模型',\n 'picker.close': '关闭',\n 'picker.search': '搜索模型或提供商…',\n 'picker.searchEmpty': '没有匹配的模型。',\n 'picker.all': '全部',\n 'picker.favorite': '收藏 {model}',\n 'picker.unfavorite': '取消收藏 {model}',\n 'picker.hintNavigate': '导航',\n 'picker.hintSelect': '选择',\n 'picker.hintClose': '关闭',\n 'meta.effort': '思考',\n 'meta.images': '图片输入',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<ModelSubmenuLocaleKey, string> = {\n 'trigger.fallback': 'Select model',\n 'trigger.loading': 'Loading models…',\n 'trigger.selectAria': 'Select model',\n 'trigger.aria': 'Select model, current {model}',\n 'trigger.ariaEffort': 'Select model, current {model}, effort {effort}',\n 'menu.aria': 'Model and effort',\n 'menu.effort': 'Effort',\n 'menu.more': 'More models…',\n 'menu.hint': 'Changing the model or the effort invalidates the existing prompt cache. Start a new session to avoid the extra token cost.',\n 'effort.providerDefault': 'Default',\n 'status.loading': 'Loading models…',\n 'status.empty': 'No models available.',\n 'status.failed': 'Model list failed to load: {message}',\n 'status.providerFailed': '{name} failed to load: {message}',\n 'action.reload': 'Reload',\n 'error.action': 'Model operation failed: {message}',\n 'error.sessionInUse': 'This session is already in use, possibly by another running DSH instance (such as dsh web or the desktop app). Quit other running DSH instances and try again.',\n 'picker.title': 'Switch model',\n 'picker.close': 'Close',\n 'picker.search': 'Search models or providers…',\n 'picker.searchEmpty': 'No matching models.',\n 'picker.all': 'All',\n 'picker.favorite': 'Favorite {model}',\n 'picker.unfavorite': 'Remove {model} from favorites',\n 'picker.hintNavigate': 'navigate',\n 'picker.hintSelect': 'select',\n 'picker.hintClose': 'close',\n 'meta.effort': 'Effort',\n 'meta.images': 'Images',\n}\n","import type { Context as ClientContext } from '@deepseek-ai/cordis'\n// Type-only: `slots` and its LocaleNamespaceMap merge come from the renderer and\n// the slot package; the composer seat's SlotMap entry and owner props from\n// ui-conversation; the `modelDirectories` service and the seat's injected face\n// from ui-model-selection's browser half; `configForms` from the settings\n// provider, whose shared mirror answers the metadata line.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { ModelSubmenu } from './ModelSubmenu.tsx'\nimport { createFactsSource, type DescribeFace } from './facts-source.ts'\nimport { NS, en, zh } from './locales.ts'\n\nexport { ModelSubmenu } from './ModelSubmenu.tsx'\n\n/**\n * Cordis services required by the browser half. `slots` is the contribution\n * registry, `sessions` tells whether a session may select a model,\n * `modelDirectories` owns the per-session catalog snapshot this seat renders\n * from, and `configForms` carries the settings provider's shared describe\n * mirror, which answers each model's context window and accepted modalities.\n * `remote`, `remote.llm`, and `remote.session` are declared because a service\n * method runs on the calling context: `directoryFor` reads\n * `this.ctx.remote.session`, and the provider directory that names each\n * settings address is read through `this.ctx.remote.llm`.\n */\nexport const inject = [\n 'configForms',\n 'locale',\n 'modelDirectories',\n 'remote',\n 'remote.llm',\n 'remote.session',\n 'sessions',\n 'slots',\n]\n\n/**\n * Client plugin body: register this plugin's dictionaries, then take over the\n * composer model seat below the built-in occupant's priority so this menu\n * renders in its place.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-submenu: dictionaries')\n ctx.inject(['slots', 'modelDirectories', 'configForms', 'remote'], (scope) => {\n const models = scope.modelDirectories\n const sessions = scope.sessions\n const facts = createFactsSource({\n describe: scope.configForms.describe() as DescribeFace,\n listProviders: () => scope.remote.llm.listConfigurableProviders(),\n })\n ctx.effect(() => facts.start(), 'dsh-model-submenu: model metadata')\n scope.slots.inject('conversation.input.model', () => scope.slots.register({\n name: 'conversation.input.model',\n priority: -100,\n registrant: '@lynn123411/dsh-model-submenu',\n locale: NS,\n inject: (sessionId) => {\n // The seat's inject parameter is typed as a bare string; the service\n // faces carry the branded SessionId of that same runtime value.\n const key = sessionId as Parameters<typeof models.directoryFor>[0]\n const directory = models.directoryFor(key)\n const available = sessions.subagentAddress(key) === undefined\n return {\n available,\n directory: directory.store,\n factsSource: facts.source,\n load: () => {\n if (available) directory.load().catch(() => {})\n },\n resolveText: (text) => ctx.locale.resolveText(text),\n select: (selection) => available ? directory.select(selection) : Promise.resolve(undefined),\n }\n },\n }, ModelSubmenu))\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useRef","useState","useSyncExternalStore","useRef","useState","css","useRef","useState","useSyncExternalStore","useMemo","createPortal","css","css","IconCheckOutlineRegular","getItem","useId","useRef","useState","useMemo","rankByName","isMobileDevice","Modal","css","Input","IconSearchOutlineRegular","Tag","ShortcutKeys","useSyncExternalStore","useState","useRef","useMemo","css","Toast","IconWarningOutlineRegular"],"sources":["../src/client/level-color.ts","../src/client/selection.ts","../src/client/EffortTint.tsx","../src/client/slider.ts","../src/client/EffortSlider.tsx","../src/client/ModelMenuBridge.tsx","../src/client/icons.tsx","../src/client/ModelRow.tsx","../src/client/favorites.ts","../src/client/model-facts.ts","../src/client/rows.ts","../src/client/ModelPicker.tsx","../src/client/effort-memory.ts","../src/client/ModelPickerHost.tsx","../src/client/picker-state.ts","../src/client/facts-source.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * The accent one reasoning level carries.\n *\n * \"Off\" carries no accent at all — the fill and the caption stay neutral, so\n * switching reasoning off reads as switching it off rather than as the first\n * shade of a ramp. Every level above it walks a blue-to-violet ramp, and the\n * highest level is the only one whose fill is a gradient.\n */\n\n/** Off: the dimmed label tone, the same neutral the Host uses for quiet text. */\nconst NEUTRAL = 'var(--dsw-alias-label-dimmed)';\n\n/** Lowest lit level: the blue the composer already uses for accents. */\nconst LOW = [77, 147, 248] as const;\n\n/** Highest level: violet. */\nconst HIGH = [147, 51, 234] as const;\n\n/**\n * @param t - a point on the ramp, 0 at the lowest lit level and 1 at the top.\n * @returns the ramp color there.\n */\nfunction ramp(t: number): string {\n const mix = (from: number, to: number): number => Math.round(from + (to - from) * t);\n return `rgb(${mix(LOW[0], HIGH[0])}, ${mix(LOW[1], HIGH[1])}, ${mix(LOW[2], HIGH[2])})`;\n}\n\n/**\n * @param index - the level's detent, 0 being \"off\".\n * @param count - number of detents.\n * @returns the level's color as a CSS color string.\n */\nexport function levelColor(index: number, count: number): string {\n if (index <= 0) return NEUTRAL;\n // The top level is always the violet end, even when it is the only lit one.\n if (isTopLevel(index, count)) return ramp(1);\n const span = Math.max(1, count - 2);\n return ramp(Math.min(Math.max((index - 1) / span, 0), 1));\n}\n\n/**\n * @param index - the level's detent.\n * @param count - number of detents.\n * @returns whether this level is the only one painted with a gradient.\n */\nexport function isTopLevel(index: number, count: number): boolean {\n return count > 1 && index === count - 1;\n}\n\n/** The top level's fill: the whole ramp, ending on the color its text takes. */\nexport const LEVEL_GRADIENT = `linear-gradient(90deg, ${ramp(0)}, ${ramp(1)})`;\n","/**\n * When the composer menu writes a selection.\n *\n * Both gestures are immediate: clicking a level submits it, clicking a model\n * submits it. The only quiet path is clicking the model already in use — that\n * closes the menu without a write. A model click also restores the level this\n * browser last used for that model, so switching away and back never silently\n * resets the effort.\n */\n\nimport type { ModelReasoning } from '@deepseek-ai/dsh-api-session-controller/types'\nimport type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client'\n\n/** One complete selection, as the directory's `select` takes it. */\nexport interface Selection {\n readonly provider: string\n readonly model: string\n readonly reasoningEffort?: string\n}\n\n/** One segment of the reasoning row. */\nexport interface EffortChoice {\n readonly key: string\n readonly effort: string | undefined\n readonly label: string\n}\n\n/**\n * Build the slider's detents for one model.\n *\n * The provider default is deliberately absent: it is a state, not a level, and\n * giving it a detent would read as the weakest reasoning instead of \"let the\n * provider decide\". The label above the track switches to it.\n * @param reasoning - the catalog's reasoning metadata, undefined when the model has none.\n * @returns one detent per advertised level, in catalog order.\n */\nexport function effortChoices(reasoning: ModelReasoning | undefined): readonly EffortChoice[] {\n if (reasoning === undefined) return []\n return reasoning.efforts.map((level) => ({\n key: level.id,\n effort: level.id as string | undefined,\n label: level.name,\n }))\n}\n\n/**\n * The selection a level click submits.\n * @param live - the selection in force right now.\n * @param effort - the clicked level, undefined meaning the provider default.\n * @returns the selection to submit, or null when the level already is the live one.\n */\nexport function planEffortCommit(live: Selection, effort: string | undefined): Selection | null {\n if (sameEffort(live.reasoningEffort, effort)) return null\n return {\n provider: live.provider,\n model: live.model,\n ...effort === undefined ? {} : { reasoningEffort: effort },\n }\n}\n\n/**\n * The selection a model click submits.\n * @param live - the selection in force right now, null before a first selection resolves.\n * @param provider - the clicked model's provider.\n * @param model - the clicked model id.\n * @param reasoningOf - the catalog's reasoning metadata for one provider and model.\n * @param remembered - the level this browser last used for the target model, if any.\n * @returns the selection to submit, or null when the click changes nothing.\n */\nexport function planModelCommit(\n live: Selection | null,\n provider: string,\n model: string,\n reasoningOf: (provider: string, model: string) => ModelReasoning | undefined,\n remembered?: string | undefined,\n): Selection | null {\n if (live !== null && sameModel(live, provider, model)) return null\n const offered = reasoningOf(provider, model)\n // The target model's own memory is restored, so switching away and back never\n // silently resets the effort.\n const carried = offered !== undefined\n && remembered !== undefined\n && offered.efforts.some((level) => level.id === remembered)\n return {\n provider,\n model,\n ...carried ? { reasoningEffort: remembered } : {},\n }\n}\n\n/**\n * The reasoning metadata the catalog advertises for the model in force.\n * @param state - the session's directory snapshot.\n * @returns the metadata, or undefined when no model is live or it advertises none.\n */\nexport function liveReasoning(state: ModelDirectoryState): ModelReasoning | undefined {\n const current = state.current\n if (current === null) return undefined\n return state.groups\n .find((group) => group.id === current.provider)\n ?.models.find((model) => model.id === current.model)\n ?.reasoning\n}\n\n/**\n * The selection in force, or null while the Host has not resolved one.\n * @param state - the session's directory snapshot.\n * @returns the live selection, with the effort only when one is set.\n */\nexport function selectionOf(state: ModelDirectoryState): Selection | null {\n if (state.current === null) return null\n return state.current.reasoningEffort === undefined\n ? { provider: state.current.provider, model: state.current.model }\n : {\n provider: state.current.provider,\n model: state.current.model,\n reasoningEffort: state.current.reasoningEffort,\n }\n}\n\n/**\n * @param live - one selection.\n * @param provider - the provider to compare.\n * @param model - the model id to compare.\n * @returns whether both name the same model.\n */\nexport function sameModel(live: Selection, provider: string, model: string): boolean {\n return live.provider === provider && live.model === model\n}\n\n/**\n * @param liveEffort - the level in force, undefined meaning the provider default.\n * @param effort - the level in question.\n * @returns whether they name the same level.\n */\nexport function sameEffort(liveEffort: string | undefined, effort: string | undefined): boolean {\n return liveEffort === effort\n}\n","/**\n * Tint the composer's effort caption with the level's color.\n *\n * The slider's fill and the menu's value already carry the level's color; the\n * caption on the collapsed trigger is the third place the level shows, and it\n * lives outside the menu. This entry stays mounted for the whole session and\n * writes that one color, so all three read as one signal.\n *\n * The caption is recognized as the trigger's `span[class*='triggerEffort']`\n * child — the same class-substring contract the menu row uses. When the model\n * declares no levels the span does not exist and nothing is written.\n */\nimport { useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react';\nimport type { ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client';\nimport { levelColor } from './level-color.ts';\nimport { effortChoices, liveReasoning } from './selection.ts';\n\n/** Props of the tint: the shared catalog face. */\nexport type EffortTintProps = Pick<ModelSelectInjected, 'available' | 'directory'>;\n\n/**\n * Render nothing and keep the trigger caption colored.\n * @param props - the session's catalog face.\n * @returns an inert marker.\n */\nexport function EffortTint({ available, directory }: EffortTintProps) {\n const markerRef = useRef<HTMLSpanElement | null>(null);\n const [caption, setCaption] = useState<HTMLElement | null>(null);\n const state = useSyncExternalStore(\n (listener) => directory.subscribe(listener),\n () => directory.getSnapshot(),\n );\n const levels = effortChoices(liveReasoning(state));\n const effort = state.current?.reasoningEffort;\n const chosen = effort === undefined ? -1 : levels.findIndex((level) => level.effort === effort);\n // The provider default has no color of its own: the caption keeps the Host's.\n const color = available && chosen >= 0 && levels.length >= 2\n ? levelColor(chosen, levels.length)\n : null;\n\n // The Host rebuilds the trigger on every model change, so the caption is\n // re-read after each render; the identity guard keeps that from looping.\n useLayoutEffect(() => {\n const card = markerRef.current?.closest('[data-composer-card]');\n const next = card?.querySelector<HTMLElement>(\n '[data-slot=\"conversation.input.model\"] button[aria-haspopup=\"menu\"] span[class*=\"triggerEffort\"]',\n ) ?? null;\n if (next !== caption) setCaption(next);\n });\n\n useLayoutEffect(() => {\n if (caption === null || color === null) return;\n const saved = caption.style.color;\n caption.style.color = color;\n return () => {\n caption.style.color = saved;\n };\n }, [caption, color]);\n\n return <span ref={markerRef} hidden />;\n}\n","/**\n * Geometry of the discrete effort slider.\n *\n * The track carries one detent per level and the knob's centre travels between\n * two ends inset by the knob radius, so the knob never overhangs the track. A\n * pointer position becomes the detent nearest it; a detent becomes a fraction\n * of the track that CSS turns into the knob's centre and the filled width.\n */\n\n/**\n * Knob diameter in CSS pixels, and the track's height: the slider stands as tall\n * as the row's text line. The centre stops half of it from each end of the\n * track, so the knob never overhangs.\n */\nexport const KNOB_SIZE = 20;\n\n/**\n * @param index - detent index.\n * @param count - number of detents.\n * @returns the knob centre as a fraction of the track, 0 at the first detent and 1 at the last.\n */\nexport function offsetOf(index: number, count: number): number {\n if (count <= 1) return 0;\n const clamped = Math.min(Math.max(index, 0), count - 1);\n return clamped / (count - 1);\n}\n\n/**\n * @param clientX - pointer position in viewport coordinates.\n * @param left - the track's left edge in viewport coordinates.\n * @param width - the track's width in pixels.\n * @param count - number of detents.\n * @returns the detent nearest the pointer, clamped to the two ends.\n */\nexport function stepAt(clientX: number, left: number, width: number, count: number): number {\n if (count <= 1) return 0;\n const usable = width - KNOB_SIZE;\n if (usable <= 0) return 0;\n const fraction = (clientX - left - KNOB_SIZE / 2) / usable;\n const clamped = Math.min(Math.max(fraction, 0), 1);\n return Math.round(clamped * (count - 1));\n}\n\n/**\n * @param fraction - a knob position between 0 and 1.\n * @returns the CSS length that puts the knob centre there, inset at both ends.\n */\nexport function knobOffset(fraction: number): string {\n const clamped = Math.min(Math.max(fraction, 0), 1);\n return `calc(${KNOB_SIZE / 2}px + ${clamped} * (100% - ${KNOB_SIZE}px))`;\n}\n","/**\n * The reasoning-level slider that replaces the Host's effort drill.\n *\n * The Host's second menu cell is a button that drills into a list of levels.\n * This slider sits inside that same cell, between the Host's label and value, so\n * the levels are reachable without leaving the menu. Levels are discrete: the\n * knob snaps to one detent per level, the drag only moves the knob, and the\n * release commits once. Keyboard arrows step and commit immediately.\n *\n * The fill takes the level's color, so the track and the two captions read as\n * one signal: \"off\" is neutral, the levels above it walk a blue-to-violet ramp,\n * and only the top level fills with the whole gradient.\n *\n * \"Provider default\" is not a detent: it is a state, drawn as an empty track\n * with a hollow knob, so it never reads as the lowest level.\n */\nimport { useRef, useState, type KeyboardEvent, type PointerEvent } from 'react';\nimport type { EffortChoice } from './selection.ts';\nimport { LEVEL_GRADIENT, isTopLevel, levelColor } from './level-color.ts';\nimport { knobOffset, offsetOf, stepAt } from './slider.ts';\nimport css from './ModelOptions.module.css';\n\n/** Props of the slider: the levels, the one in force, and the commit path. */\nexport interface EffortSliderProps {\n /** The levels in catalog order, lowest first. */\n readonly steps: readonly EffortChoice[];\n /** Index of the level in force, already clamped into `steps`. */\n readonly current: number;\n /** Whether the provider default is in force instead of a level. */\n readonly defaultActive: boolean;\n /** Where the knob rests while the provider default is in force. */\n readonly defaultIndex: number;\n /** Localized name of the provider default, read while it is in force. */\n readonly defaultLabel: string;\n /** Whether a selection is in flight; input is ignored while it is. */\n readonly busy: boolean;\n /** Accessible name, taken from the Host's own row label. */\n readonly label: string;\n /** @param index - the level the user settled on. */\n readonly onCommit: (index: number) => void;\n}\n\n/**\n * Render the slider.\n * @param props - levels, the level in force, and the commit path.\n * @returns one focusable slider over the discrete levels.\n */\nexport function EffortSlider({\n steps, current, defaultActive, defaultIndex, defaultLabel, busy, label, onCommit,\n}: EffortSliderProps) {\n const trackRef = useRef<HTMLDivElement | null>(null);\n // The drag index lives in a ref as well as in state: a press and a release can\n // arrive in one task, and the release must not read a render that never ran.\n const dragRef = useRef<number | null>(null);\n const [drag, setDrag] = useState<number | null>(null);\n const resting = defaultActive ? defaultIndex : current;\n const active = drag ?? resting;\n const beginDrag = (index: number | null): void => {\n dragRef.current = index;\n setDrag(index);\n };\n\n const indexAt = (clientX: number): number => {\n const track = trackRef.current;\n if (track === null) return active;\n const rect = track.getBoundingClientRect();\n return stepAt(clientX, rect.left, rect.width, steps.length);\n };\n\n const onPointerDown = (event: PointerEvent<HTMLDivElement>): void => {\n if (busy) return;\n // The Host's menu cell owns this subtree; without these the press would\n // also settle the cell and pull focus out of the slider.\n event.preventDefault();\n event.stopPropagation();\n beginDrag(indexAt(event.clientX));\n try {\n event.currentTarget.setPointerCapture(event.pointerId);\n } catch {\n // A synthetic pointer has no capture to take; the drag still tracks moves.\n }\n event.currentTarget.focus();\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>): void => {\n if (dragRef.current === null || busy) return;\n const next = indexAt(event.clientX);\n if (next !== dragRef.current) beginDrag(next);\n };\n\n const settle = (event: PointerEvent<HTMLDivElement>, commit: boolean): void => {\n if (dragRef.current === null) return;\n const next = indexAt(event.clientX);\n beginDrag(null);\n if (!commit) return;\n // Leaving the provider default is a change even when the knob lands where\n // the default already pointed.\n if (next !== current || defaultActive) onCommit(next);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n if (busy) return;\n const last = steps.length - 1;\n const next = event.key === 'ArrowRight' || event.key === 'ArrowUp'\n ? Math.min(active + 1, last)\n : event.key === 'ArrowLeft' || event.key === 'ArrowDown'\n ? Math.max(active - 1, 0)\n : event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? last\n : null;\n if (next === null) return;\n // The menu walks rows with the arrow keys; a slider keeps them for itself.\n event.preventDefault();\n event.stopPropagation();\n if (next !== current || defaultActive) onCommit(next);\n };\n\n const knobFraction = offsetOf(active, steps.length);\n const offset = knobOffset(knobFraction);\n // The provider default fills nothing: the knob shows where it lands, the\n // track stays empty so it never reads as a chosen level.\n const idle = defaultActive && drag === null;\n const filled = idle ? 0 : knobFraction;\n const fill = isTopLevel(active, steps.length) ? LEVEL_GRADIENT : levelColor(active, steps.length);\n return <div\n ref={trackRef}\n className={css.slider}\n role=\"slider\"\n tabIndex={0}\n aria-label={label}\n aria-valuemin={0}\n aria-valuemax={Math.max(0, steps.length - 1)}\n aria-valuenow={active}\n aria-valuetext={defaultActive && drag === null ? defaultLabel : steps[active]?.label}\n aria-disabled={busy || undefined}\n data-busy={busy ? '' : undefined}\n data-dragging={drag === null ? undefined : ''}\n data-default={defaultActive && drag === null ? '' : undefined}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={(event) => { settle(event, true); }}\n onPointerCancel={(event) => { settle(event, false); }}\n onKeyDown={onKeyDown}\n onClick={(event) => { event.stopPropagation(); }}\n >\n <div className={css.sliderTrack} aria-hidden=\"true\">\n <div className={css.sliderFill} style={{ width: knobOffset(filled), background: fill }} />\n {steps.map((step, index) => <span\n key={step.key}\n className={css.sliderTick}\n data-on={index <= active && !idle ? '' : undefined}\n style={{ left: knobOffset(offsetOf(index, steps.length)) }}\n />)}\n <div className={css.sliderKnob} style={{ left: offset }} />\n </div>\n </div>;\n}\n","/**\n * Bridge the Host's own model menu: the model cell opens the all-provider\n * picker, and the effort cell carries the reasoning-level slider.\n *\n * The Host draws the root menu's first two cells itself: the model cell drills\n * into the current provider's list, the effort cell into the levels. This plugin\n * wants the first to open its dialog and the second to stop drilling, and the\n * Host exposes no hook for either. This entry is mounted exactly while the root\n * pane is open, so it can take the click on the menu surface before the cells'\n * own handlers run and mount the slider into the effort cell.\n *\n * The cells are recognized as the menu surface's direct `role=\"menuitem\"`\n * children, which is the Host's root-menu shape; the options slot output sits in\n * its own wrapper, so other plugins' rows never join that list. When the second\n * cell is missing the model declares no reasoning levels and the row is left\n * alone; when the first is missing the click falls through to the Host.\n *\n * Clicking the cell's label switches to the provider default, which is a state\n * rather than a detent: the slider shows it as an empty track under a hollow\n * knob, so it never reads as the weakest level.\n */\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client';\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';\nimport { EffortSlider } from './EffortSlider.tsx';\nimport type { PickerStore } from './picker-state.ts';\nimport { effortChoices, liveReasoning, planEffortCommit, selectionOf, type Selection } from './selection.ts';\nimport css from './ModelOptions.module.css';\n\n/** Props of the bridge: menu state, the owning session, and the seat's injected face. */\nexport type ModelMenuBridgeProps = PropsRuntime<'conversation.input.model.options'>\n & PropsLocale<'modelSubmenu'>\n & Pick<ModelSelectInjected, 'available' | 'directory' | 'select'>\n & {\n /** Session whose catalog and picker this menu drives. */\n readonly sessionId: string;\n /** Carries the open request to the overlay view. */\n readonly picker: PickerStore;\n }\n\n/**\n * Render the marker, redirect the model cell, and mount the effort slider.\n * @param props - menu state, session, catalog face, and localized copy.\n * @returns an inert marker plus the slider while the effort cell is present.\n */\nexport function ModelMenuBridge({\n sessionId, picker, dismiss, reportFailure, available, directory, select, t,\n}: ModelMenuBridgeProps) {\n const markerRef = useRef<HTMLSpanElement | null>(null);\n const sliderRef = useRef<HTMLDivElement | null>(null);\n const [surface, setSurface] = useState<HTMLElement | null>(null);\n const [effortRow, setEffortRow] = useState<HTMLElement | null>(null);\n const [rowLabel, setRowLabel] = useState<string | null>(null);\n\n const state = useSyncExternalStore(\n (listener) => directory.subscribe(listener),\n () => directory.getSnapshot(),\n );\n const current = state.current;\n const reasoning = liveReasoning(state);\n const levels = useMemo(() => effortChoices(reasoning), [reasoning]);\n const declared = levels.findIndex((level) => level.effort === reasoning?.defaultEffort);\n const chosen = current?.reasoningEffort === undefined\n ? -1\n : levels.findIndex((level) => level.effort === current.reasoningEffort);\n // The provider default is a state, not a detent: it is in force whenever the\n // session carries no explicit level.\n const defaultActive = current !== null && current.reasoningEffort === undefined;\n const currentIndex = chosen >= 0 ? chosen : declared >= 0 ? declared : 0;\n const defaultIndex = declared >= 0 ? declared : 0;\n const canDefault = !defaultActive;\n const busy = state.pending !== null;\n // One detent is not a choice: leave the Host's row exactly as it is.\n const showSlider = available && levels.length >= 2 && effortRow !== null;\n\n // The Host rebuilds its cells on every render, so the surface and the effort\n // cell are re-read after each one; the identity guards keep that from looping.\n useLayoutEffect(() => {\n const foundSurface = markerRef.current?.closest('[data-menu-material]');\n const nextSurface = foundSurface instanceof HTMLElement ? foundSurface : null;\n if (nextSurface !== surface) setSurface(nextSurface);\n const cells = nextSurface === null\n ? []\n : [...nextSurface.querySelectorAll<HTMLElement>(':scope > button[role=\"menuitem\"]')];\n const nextRow = cells.length >= 2 ? cells[1] ?? null : null;\n if (nextRow !== effortRow) setEffortRow(nextRow);\n const nextLabel = nextRow?.querySelector(\"span[class*='cellLabel']\")?.textContent?.trim() ?? '';\n if (nextLabel !== (rowLabel ?? '')) setRowLabel(nextLabel);\n });\n\n const submit = (selection: Selection | null): void => {\n if (selection === null) return;\n void select(selection).then((result) => {\n if (result === undefined || result.ok) return;\n reportFailure(result.error.code === 'session/writer-held'\n ? t('error.sessionInUse')\n : t('error.action', { message: `${result.error.code}: ${result.error.message}` }));\n });\n };\n const commit = (index: number): void => {\n const live = selectionOf(state);\n const level = levels[index];\n if (live === null || level === undefined) return;\n submit(planEffortCommit(live, level.effort));\n };\n const commitDefault = (): void => {\n const live = selectionOf(state);\n if (live === null) return;\n submit(planEffortCommit(live, undefined));\n };\n\n // The Host rebuilds `dismiss` on every render, so the listener reads the\n // current one through a ref instead of being torn down and reinstalled.\n const latest = useRef({ sessionId, picker, dismiss, showSlider, canDefault, commitDefault });\n latest.current = { sessionId, picker, dismiss, showSlider, canDefault, commitDefault };\n\n useEffect(() => {\n if (surface === null) return;\n const redirect = (event: MouseEvent): void => {\n const target = event.target;\n if (!(target instanceof Node)) return;\n const cells = [...surface.querySelectorAll<HTMLElement>(':scope > button[role=\"menuitem\"]')];\n const modelCell = cells[0];\n if (modelCell !== undefined && modelCell.contains(target)) {\n // Capture on the surface runs before the React root's bubble listener, so\n // stopping here keeps the cell's own drill handler from ever running.\n event.preventDefault();\n event.stopPropagation();\n const request = latest.current;\n request.dismiss();\n request.picker.open(request.sessionId);\n return;\n }\n const row = cells[1];\n if (row === undefined || !row.contains(target) || !latest.current.showSlider) return;\n // The slider owns its own presses; only the label and the value are inert.\n if (sliderRef.current?.contains(target) === true) return;\n event.preventDefault();\n event.stopPropagation();\n const label = row.querySelector(\"span[class*='cellLabel']\");\n if (latest.current.canDefault && label !== null && label.contains(target)) {\n latest.current.commitDefault();\n return;\n }\n sliderRef.current?.querySelector<HTMLElement>('[role=\"slider\"]')?.focus();\n };\n surface.addEventListener('click', redirect, true);\n return () => {\n surface.removeEventListener('click', redirect, true);\n };\n }, [surface]);\n\n // The slider takes the whole slack beside the label: the value and the\n // chevron go, because the level is already written under the composer and the\n // row no longer drills anywhere. Every write is recorded and put back.\n useLayoutEffect(() => {\n if (effortRow === null || !showSlider) return;\n const label = effortRow.querySelector<HTMLElement>(\"span[class*='cellLabel']\");\n const value = effortRow.querySelector<HTMLElement>(\"span[class*='cellValue']\");\n const chevron = effortRow.querySelector<SVGElement>(\"svg[class*='cellChevron']\");\n const saved = {\n value: value?.style.display ?? '',\n chevron: chevron?.style.display ?? '',\n cursor: label?.style.cursor ?? '',\n title: label?.getAttribute('title') ?? null,\n };\n if (value !== null) value.style.display = 'none';\n if (chevron !== null) chevron.style.display = 'none';\n if (label !== null && canDefault) {\n label.style.cursor = 'pointer';\n label.title = t('effort.useDefault');\n }\n return () => {\n if (value !== null) value.style.display = saved.value;\n if (chevron !== null) chevron.style.display = saved.chevron;\n if (label !== null) {\n label.style.cursor = saved.cursor;\n if (saved.title === null) label.removeAttribute('title');\n else label.title = saved.title;\n }\n };\n }, [effortRow, showSlider, canDefault, t]);\n\n return <>\n <span ref={markerRef} hidden />\n {showSlider && effortRow !== null && createPortal(\n <div ref={sliderRef} className={css.sliderCell}>\n <EffortSlider\n steps={levels}\n current={currentIndex}\n defaultActive={defaultActive}\n defaultIndex={defaultIndex}\n defaultLabel={t('effort.providerDefault')}\n busy={busy}\n label={rowLabel !== null && rowLabel !== '' ? rowLabel : t('effort.label')}\n onCommit={commit}\n />\n </div>,\n effortRow,\n )}\n </>;\n}\n","/**\n * The one glyph this plugin draws itself.\n *\n * The shared icon library carries no star, so the favorite mark is defined here:\n * a five-point star whose outline and fill use the same path, which keeps the\n * hover-only outline and the standing filled state identical in geometry.\n */\n\n/**\n * Render the favorite star.\n * @param props.filled - draw the solid star; otherwise the outline.\n * @param props.size - square edge in pixels, matching the shared icon set's default.\n * @param props.className - extra class for colour and placement.\n * @returns the inline SVG.\n */\nexport function StarIcon({ filled, size = 14, className }: {\n readonly filled: boolean\n readonly size?: number | undefined\n readonly className?: string | undefined\n}) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill={filled ? 'currentColor' : 'none'}\n stroke=\"currentColor\"\n strokeWidth={filled ? 0 : 1.6}\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n className={className}\n >\n <path d=\"M12 3.2l2.7 5.6 6.1.85-4.45 4.3 1.08 6.05L12 17.1l-5.43 2.9 1.08-6.05L3.2 9.65l6.1-.85z\" />\n </svg>\n )\n}\n","/**\n * One pickable model in the picker.\n *\n * The star is its own control, because favouriting there must not switch the\n * model: the row button picks, the star toggles, and the check marks the model\n * in use.\n */\n\nimport type { ReactNode } from 'react';\nimport { IconCheckOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives';\nimport { StarIcon } from './icons.tsx';\nimport css from './ModelOptions.module.css';\n\n/** Props of one row. */\nexport interface ModelRowProps {\n /** The model's catalog name. */\n readonly name: string;\n /** Optional catalog badge shown beside the name. */\n readonly badge?: ReactNode | undefined;\n /** Whether this row is the model in use. */\n readonly selected: boolean;\n /** Whether a selection is in flight, which locks the row. */\n readonly busy: boolean;\n /** Whether the model is favorited right now. */\n readonly favorited: boolean;\n /** The metadata line's text. */\n readonly meta?: string | undefined;\n /** Localized accessible name for the star control. */\n readonly starLabel?: string | undefined;\n /** Whether the star is a Tab stop right now (the picker's roving highlight). */\n readonly starTabStop?: boolean;\n /** Tab order of the row itself; the picker keeps rows out of it so ↑/↓ own the walk. */\n readonly rowTabIndex?: number;\n /** Pick this row. */\n readonly onPick: () => void;\n /** The row took the keyboard, so its star becomes reachable. */\n readonly onFocusRow?: (() => void) | undefined;\n /** Toggle this row's favorite. */\n readonly onToggleFavorite: () => void;\n /** Extra row content, such as the picker's disabled reason. */\n readonly children?: ReactNode;\n}\n\n/**\n * Render one model row.\n * @param props - the row's content and behaviour.\n * @returns the row element.\n */\nexport function ModelRow({\n name, badge, selected, busy, favorited, meta, starLabel,\n starTabStop = false, rowTabIndex, onPick, onFocusRow, onToggleFavorite, children,\n}: ModelRowProps) {\n return <div\n className={css.row}\n data-selected={selected ? '' : undefined}\n data-favorited={favorited ? '' : undefined}\n >\n <button\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n tabIndex={rowTabIndex}\n className={css.rowPick}\n title={name}\n disabled={busy}\n onClick={onPick}\n onFocus={onFocusRow}\n >\n <span className={css.rowCopy}>\n <span className={css.rowName}>{name}</span>\n {badge}\n {meta !== undefined && meta !== '' && <span className={css.rowMeta}>{meta}</span>}\n </span>\n </button>\n <button\n type=\"button\"\n className={css.starButton}\n aria-pressed={favorited}\n aria-label={starLabel}\n tabIndex={starTabStop ? 0 : -1}\n disabled={busy}\n onClick={onToggleFavorite}\n >\n <StarIcon filled={favorited} className={css.star} />\n </button>\n <span className={css.check} aria-hidden={!selected}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n {children}\n </div>;\n}\n","/**\n * The favorite-model table the picker keeps in the browser.\n *\n * One browser-wide key holds `{ provider, model }` rows: the provider route key\n * and the model id are the catalog's own identity, so a favorite survives a\n * display-name change and never collides across providers. A value that cannot\n * be read or does not parse reads as an empty table — a privacy-mode browser or\n * a hand-edited row must never keep the menu from opening. Rows whose provider\n * leaves the catalog are kept, so restoring the provider restores the star.\n */\n\nimport type { ModelRef } from './rows.ts'\n\n/** One favorited model, identified the way the catalog identifies it. */\nexport type FavoriteModel = ModelRef\n\n/** The single browser-wide storage key holding the whole table. */\nexport const FAVORITES_KEY = 'dsh-model-submenu.favorites'\n\n/** The part of `Storage` this module uses; absent or throwing reads mean \"none\". */\nexport type FavoritesStorage = Pick<Storage, 'getItem' | 'setItem'>\n\n/**\n * Read the table, keeping only rows that name both halves.\n * @param storage - browser storage, or undefined when the browser withholds it.\n * @returns the stored favorites in stored order; empty when unreadable.\n */\nexport function readFavorites(storage: FavoritesStorage | undefined): FavoriteModel[] {\n const raw = getItem(storage)\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return []\n }\n if (!Array.isArray(parsed)) return []\n return parsed.filter((row): row is FavoriteModel => typeof row === 'object' && row !== null\n && typeof (row as FavoriteModel).provider === 'string'\n && typeof (row as FavoriteModel).model === 'string')\n}\n\n/**\n * Add or remove one model, writing the whole table back.\n * @param storage - browser storage, or undefined when writes are unavailable.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns the table after the change, whether or not the write landed.\n */\nexport function toggleFavorite(\n storage: FavoritesStorage | undefined,\n provider: string,\n model: string,\n): FavoriteModel[] {\n const current = readFavorites(storage)\n const next = isFavorite(current, provider, model)\n ? current.filter((row) => row.provider !== provider || row.model !== model)\n : [...current, { provider, model }]\n try {\n storage?.setItem(FAVORITES_KEY, JSON.stringify(next))\n } catch {\n // A full quota or a locked-down browser loses the star, not the menu.\n }\n return next\n}\n\n/**\n * @param favorites - the table to search.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns whether that exact pair is favorited.\n */\nexport function isFavorite(\n favorites: readonly FavoriteModel[],\n provider: string,\n model: string,\n): boolean {\n return favorites.some((row) => row.provider === provider && row.model === model)\n}\n\n/**\n * Stable-partition a catalog so favorited rows lead, each part keeping the\n * catalog's own order.\n * @param rows - the catalog in its display order.\n * @param favorited - predicate answering whether one row is favorited.\n * @returns a new list; the input order when nothing is favorited.\n */\nexport function orderWithFavorites<T>(\n rows: readonly T[],\n favorited: (row: T) => boolean,\n): readonly T[] {\n const starred = rows.filter(favorited)\n if (starred.length === 0) return rows\n return [...starred, ...rows.filter((row) => !favorited(row))]\n}\n\nfunction getItem(storage: FavoritesStorage | undefined): string | null {\n try {\n return storage?.getItem(FAVORITES_KEY) ?? null\n } catch {\n return null\n }\n}\n","/**\n * What the settings document knows about one model, for the picker's metadata\n * line.\n *\n * The Host's model catalog carries only a name and a reasoning list; context\n * window and accepted modalities live in each provider's settings profile,\n * which the settings mirror already holds in the browser. This module joins\n * the two by the identity both agree on: the catalog's provider route key and\n * model id are exactly the settings profile's provider key and model id.\n *\n * Every field is answered independently. A provider whose profile lists no\n * models (an OAuth route such as the Kimi subscription, or the account\n * provider) answers `unknown` rather than guessing the route default, because\n * the line's rule is to omit what cannot be asserted.\n */\n\n/** Accepted-modality answer for one model. */\nexport type ImageAnswer = 'yes' | 'no' | 'unknown'\n\n/**\n * The model knowledge a shipped adapter carries for its own account route.\n *\n * The account route has no `models` list on purpose: the account listing\n * supplies the catalog and settings only carry per-model overrides. The same\n * adapter family ships a default catalog for its API-key route, and the account\n * route serves the same models, so those entries answer what the account\n * profile cannot. Ids and facts mirror the adapter's own table.\n */\nconst FAMILY_DEFAULTS: Readonly<Record<string, readonly {\n readonly id: string\n readonly contextWindow: number\n readonly images: boolean\n}[]>> = {\n 'deepseek-account': [\n { id: 'deepseek-flash', contextWindow: 1_000_000, images: true },\n { id: 'deepseek-v4-pro', contextWindow: 1_000_000, images: false },\n ],\n}\n\n/** The metadata the settings document can answer for one model. */\nexport interface ModelFacts {\n /** Exact advertised capacity, or undefined when the model declares none. */\n readonly contextWindow: number | undefined\n /** Whether the model accepts images; `unknown` means the document is silent. */\n readonly images: ImageAnswer\n}\n\n/** One provider directory row, as the Host's LLM directory reports it. */\nexport interface ConfigurableProviderRow {\n readonly provider: string\n readonly settingsNs: string\n readonly settingsPath: readonly string[]\n}\n\n/** One settings namespace view, as the describe answer carries it. */\nexport interface NamespaceRow {\n readonly ns: string\n readonly value: unknown\n}\n\n/** What one provider's profile may carry, across both adapter families. */\ninterface ProfileView {\n readonly models?: readonly Record<string, unknown>[]\n readonly defaultContextWindow?: unknown\n readonly defaultInput?: unknown\n}\n\ntype Record_ = Record<string, unknown>\n\n/**\n * Build the fact lookup from the settings answer.\n * @param providers - provider directory rows giving each route's settings address.\n * @param namespaces - the describe answer's namespace views.\n * @returns a lookup answering both fields for one provider and model.\n */\nexport function buildModelFacts(\n providers: readonly ConfigurableProviderRow[],\n namespaces: readonly NamespaceRow[],\n): (provider: string, model: string) => ModelFacts {\n const byName = new Map(namespaces.map((row) => [row.ns, row.value]))\n const profiles = new Map<string, ProfileView>()\n for (const row of providers) {\n const section = byName.get(row.settingsNs)\n const profile = readPath(section, row.settingsPath)\n if (isRecord(profile)) profiles.set(row.provider, profile as ProfileView)\n }\n return (provider, model) => {\n const profile = profiles.get(provider)\n const entry = profile?.models === undefined\n ? undefined\n : profile.models.find((candidate) => candidate.id === model)\n if (profile !== undefined && entry !== undefined) {\n const window = typeof entry.contextWindow === 'number' && entry.contextWindow > 0\n ? entry.contextWindow\n : undefined\n return { contextWindow: window, images: imageAnswer(entry, profile) }\n }\n // A route with no model list of its own (the account route) still serves its\n // adapter family's models; a declared override there wins over the default.\n const override = readOverride(profile, model)\n if (override !== undefined) {\n const window = typeof override.contextWindow === 'number' && override.contextWindow > 0\n ? override.contextWindow\n : undefined\n return {\n contextWindow: window,\n images: Array.isArray(override.inputModalities) ? containsImage(override.inputModalities) : 'unknown',\n }\n }\n const family = FAMILY_DEFAULTS[provider]?.find((candidate) => candidate.id === model)\n return family === undefined\n ? { contextWindow: undefined, images: 'unknown' }\n : { contextWindow: family.contextWindow, images: family.images ? 'yes' : 'no' }\n }\n}\n\n/**\n * Read one model entry's accepted image modalities.\n *\n * The two adapter families disagree about an omission. The Messages family\n * names the field `inputModalities`, and leaving it out means text only. The\n * pi-ai family names it `input`, and an empty or absent list defers to the\n * route's `defaultInput`; with no route default the answer stays unknown.\n */\nfunction imageAnswer(entry: Record_, profile: ProfileView): ImageAnswer {\n if (Array.isArray(entry.inputModalities)) return containsImage(entry.inputModalities)\n const defaultInput = Array.isArray(profile.defaultInput) ? profile.defaultInput : undefined\n if (Array.isArray(entry.input)) {\n if (entry.input.length > 0) return containsImage(entry.input)\n return defaultInput === undefined ? 'unknown' : containsImage(defaultInput)\n }\n return defaultInput === undefined ? 'no' : containsImage(defaultInput)\n}\n\n/** One model's declared override, when the route keeps a `modelOverrides` table. */\nfunction readOverride(profile: ProfileView | undefined, model: string): Record_ | undefined {\n const overrides = (profile as Record_ | undefined)?.modelOverrides\n if (!isRecord(overrides)) return undefined\n const entry = overrides[model]\n return isRecord(entry) ? entry : undefined\n}\n\nfunction containsImage(modalities: readonly unknown[]): ImageAnswer {\n return modalities.includes('image') ? 'yes' : 'no'\n}\n\n/**\n * Abbreviate one capacity the way the metadata line shows it.\n * @param tokens - exact advertised capacity in tokens.\n * @returns e.g. `1M ctx`, `1.5M ctx`, `272k ctx`, or `512 ctx` below a thousand.\n */\nexport function formatContextWindow(tokens: number): string {\n if (tokens >= 1_000_000) return `${trimNumber(tokens / 1_000_000)}M ctx`\n if (tokens >= 1_000) return `${Math.round(tokens / 1_000)}k ctx`\n return `${tokens} ctx`\n}\n\n/**\n * Build the metadata line's segments.\n * @param input.providerName - the provider's display name, omitted inside that provider's own tab.\n * @param input.facts - what the settings document answered.\n * @param input.thinks - whether the catalog advertises reasoning levels for this model.\n * @param input.effortLabel - the localized word for the reasoning segment.\n * @param input.imageLabel - the localized word for the image segment.\n * @returns the segments to join; an empty list means show no line.\n */\nexport function metaSegments(input: {\n readonly providerName?: string\n readonly facts: ModelFacts\n readonly thinks: boolean\n readonly effortLabel: string\n readonly imageLabel: string\n}): readonly string[] {\n const segments: string[] = []\n if (input.providerName !== undefined) segments.push(input.providerName)\n if (input.facts.contextWindow !== undefined) segments.push(formatContextWindow(input.facts.contextWindow))\n if (input.thinks) segments.push(input.effortLabel)\n if (input.facts.images === 'yes') segments.push(input.imageLabel)\n return segments\n}\n\nfunction trimNumber(value: number): string {\n const rounded = Math.round(value * 10) / 10\n return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1)\n}\n\nfunction readPath(value: unknown, path: readonly string[]): unknown {\n let cursor = value\n for (const key of path) {\n if (!isRecord(cursor)) return undefined\n cursor = cursor[key]\n }\n return cursor\n}\n\nfunction isRecord(value: unknown): value is Record_ {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","/**\n * Catalog flattening, tab derivation, and query matching for the picker.\n *\n * The model catalog groups models by provider; the picker shows one flat list\n * with a tab per provider, so both surfaces read from these rows. Matching\n * delegates to the shell's own ranker, which is why a query behaves the same\n * here as in the built-in menu: case-insensitive, ordered subsequence, prefix\n * hits first.\n */\n\nimport type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client'\n\n/** One provider group of the shared catalog. */\nexport type ProviderGroup = ModelDirectoryState['groups'][number]\n\n/** One model inside a provider group. */\nexport type CatalogModel = ProviderGroup['models'][number]\n\n/** One flat catalog row, carrying the provider identity beside the model. */\nexport interface ModelRow extends ModelRef {\n readonly providerName: string\n /** The model id inside its provider, the other half of a selection. */\n readonly model: string\n /** The catalog entry itself, for name and reasoning metadata. */\n readonly entry: CatalogModel\n}\n\n/** A provider and one of its models: the pair every selection and favorite names. */\nexport interface ModelRef {\n readonly provider: string\n readonly model: string\n}\n\n/** One picker tab. */\nexport interface PickerTab {\n readonly id: string\n readonly label: string\n}\n\n/** The tab id standing for every provider. */\nexport const ALL_TAB = '*'\n\n/**\n * Flatten the catalog to one row per model.\n * @param groups - the shared directory's provider groups, in display order.\n * @returns the rows in catalog order.\n */\nexport function flattenGroups(groups: readonly ProviderGroup[]): readonly ModelRow[] {\n return groups.flatMap((group) => group.models.map((model) => ({\n provider: group.id,\n providerName: group.name,\n model: model.id,\n entry: model,\n })))\n}\n\n/**\n * Build the picker's tabs: the all-tab, then one per provider that has a model.\n * @param groups - the shared directory's provider groups.\n * @param allLabel - localized label for the all-tab.\n * @returns the tabs in catalog order.\n */\nexport function pickerTabs(groups: readonly ProviderGroup[], allLabel = 'All'): readonly PickerTab[] {\n return [\n { id: ALL_TAB, label: allLabel },\n ...groups.filter((group) => group.models.length > 0).map((group) => ({ id: group.id, label: group.name })),\n ]\n}\n\n/**\n * @param rows - the flat catalog.\n * @param tab - the tab id; the all-tab keeps every row.\n * @returns the rows the tab shows, in their current order.\n */\nexport function rowsForTab(rows: readonly ModelRow[], tab: string): readonly ModelRow[] {\n return tab === ALL_TAB ? rows : rows.filter((row) => row.provider === tab)\n}\n\n/** One row handed to the shell's ranker, carrying both searchable keys. */\nexport interface SearchCandidate {\n readonly name: string\n readonly label: string\n readonly row: ModelRow\n}\n\n/**\n * Shape rows as the shell's ranker candidates: the model name is the name, the\n * provider display name is the second key, so a query reaches either.\n * @param rows - the rows to search.\n * @returns candidates in row order.\n */\nexport function searchCandidates(rows: readonly ModelRow[]): readonly SearchCandidate[] {\n return rows.map((row) => ({ name: row.entry.name, label: row.providerName, row }))\n}\n\n/**\n * Read the reasoning metadata the catalog advertises for one model.\n * @param groups - the shared directory's provider groups.\n * @returns the metadata, or undefined when that model advertises none.\n */\nexport function reasoningOf(\n groups: readonly ProviderGroup[],\n): (provider: string, model: string) => CatalogModel['reasoning'] {\n return (provider, model) => groups\n .find((group) => group.id === provider)\n ?.models.find((candidate) => candidate.id === model)\n ?.reasoning\n}\n\n/**\n * Filter rows by a query over the model name and the provider name.\n * @param rows - the rows to search.\n * @param query - the typed text; an empty or blank query keeps every row.\n * @param rank - the shell's own ranker, so this search behaves like every other one.\n * @returns the matching rows.\n */\nexport function searchRows(\n rows: readonly ModelRow[],\n query: string,\n rank: (items: readonly SearchCandidate[], query: string) => readonly SearchCandidate[],\n): readonly ModelRow[] {\n const trimmed = query.trim()\n if (trimmed === '') return rows\n return rank(searchCandidates(rows), trimmed).map((match) => match.row)\n}\n","/**\n * The model picker: the centered dialog opened from the menu's last row.\n *\n * It is the one place every provider is visible at once — a search field, a tab\n * per provider with a model, and one flat list with each model's metadata line.\n * Favorites lead the list and can be toggled from a row's star without\n * selecting that row. A click commits at once; a rejected commit keeps the\n * dialog open so the user can retry or pick another model.\n */\n\nimport { useEffect, useId, useMemo, useRef, useState } from 'react'\nimport {\n IconSearchOutlineRegular,\n Input,\n Modal,\n ShortcutKeys,\n rankByName,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { ModelRow } from './ModelRow.tsx'\nimport { isFavorite, orderWithFavorites } from './favorites.ts'\nimport type { ModelFacts } from './model-facts.ts'\nimport { metaSegments } from './model-facts.ts'\nimport {\n ALL_TAB,\n flattenGroups,\n pickerTabs,\n reasoningOf,\n rowsForTab,\n searchRows,\n type CatalogModel,\n type ModelRow as CatalogRow,\n type PickerTab,\n} from './rows.ts'\nimport { Tag, isMobileDevice } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ModelFactsLookup } from './facts-source.ts'\nimport type { Selection } from './selection.ts'\nimport { planModelCommit } from './selection.ts'\nimport css from './ModelOptions.module.css'\n\n/** Props the seat hands the picker. */\nexport interface ModelPickerProps {\n /** Whether the dialog is showing. */\n readonly open: boolean\n /** Resolve a catalog badge's localized text for the active language. */\n readonly resolveText: (text: NonNullable<CatalogModel['badge']>['text']) => string\n /** The shared directory snapshot. */\n readonly state: ModelDirectoryState\n /** The selection in force, null before a first selection resolves. */\n readonly live: Selection | null\n /** The metadata lookup for the current settings answer. */\n readonly facts: ModelFactsLookup\n /** The favorite table right now. */\n readonly favorites: readonly { readonly provider: string; readonly model: string }[]\n /** Whether a selection is in flight. */\n readonly busy: boolean\n /**\n * The reasoning level this browser last used for one model, if any.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns the remembered level, or undefined when none is remembered.\n */\n readonly rememberedOf?: (provider: string, model: string) => string | undefined\n /** Submit one selection. */\n readonly onPick: (selection: Selection) => void\n /** Toggle one model's favorite. */\n readonly onToggleFavorite: (provider: string, model: string) => void\n /** Reload the catalog after a failure. */\n readonly onReload: () => void\n /** Close the dialog, optionally returning focus. */\n readonly onClose: () => void\n}\n\n/**\n * Render the picker.\n * @param props - the catalog, the live selection, and the picker's verbs.\n * @returns the dialog; nothing while closed.\n */\nexport function ModelPicker({\n open, resolveText, state, live, facts, favorites, busy, rememberedOf, onPick, onToggleFavorite, onReload, onClose, t,\n}: ModelPickerProps & PropsLocale<'modelSubmenu'>) {\n const id = useId()\n const searchRef = useRef<HTMLInputElement | null>(null)\n const listRef = useRef<HTMLDivElement | null>(null)\n const [query, setQuery] = useState('')\n const [tab, setTab] = useState(ALL_TAB)\n const [highlight, setHighlight] = useState(0)\n const tabRefs = useRef(new Map<string, HTMLButtonElement>())\n\n const tabs = useMemo(() => pickerTabs(state.groups, t('picker.all')), [state.groups, t])\n const reason = useMemo(() => reasoningOf(state.groups), [state.groups])\n const rows = useMemo(() => orderWithFavorites(\n rowsForTab(flattenGroups(state.groups), tab),\n (row) => isFavorite(favorites, row.provider, row.model),\n ), [state.groups, tab, favorites])\n // Search runs inside the favorite partition, never across it: a query must not\n // pull an unstarred model above a starred one, because favorites lead the list\n // whether or not a query is typed.\n const visible = useMemo(() => orderWithFavorites(\n searchRows(rows, query, rankByName),\n (row) => isFavorite(favorites, row.provider, row.model),\n ), [rows, query, favorites])\n\n useEffect(() => {\n if (!open) return\n setQuery('')\n setTab(ALL_TAB)\n setHighlight(0)\n if (listRef.current !== null) listRef.current.scrollTop = 0\n // 粗指针设备不自动聚焦文本输入:移动端弹键盘会顶起布局,宿主座位也这样守。\n const frame = requestAnimationFrame(() => {\n if (!isMobileDevice()) searchRef.current?.focus()\n })\n return () => { cancelAnimationFrame(frame) }\n }, [open])\n\n useEffect(() => {\n setHighlight((current) => visible.length === 0 ? 0 : Math.min(current, visible.length - 1))\n }, [visible.length])\n\n useEffect(() => {\n const row = listRef.current?.querySelector<HTMLElement>(`[data-row-index=\"${highlight}\"]`)\n row?.scrollIntoView({ block: 'nearest' })\n }, [highlight])\n\n if (!open) return null\n\n const activeRow = visible[highlight]\n const activeId = activeRow === undefined ? undefined : `${id}-row-${highlight}`\n const onSearchKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n if (visible.length === 0) return\n setHighlight((current) => {\n const next = current + (event.key === 'ArrowDown' ? 1 : -1)\n return (next + visible.length) % visible.length\n })\n return\n }\n if (event.key === 'Enter' && activeRow !== undefined && !busy) {\n event.preventDefault()\n pick(activeRow)\n }\n }\n const pick = (row: CatalogRow) => {\n const selection = planModelCommit(live, row.provider, row.model, reason, rememberedOf?.(row.provider, row.model))\n if (selection === null) {\n onClose()\n return\n }\n onPick(selection)\n }\n /** Move to another tab and hand it the keyboard, in one step. */\n const goTab = (next: PickerTab | undefined) => {\n if (next === undefined || next.id === tab) return\n setTab(next.id)\n setHighlight(0)\n tabRefs.current.get(next.id)?.focus()\n }\n const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n const index = tabs.findIndex((candidate) => candidate.id === tab)\n if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') {\n event.preventDefault()\n const step = event.key === 'ArrowRight' ? 1 : -1\n goTab(tabs[((index === -1 ? 0 : index) + step + tabs.length) % tabs.length])\n return\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n goTab(tabs[event.key === 'Home' ? 0 : tabs.length - 1])\n }\n }\n\n const failures = state.failures.filter((failure) => tab === ALL_TAB || failure.id === tab)\n const failed = state.error !== null && state.status === 'error'\n const loading = state.status === 'loading'\n return (\n <Modal\n open={open}\n onClose={onClose}\n title={t('picker.title')}\n closeLabel={t('picker.close')}\n className={css.pickerDialog ?? ''}\n contentClassName={css.pickerContent ?? ''}\n >\n <div className={css.pickerSearch}>\n <Input\n ref={searchRef}\n className={css.pickerSearchInput ?? ''}\n type=\"text\"\n role=\"searchbox\"\n aria-label={t('picker.search')}\n aria-controls={`${id}-list`}\n aria-activedescendant={activeId}\n placeholder={t('picker.search')}\n icon={<IconSearchOutlineRegular size={14} />}\n value={query}\n readOnly={busy}\n onChange={(event) => { setQuery(event.target.value) }}\n onKeyDown={onSearchKeyDown}\n data-modal-autofocus=\"\"\n />\n </div>\n <div className={css.pickerTabs} role=\"tablist\" aria-label={t('picker.title')}>\n {tabs.map((entry) => (\n <button\n key={entry.id}\n ref={(node) => {\n if (node === null) tabRefs.current.delete(entry.id)\n else tabRefs.current.set(entry.id, node)\n }}\n type=\"button\"\n role=\"tab\"\n id={`${id}-tab-${entry.id}`}\n aria-selected={entry.id === tab}\n aria-controls={`${id}-list`}\n tabIndex={0}\n className={css.pickerTab}\n onClick={() => {\n setTab(entry.id)\n setHighlight(0)\n }}\n onKeyDown={onTabKeyDown}\n onFocus={() => {\n if (entry.id !== tab) {\n setTab(entry.id)\n setHighlight(0)\n }\n }}\n >\n {entry.label}\n </button>\n ))}\n </div>\n <div\n ref={listRef}\n id={`${id}-list`}\n className={css.pickerList}\n role=\"menu\"\n aria-label={t('picker.title')}\n >\n {loading && <div className={css.notice}>{t('status.loading')}</div>}\n {failed && (\n <div className={css.notice}>\n <span>{t('status.failed', { message: state.error ?? '' })}</span>\n <button type=\"button\" className={css.retry} onClick={onReload}>{t('action.reload')}</button>\n </div>\n )}\n {failures.map((failure) => (\n <div className={css.notice} key={failure.id}>\n <span>{t('status.providerFailed', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={onReload}>{t('action.reload')}</button>\n </div>\n ))}\n {visible.length === 0 && !loading && !failed && (\n <div className={css.notice}>{state.groups.length === 0 ? t('status.empty') : t('picker.searchEmpty')}</div>\n )}\n {visible.map((row, index) => (\n <div key={`${row.provider}/${row.model}`} data-row-index={index} id={`${id}-row-${index}`}>\n <ModelRow\n name={row.entry.name}\n badge={row.entry.badge === undefined\n ? undefined\n : <Tag tone={row.entry.badge.tone} className={css.rowBadge}>{resolveText(row.entry.badge.text)}</Tag>}\n selected={live?.provider === row.provider && live.model === row.model}\n busy={busy}\n favorited={isFavorite(favorites, row.provider, row.model)}\n meta={metaLine({\n row,\n facts: facts(row.provider, row.model),\n providerName: tab === ALL_TAB ? row.providerName : undefined,\n thinks: row.entry.reasoning !== undefined,\n effortLabel: t('meta.effort'),\n imageLabel: t('meta.images'),\n })}\n starLabel={isFavorite(favorites, row.provider, row.model)\n ? t('picker.unfavorite', { model: row.entry.name })\n : t('picker.favorite', { model: row.entry.name })}\n starTabStop={index === highlight}\n rowTabIndex={-1}\n onPick={() => { pick(row) }}\n onFocusRow={() => { setHighlight(index) }}\n onToggleFavorite={() => { onToggleFavorite(row.provider, row.model) }}\n />\n </div>\n ))}\n </div>\n <div className={css.pickerFooter}>\n <span className={css.footerHint}>\n <ShortcutKeys keys={['↑', '↓']} />\n <span>{t('picker.hintNavigate')}</span>\n <span className={css.footerDot}>·</span>\n <ShortcutKeys keys={['Enter']} />\n <span>{t('picker.hintSelect')}</span>\n <span className={css.footerDot}>·</span>\n <ShortcutKeys keys={['Esc']} />\n <span>{t('picker.hintClose')}</span>\n </span>\n </div>\n </Modal>\n )\n}\n\nfunction metaLine(input: {\n readonly row: CatalogRow\n readonly facts: ModelFacts\n readonly providerName: string | undefined\n readonly thinks: boolean\n readonly effortLabel: string\n readonly imageLabel: string\n}): string {\n return metaSegments({\n ...input.providerName === undefined ? {} : { providerName: input.providerName },\n facts: input.facts,\n thinks: input.thinks,\n effortLabel: input.effortLabel,\n imageLabel: input.imageLabel,\n }).join(' · ')\n}\n\n","/**\n * The per-model reasoning level this browser last chose.\n *\n * The Host stores one level per session, so switching models away and back\n * forgets what was picked for the first one. This module keeps that memory\n * beside the favorite table, keyed the same way: provider route key plus model\n * id. Remembering the provider default removes the row, so \"follow the\n * provider\" stays distinguishable from \"remembered a level\".\n */\n\n/** One remembered reasoning level. */\nexport interface RememberedEffort {\n readonly provider: string\n readonly model: string\n readonly effort: string\n}\n\n/** The single browser-wide storage key holding the whole memory. */\nexport const EFFORTS_KEY = 'dsh-model-submenu.efforts'\n\n/** The part of `Storage` this module uses; absent or throwing reads mean \"none\". */\nexport type EffortStorage = Pick<Storage, 'getItem' | 'setItem'>\n\n/**\n * Read the memory, keeping only rows naming both halves and a level.\n * @param storage - browser storage, or undefined when the browser withholds it.\n * @returns the remembered rows; empty when unreadable.\n */\nexport function readEfforts(storage: EffortStorage | undefined): RememberedEffort[] {\n const raw = getItem(storage)\n if (raw === null) return []\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n return []\n }\n if (!Array.isArray(parsed)) return []\n return parsed.filter((row): row is RememberedEffort => typeof row === 'object' && row !== null\n && typeof (row as RememberedEffort).provider === 'string'\n && typeof (row as RememberedEffort).model === 'string'\n && typeof (row as RememberedEffort).effort === 'string'\n && (row as RememberedEffort).effort !== '')\n}\n\n/**\n * @param memory - the rows to search.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @returns the level last chosen for that exact model, or undefined.\n */\nexport function effortFor(\n memory: readonly RememberedEffort[],\n provider: string,\n model: string,\n): string | undefined {\n return memory.find((row) => row.provider === provider && row.model === model)?.effort\n}\n\n/**\n * Remember one model's level, or forget it when the choice is the provider default.\n * @param storage - browser storage, or undefined when writes are unavailable.\n * @param provider - the provider route key.\n * @param model - the model id inside that provider.\n * @param effort - the chosen level, undefined meaning the provider default.\n * @returns the memory after the change, whether or not the write landed.\n */\nexport function rememberEffort(\n storage: EffortStorage | undefined,\n provider: string,\n model: string,\n effort: string | undefined,\n): RememberedEffort[] {\n const rest = readEfforts(storage).filter((row) => row.provider !== provider || row.model !== model)\n const next = effort === undefined ? rest : [...rest, { provider, model, effort }]\n try {\n storage?.setItem(EFFORTS_KEY, JSON.stringify(next))\n } catch {\n // A full quota or a locked-down browser loses the memory, not the menu.\n }\n return next\n}\n\nfunction getItem(storage: EffortStorage | undefined): string | null {\n try {\n return storage?.getItem(EFFORTS_KEY) ?? null\n } catch {\n return null\n }\n}\n","/**\n * The composer overlay's picker view: the dialog, its catalog, and its verbs.\n *\n * It lives in `conversation.input.overlay` rather than beside the row, because\n * the Host unmounts the model menu as soon as a row is clicked. Everything the\n * dialog reads arrives through this entry's injected face.\n */\nimport { useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';\nimport { IconWarningOutlineRegular, Toast } from '@deepseek-ai/dsh-client-ui-primitives';\nimport type { ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client';\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';\nimport { ModelPicker } from './ModelPicker.tsx';\nimport type { FactsSource } from './facts-source.ts';\nimport {\n readFavorites,\n toggleFavorite,\n type FavoriteModel,\n type FavoritesStorage,\n} from './favorites.ts';\nimport {\n effortFor,\n readEfforts,\n rememberEffort,\n type RememberedEffort,\n} from './effort-memory.ts';\nimport { selectionOf, type Selection } from './selection.ts';\nimport type { PickerStore } from './picker-state.ts';\nimport css from './ModelOptions.module.css';\n\n/** Props of the overlay view: the session, the store, and the seat's injected face. */\nexport type ModelPickerHostProps = PropsLocale<'modelSubmenu'>\n & ModelSelectInjected\n & {\n /** Session whose catalog this view renders. */\n readonly sessionId: string;\n /** The request written by the menu row. */\n readonly picker: PickerStore;\n /** The settings-derived metadata the picker's line reads. */\n readonly factsSource: FactsSource;\n }\n\n/**\n * Render the picker for this session.\n * @param props - session, store, catalog face, and localized copy.\n * @returns the dialog while the store names this session; otherwise nothing.\n */\nexport function ModelPickerHost({\n sessionId, picker, available, directory, load, select, resolveText, factsSource, t,\n}: ModelPickerHostProps) {\n const request = useSyncExternalStore(picker.subscribe, picker.getSnapshot);\n const state = useSyncExternalStore((listener) => directory.subscribe(listener), () => directory.getSnapshot());\n const [favorites, setFavorites] = useState<readonly FavoriteModel[]>(() => readFavorites(storageOf()));\n const [memory, setMemory] = useState<readonly RememberedEffort[]>(() => readEfforts(storageOf()));\n const [toast, setToast] = useState<{ seq: number; text: string } | null>(null);\n const toastSeq = useRef(0);\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const busy = state.status === 'selecting';\n const live = useMemo(() => selectionOf(state), [state]);\n const facts = useSyncExternalStore((listener) => factsSource.subscribe(listener), () => factsSource.getSnapshot());\n const open = request.sessionId === sessionId;\n // The injected face is cached per entry and session, but the read goes through\n // a ref anyway: a catalog load writes the store, so an unstable `load` in the\n // dependency list would reload on every render it caused.\n const loadRef = useRef(load);\n loadRef.current = load;\n\n // Opening reads the catalog again: another client may have changed it, and a\n // failed load has to be retryable from the same gesture.\n useEffect(() => {\n if (open) loadRef.current();\n }, [open]);\n\n // The Host's own menu changes the reasoning level without passing through this\n // plugin, so the memory is written from the directory snapshot too — a picker\n // click alone would only ever record levels chosen in the dialog. The key guard\n // keeps one write per distinct selection instead of one per snapshot.\n const current = state.current;\n const rememberedRef = useRef<string | null>(null);\n useEffect(() => {\n if (current === null) return;\n const key = `${current.provider}/${current.model}/${current.reasoningEffort ?? ''}`;\n if (rememberedRef.current === key) return;\n rememberedRef.current = key;\n setMemory(rememberEffort(storageOf(), current.provider, current.model, current.reasoningEffort));\n }, [current]);\n\n if (!available) return null;\n\n const raiseToast = (text: string): void => {\n toastSeq.current += 1;\n setToast({ seq: toastSeq.current, text });\n };\n const submit = (selection: Selection): void => {\n void select(selection).then((result) => {\n if (result === undefined || result.ok) {\n setMemory(rememberEffort(storageOf(), selection.provider, selection.model, selection.reasoningEffort));\n picker.close();\n return;\n }\n raiseToast(result.error.code === 'session/writer-held'\n ? t('error.sessionInUse')\n : t('error.action', { message: `${result.error.code}: ${result.error.message}` }));\n });\n };\n\n return <div ref={rootRef} className={css.pickerHost}>\n <ModelPicker\n open={open}\n resolveText={resolveText}\n state={state}\n live={live}\n facts={facts}\n favorites={favorites}\n busy={busy}\n t={t}\n rememberedOf={(provider, model) => effortFor(memory, provider, model)}\n onPick={submit}\n onToggleFavorite={(provider, model) => {\n setFavorites(toggleFavorite(storageOf(), provider, model));\n }}\n onReload={load}\n onClose={() => {\n picker.close();\n }}\n />\n {toast !== null && <Toast\n key={toast.seq}\n text={toast.text}\n icon={<IconWarningOutlineRegular />}\n anchor={rootRef.current?.closest('[data-composer-card]') ?? null}\n onDone={() => {\n setToast(null);\n }}\n />}\n </div>;\n}\n\n/** Isolate the browser's storage so a locked-down browser reads as \"no favorites\". */\nfunction storageOf(): FavoritesStorage | undefined {\n try {\n return globalThis.localStorage;\n } catch {\n return undefined;\n }\n}\n","/**\n * Which session's picker is open.\n *\n * The row that asks for the picker lives inside the composer model menu, and the\n * Host unmounts that menu the moment a row is clicked. The dialog lives in the\n * composer's overlay slot, which stays mounted. One plugin-wide store carries the\n * request across that unmount — the same split the Host's own command popups use\n * between their controller and their overlay view.\n */\n\n/** What the store publishes. */\nexport interface PickerSnapshot {\n /** Session whose picker is open, or null when none is. */\n readonly sessionId: string | null\n}\n\n/** Open and close verbs plus the observable the overlay view subscribes to. */\nexport interface PickerStore {\n /** @returns the current request. */\n readonly getSnapshot: () => PickerSnapshot\n /** @param listener - called after every change. @returns the unsubscribe. */\n readonly subscribe: (listener: () => void) => () => void\n /** @param sessionId - open the picker for one session, replacing any other. */\n readonly open: (sessionId: string) => void\n /** Close whatever is open. */\n readonly close: () => void\n}\n\n/**\n * @returns a store that starts closed.\n */\nexport function createPickerStore(): PickerStore {\n let snapshot: PickerSnapshot = { sessionId: null };\n const listeners = new Set<() => void>();\n const publish = (next: PickerSnapshot): void => {\n if (next.sessionId === snapshot.sessionId) return;\n snapshot = next;\n for (const listener of listeners) listener();\n };\n return {\n getSnapshot: () => snapshot,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n open: (sessionId) => {\n publish({ sessionId });\n },\n close: () => {\n publish({ sessionId: null });\n },\n };\n}\n","/**\n * The browser's live answer to \"what does the settings document know about this\n * model?\".\n *\n * Two host answers meet here: the shared settings mirror (which the settings\n * page already keeps warm) and the LLM provider directory that says which\n * settings namespace holds each provider's profile. Both can change while the\n * page is open — a saved profile, a reconnected host — so the join is rebuilt\n * whenever the mirror or the directory reports a change, and readers subscribe\n * to the lookup itself.\n */\n\nimport type { ModelFacts } from './model-facts.ts'\nimport {\n buildModelFacts,\n type ConfigurableProviderRow,\n type NamespaceRow,\n} from './model-facts.ts'\n\n/** One lookup answering both metadata fields for a provider and model. */\nexport type ModelFactsLookup = (provider: string, model: string) => ModelFacts\n\n/** The mirror face this source reads; a subset of the settings provider's. */\nexport interface DescribeFace {\n getSnapshot(): { readonly view: { readonly namespaces: readonly NamespaceRow[] } | undefined }\n subscribe(listener: () => void): () => void\n ensure(): Promise<void>\n}\n\n/** One remote answer, as the gateway returns it. */\nexport interface DirectoryAnswer {\n readonly ok: boolean\n readonly value?: readonly ConfigurableProviderRow[]\n}\n\n/** A stable, subscribable lookup over the current settings answer. */\nexport interface FactsSource {\n /** @returns the lookup for the current answer; the identity changes on every rebuild. */\n getSnapshot(): ModelFactsLookup\n /** @param listener - called after each rebuild. @returns the disposer. */\n subscribe(listener: () => void): () => void\n}\n\nconst EMPTY: ModelFactsLookup = () => ({ contextWindow: undefined, images: 'unknown' })\n\n/**\n * Join the settings mirror with the provider directory.\n * @param deps.describe - the settings mirror's describe face.\n * @param deps.listProviders - reads the LLM provider directory once.\n * @returns the source, plus `start` which wires both reads and returns its disposer.\n */\nexport function createFactsSource(deps: {\n readonly describe: DescribeFace\n readonly listProviders: () => Promise<DirectoryAnswer>\n}): { readonly source: FactsSource; readonly start: () => () => void } {\n const listeners = new Set<() => void>()\n let providers: readonly ConfigurableProviderRow[] = []\n let lookup: ModelFactsLookup = EMPTY\n\n const rebuild = () => {\n const namespaces = deps.describe.getSnapshot().view?.namespaces ?? []\n lookup = providers.length === 0 || namespaces.length === 0\n ? EMPTY\n : buildModelFacts(providers, namespaces)\n for (const listener of [...listeners]) listener()\n }\n\n return {\n source: {\n getSnapshot: () => lookup,\n subscribe: (listener) => {\n listeners.add(listener)\n return () => { listeners.delete(listener) }\n },\n },\n start: () => {\n const off = deps.describe.subscribe(rebuild)\n void deps.describe.ensure().catch(() => { /* a failed read leaves the empty lookup in place */ })\n void deps.listProviders().then(\n (answer) => {\n providers = answer.ok && answer.value !== undefined ? answer.value : []\n rebuild()\n },\n () => { /* the directory being unavailable leaves every model's facts unknown */ },\n )\n rebuild()\n return () => {\n off()\n listeners.clear()\n }\n },\n }\n}\n","/** Locale bundles for the all-provider model picker. */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelSubmenu'\n\n/** Locale keys the picker renders. */\nexport type ModelSubmenuLocaleKey =\n | 'status.loading'\n | 'status.empty'\n | 'status.failed'\n | 'status.providerFailed'\n | 'action.reload'\n | 'error.action'\n | 'error.sessionInUse'\n | 'picker.title'\n | 'picker.close'\n | 'picker.search'\n | 'picker.searchEmpty'\n | 'picker.all'\n | 'picker.favorite'\n | 'picker.unfavorite'\n | 'picker.hintNavigate'\n | 'picker.hintSelect'\n | 'picker.hintClose'\n | 'meta.effort'\n | 'meta.images'\n | 'effort.label'\n | 'effort.providerDefault'\n | 'effort.useDefault'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The all-provider model picker's copy. */\n modelSubmenu: ModelSubmenuLocaleKey\n }\n}\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh: Record<ModelSubmenuLocaleKey, string> = {\n 'status.loading': '正在加载模型…',\n 'status.empty': '没有可用的模型。',\n 'status.failed': '模型列表加载失败:{message}',\n 'status.providerFailed': '{name} 加载失败:{message}',\n 'action.reload': '重新加载',\n 'error.action': '模型操作失败:{message}',\n 'error.sessionInUse': '当前会话已被占用,可能是其他正在运行的 DSH 导致的(如其他 dsh web、桌面端),请退出其他正在运行的 DSH 后重试。',\n 'picker.title': '切换模型',\n 'picker.close': '关闭',\n 'picker.search': '搜索模型或提供商…',\n 'picker.searchEmpty': '没有匹配的模型。',\n 'picker.all': '全部',\n 'picker.favorite': '收藏 {model}',\n 'picker.unfavorite': '取消收藏 {model}',\n 'picker.hintNavigate': '导航',\n 'picker.hintSelect': '选择',\n 'picker.hintClose': '关闭',\n 'meta.effort': '思考',\n 'meta.images': '图片输入',\n 'effort.label': '推理等级',\n 'effort.providerDefault': 'Default',\n 'effort.useDefault': '切换为默认档位',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<ModelSubmenuLocaleKey, string> = {\n 'status.loading': 'Loading models…',\n 'status.empty': 'No models available.',\n 'status.failed': 'Model list failed to load: {message}',\n 'status.providerFailed': '{name} failed to load: {message}',\n 'action.reload': 'Reload',\n 'error.action': 'Model operation failed: {message}',\n 'error.sessionInUse': 'This session is already in use, possibly by another running DSH instance (such as dsh web or the desktop app). Quit other running DSH instances and try again.',\n 'picker.title': 'Switch model',\n 'picker.close': 'Close',\n 'picker.search': 'Search models or providers…',\n 'picker.searchEmpty': 'No matching models.',\n 'picker.all': 'All',\n 'picker.favorite': 'Favorite {model}',\n 'picker.unfavorite': 'Remove {model} from favorites',\n 'picker.hintNavigate': 'navigate',\n 'picker.hintSelect': 'select',\n 'picker.hintClose': 'close',\n 'meta.effort': 'Effort',\n 'meta.images': 'Images',\n 'effort.label': 'Reasoning effort',\n 'effort.providerDefault': 'Default',\n 'effort.useDefault': 'Switch to the provider default',\n}\n","import type { Context as ClientContext } from '@deepseek-ai/cordis'\n// Type-only: `slots` and its LocaleNamespaceMap merge come from the renderer and\n// the slot package; the model menu's options slot and the composer overlay from\n// ui-conversation; the `modelDirectories` service and the seat's injected face\n// from ui-model-selection's browser half; `configForms` from the settings\n// provider, whose shared mirror answers the metadata line.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { EffortTint } from './EffortTint.tsx'\nimport { ModelMenuBridge } from './ModelMenuBridge.tsx'\nimport { ModelPickerHost } from './ModelPickerHost.tsx'\nimport { createPickerStore } from './picker-state.ts'\nimport { createFactsSource, type DescribeFace } from './facts-source.ts'\nimport { NS, en, zh } from './locales.ts'\n\nexport { EffortTint } from './EffortTint.tsx'\nexport { ModelMenuBridge } from './ModelMenuBridge.tsx'\nexport { ModelPickerHost } from './ModelPickerHost.tsx'\nexport { createPickerStore } from './picker-state.ts'\n\n/**\n * Cordis services required by the browser half. `slots` is the contribution\n * registry, `sessions` tells whether a session may select a model,\n * `modelDirectories` owns the per-session catalog snapshot both entries render\n * from, and `configForms` carries the settings provider's shared describe\n * mirror, which answers each model's context window and accepted modalities.\n * `remote`, `remote.llm`, and `remote.session` are declared because a service\n * method runs on the calling context: `directoryFor` reads\n * `this.ctx.remote.session`, and the provider directory that names each\n * settings address is read through `this.ctx.remote.llm`.\n */\nexport const inject = [\n 'configForms',\n 'locale',\n 'modelDirectories',\n 'remote',\n 'remote.llm',\n 'remote.session',\n 'sessions',\n 'slots',\n]\n\n/**\n * Client plugin body: register this plugin's dictionaries, then contribute the\n * bridge that turns the Host's model cell into the picker's door and its effort\n * cell into the reasoning-level slider, the overlay that renders the picker, and\n * the tint that keeps the collapsed trigger's effort caption on the same color.\n *\n * The two are separate entries because the Host unmounts the model menu the\n * moment a row is clicked; the overlay slot stays mounted, so the dialog\n * survives the menu's teardown.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-submenu: dictionaries')\n ctx.inject(['slots', 'modelDirectories', 'configForms', 'remote'], (scope) => {\n const models = scope.modelDirectories\n const sessions = scope.sessions\n const picker = createPickerStore()\n const facts = createFactsSource({\n describe: scope.configForms.describe() as DescribeFace,\n listProviders: () => scope.remote.llm.listConfigurableProviders(),\n })\n ctx.effect(() => facts.start(), 'dsh-model-submenu: model metadata')\n /**\n * Build one entry's business face for a session.\n * @param sessionId - the slot's session scope.\n * @returns the catalog face plus the session and store both entries need.\n */\n const faceOf = (sessionId: string) => {\n // The slot's inject parameter is typed as a bare string; the service\n // faces carry the branded SessionId of that same runtime value.\n const key = sessionId as Parameters<typeof models.directoryFor>[0]\n const directory = models.directoryFor(key)\n const available = sessions.subagentAddress(key) === undefined\n return {\n sessionId,\n picker,\n available,\n directory: directory.store,\n factsSource: facts.source,\n load: () => {\n if (available) directory.load().catch(() => {})\n },\n resolveText: (text: Parameters<typeof ctx.locale.resolveText>[0]) => ctx.locale.resolveText(text),\n select: (selection: Parameters<typeof directory.select>[0]) => available\n ? directory.select(selection)\n : Promise.resolve(undefined),\n }\n }\n scope.slots.inject('conversation.input.model.options', () => scope.slots.register({\n name: 'conversation.input.model.options',\n id: 'model-menu-bridge',\n registrant: '@lynn123411/dsh-model-submenu',\n locale: NS,\n inject: faceOf,\n }, ModelMenuBridge))\n scope.slots.inject('conversation.input.overlay', () => scope.slots.register({\n name: 'conversation.input.overlay',\n id: 'model-picker',\n registrant: '@lynn123411/dsh-model-submenu',\n locale: NS,\n inject: faceOf,\n }, ModelPickerHost))\n // The trigger's effort caption lives outside the menu, so its tint needs an\n // entry that stays mounted for the whole session.\n scope.slots.inject('conversation.input.overlay', () => scope.slots.register({\n name: 'conversation.input.overlay',\n id: 'model-effort-tint',\n registrant: '@lynn123411/dsh-model-submenu',\n inject: faceOf,\n }, EffortTint))\n })\n}\n"],"mappings":"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"}
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
3
|
"title": "Model picker",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Enhances the composer model menu: the model row opens a cross-provider dialog, and the reasoning row becomes a colored slider."
|
|
5
5
|
}
|
|
6
6
|
}
|