@lynn123411/dsh-model-submenu 0.2.5 → 0.3.1
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 +9 -3
- package/README.md +10 -8
- package/lib/client.js +1158 -326
- package/lib/client.js.map +1 -1
- package/locale/en.json +2 -2
- package/locale/zh.json +2 -2
- package/package.json +26 -20
- package/src/client/ModelPicker.tsx +305 -0
- package/src/client/ModelRow.tsx +127 -0
- package/src/client/ModelSubmenu.module.css +338 -97
- package/src/client/ModelSubmenu.tsx +237 -233
- package/src/client/effort-memory.ts +90 -0
- package/src/client/facts-source.ts +93 -0
- package/src/client/favorites.ts +103 -0
- package/src/client/icons.tsx +36 -0
- package/src/client/index.ts +29 -8
- package/src/client/locales.ts +66 -33
- package/src/client/model-facts.ts +198 -0
- package/src/client/rows.ts +125 -0
- package/src/client/selection.ts +112 -0
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","useId","useMemo","css","IconChevronLeftOutlineRegular","IconDataOutlineRegular","IconChevronDownOutlineRegular","createPortal","MenuSurface","Fragment","IconChevronRightOutlineRegular","IconCheckOutlineRegular","Toast","IconWarningOutlineRegular"],"sources":["../src/client/ModelSubmenu.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["import { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconCheckOutlineRegular,\n IconChevronDownOutlineRegular,\n IconChevronLeftOutlineRegular,\n IconChevronRightOutlineRegular,\n IconDataOutlineRegular,\n IconWarningOutlineRegular,\n MenuSurface,\n Toast,\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 css from './ModelSubmenu.module.css'\n\ntype ModelSubmenuProps = ModelSelectInjected & { locked: boolean } & PropsLocale<'modelSubmenu'>\n\ntype Selection = Parameters<ModelSelectInjected['select']>[0]\ntype ProviderGroup = ModelDirectoryState['groups'][number]\ntype CatalogModel = ProviderGroup['models'][number]\n\n/** Which list the open menu is showing. */\ntype Pane = 'root' | 'providers' | 'models' | 'effort'\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 level: the root pane keeps the built-in's\n * two cells — 供应商 in place of 模型, plus the native 推理等级 — the provider\n * cell drills into the catalog's providers, and a provider drills into its\n * models before submitting. The trigger, the menu surface, the keyboard\n * contract (arrows move, Tab settles, Escape and Shift+Tab leave a drilled pane\n * first), the effort list and the failure surfaces are the built-in ones.\n */\nexport function ModelSubmenu({ locked, available, directory, load, select, t }: ModelSubmenuProps) {\n const state = useSyncExternalStore((fn) => directory.subscribe(fn), () => directory.getSnapshot())\n const [open, setOpen] = useState(false)\n const [pane, setPane] = useState<Pane>('root')\n const [providerId, setProviderId] = useState<string | null>(null)\n const lastActionRef = useRef<'load' | 'select'>('load')\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 [menuPos, setMenuPos] = useState<{ left: number; top: number } | null>(null)\n const itemRefs = useRef(new Map<string, HTMLButtonElement>())\n const focusIntent = useRef<string | 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 const effortLabel = reasoning === undefined\n ? undefined\n : effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find((level) => level.id === effectiveEffort)?.name ?? effectiveEffort\n const effortChoices = useMemo(() => reasoning === undefined ? [] : [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined as string | undefined, label: t('effort.providerDefault') }]\n : [],\n ...reasoning.efforts.map((level) => ({ key: `effort:${level.id}`, effort: level.id as string | undefined, label: level.name })),\n ], [reasoning, t])\n\n const shownGroup = pane === 'models' && providerId !== null ? groups.find((group) => group.id === providerId) : undefined\n const busy = state.status === 'selecting'\n\n const reload = () => {\n lastActionRef.current = 'load'\n load()\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 setOpen(false)\n setPane('root')\n }\n document.addEventListener('mousedown', closeOutside)\n return () => {\n document.removeEventListener('mousedown', closeOutside)\n }\n }, [open])\n\n useEffect(() => {\n const intent = focusIntent.current\n focusIntent.current = null\n if (!open || intent === null) return\n if (intent === 'initial') {\n const checked = menuRef.current?.querySelector<HTMLElement>('[role=\"menuitemradio\"][aria-checked=\"true\"]:not([disabled]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n const first = [...itemRefs.current].find(([key]) => !key.startsWith('back:'))?.[1]\n ;(checked ?? first ?? triggerRef.current)?.focus()\n return\n }\n ;(itemRefs.current.get(intent) ?? triggerRef.current)?.focus()\n }, [open, pane])\n\n useLayoutEffect(() => {\n if (!open) {\n setMenuPos(null)\n return\n }\n const place = () => {\n const rect = triggerRef.current?.getBoundingClientRect()\n if (rect === undefined) return\n const MARGIN = 12\n const lw = menuRef.current?.offsetWidth ?? 0\n const lh = menuRef.current?.offsetHeight ?? 0\n let x = rect.right - lw\n let y = rect.top - 8 - lh\n if (lw > 0) x = Math.min(Math.max(x, MARGIN), window.innerWidth - lw - MARGIN)\n if (lh > 0) y = Math.min(Math.max(y, MARGIN), window.innerHeight - lh - MARGIN)\n setMenuPos({ left: x, top: y })\n }\n place()\n window.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n return () => {\n window.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n }\n }, [open, pane, state])\n\n if (!available) return null\n\n const show = () => {\n setPane('root')\n setProviderId(null)\n setOpen(true)\n reload()\n }\n const close = (restoreFocus = false) => {\n setOpen(false)\n setPane('root')\n setProviderId(null)\n if (restoreFocus) queueMicrotask(() => {\n triggerRef.current?.focus()\n })\n }\n const drill = (next: Pane) => {\n focusIntent.current = 'initial'\n setPane(next)\n }\n /** Leave the shown pane for its parent, handing the keyboard back to the row that opened it. */\n const back = () => {\n if (pane === 'models') {\n focusIntent.current = providerId === null ? null : `provider:${providerId}`\n setPane('providers')\n return\n }\n focusIntent.current = pane === 'effort' ? 'root:effort' : 'root:provider'\n setPane('root')\n }\n const moveFocus = (offset: number) => {\n const items = [...itemRefs.current.values()]\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 onRootKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n if (!open) return\n if (event.key === 'Tab') {\n if (event.shiftKey) {\n event.preventDefault()\n if (pane !== 'root') back()\n else close(true)\n return\n }\n const focused = document.activeElement\n const rows = [...itemRefs.current.values()]\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]), [role=\"menuitem\"][aria-current=\"true\"]:not([disabled])')\n ;(checked ?? rows.find((item) => !item.disabled))?.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 const onBlur = (event: React.FocusEvent) => {\n if (event.relatedTarget instanceof Node && (rootRef.current?.contains(event.relatedTarget) === true || menuRef.current?.contains(event.relatedTarget) === true)) return\n close()\n }\n const settleSelection = (result: Awaited<ReturnType<ModelSelectInjected['select']>>) => {\n if (result === undefined) return\n if (result.ok) {\n if (rootRef.current !== null) close(true)\n return\n }\n const { error } = result\n toastSeq.current += 1\n setToast({\n seq: toastSeq.current,\n text: error.code === 'session/writer-held' ? t('error.sessionInUse') : t('error.action', { message: `${error.code}: ${error.message}` }),\n })\n }\n const submit = (selection: Selection) => {\n lastActionRef.current = 'select'\n select(selection).then(settleSelection)\n }\n /** A model commits outright; its reasoning levels stay behind the root's effort cell. */\n const chooseModel = (provider: string, model: CatalogModel) => {\n if (current?.provider === provider && current.model === model.id) {\n close(true)\n return\n }\n submit({ provider, model: model.id })\n }\n const chooseEffort = (effort: string | undefined) => {\n if (current === null) return\n if (effectiveEffort === effort) {\n close(true)\n return\n }\n submit({ provider: current.provider, model: current.model, ...effort === undefined ? {} : { reasoningEffort: effort } })\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 triggerLabel = effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`\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\n itemRefs.current = new Map()\n const itemRef = (key: string) => (node: HTMLButtonElement | null) => {\n if (node === null) itemRefs.current.delete(key)\n else itemRefs.current.set(key, node)\n }\n const backRow = () => (\n <button ref={itemRef('back')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={back}>\n <IconChevronLeftOutlineRegular className={css.cellChevron} />\n <span className={css.cellLabel}>{t('back')}</span>\n </button>\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={triggerLabel}\n disabled={locked}\n onClick={() => {\n if (open) close()\n else show()\n }}\n >\n <IconDataOutlineRegular className={css.triggerIcon} size={16} />\n <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\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=\"menu\"\n aria-label={pane === 'models' && shownGroup !== undefined ? shownGroup.name : pane === 'effort' ? t('menu.effort') : t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n {pane === 'root' && (\n <Fragment>\n <button ref={itemRef('root:provider')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('providers')}>\n <span className={css.cellLabel}>{t('menu.provider')}</span>\n <span className={css.cellValue}>{currentGroup?.name ?? current?.provider ?? ''}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n {reasoning !== undefined && (\n <button ref={itemRef('root:effort')} type=\"button\" role=\"menuitem\" className={css.cell} onClick={() => drill('effort')}>\n <span className={css.cellLabel}>{t('menu.effort')}</span>\n <span className={css.cellValue}>{effortLabel}</span>\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )}\n </Fragment>\n )}\n {pane === 'providers' && (\n <Fragment>\n {state.status === 'loading' && <div className={css.status}>{t('status.loading')}</div>}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {state.failures.map((failure) => (\n <div className={css.warning} key={failure.id}>\n <span>{t('warning.groupLoad', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n ))}\n {state.status === 'ready' && groups.length === 0 && <div className={css.empty}>{t('empty.models')}</div>}\n <div className={cls(css.groups, 'scrollable')}>\n {groups.map((group) => {\n const mine = current?.provider === group.id\n return (\n <button\n key={group.id}\n ref={itemRef(`provider:${group.id}`)}\n type=\"button\"\n role=\"menuitem\"\n aria-current={mine ? 'true' : undefined}\n className={css.cell}\n title={group.name}\n onClick={() => {\n setProviderId(group.id)\n drill('models')\n }}\n >\n <span className={css.cellLabel}>{group.name}</span>\n <span className={css.cellValue}>{mine ? currentModel?.name ?? current?.model ?? '' : t('provider.modelCount', { count: String(group.models.length) })}</span>\n {mine && <span className={css.check}><IconCheckOutlineRegular /></span>}\n <IconChevronRightOutlineRegular className={css.cellChevron} />\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'models' && shownGroup !== undefined && (\n <Fragment>\n {backRow()}\n <div className={cls(css.groups, 'scrollable')}>\n {shownGroup.models.map((model) => {\n const selected = current?.provider === shownGroup.id && current.model === model.id\n return (\n <button\n key={model.id}\n ref={itemRef(`model:${shownGroup.id}/${model.id}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className={cls(css.option, selected && css.selected)}\n title={model.name}\n disabled={busy}\n onClick={() => chooseModel(shownGroup.id, model)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{model.name}</span></span>\n <span className={css.check}>{selected ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n )\n })}\n </div>\n </Fragment>\n )}\n {pane === 'effort' && (\n <Fragment>\n {backRow()}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className={css.error}>\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className={css.retry} onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {effortChoices.length === 0\n ? <div className={css.empty}>{t('empty.efforts')}</div>\n : effortChoices.map((level) => (\n <button\n key={level.key}\n ref={itemRef(`effort:${level.key}`)}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={effectiveEffort === level.effort}\n className={cls(css.option, effectiveEffort === level.effort && css.selected)}\n disabled={busy}\n onClick={() => chooseEffort(level.effort)}\n >\n <span className={css.optionCopy}><span className={css.modelName}>{level.label}</span></span>\n <span className={css.check}>{effectiveEffort === level.effort ? <IconCheckOutlineRegular /> : null}</span>\n </button>\n ))}\n </Fragment>\n )}\n </MenuSurface>\n ), document.body)}\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}","/** Locale bundles for the composer model seat this plugin takes over. */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelSubmenu'\n\n/** Locale keys the seat renders. */\nexport type ModelSubmenuLocaleKey =\n | 'back'\n | 'provider.modelCount'\n | 'action.reload'\n | 'trigger.fallback'\n | 'trigger.loading'\n | 'trigger.selectAria'\n | 'trigger.aria'\n | 'trigger.ariaEffort'\n | 'menu.aria'\n | 'menu.provider'\n | 'menu.effort'\n | 'effort.providerDefault'\n | 'status.loading'\n | 'error.action'\n | 'error.sessionInUse'\n | 'warning.groupLoad'\n | 'empty.models'\n | 'empty.efforts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** The composer model seat'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 'back': '返回',\n 'provider.modelCount': '{count} 个模型',\n 'action.reload': '重新加载',\n 'trigger.fallback': '选择模型',\n 'trigger.loading': '正在加载模型…',\n 'trigger.selectAria': '选择模型',\n 'trigger.aria': '选择模型,当前 {model}',\n 'trigger.ariaEffort': '选择模型,当前 {model},推理等级 {effort}',\n 'menu.aria': '供应商与推理等级',\n 'menu.provider': '供应商',\n 'menu.effort': '推理等级',\n 'effort.providerDefault': 'Default',\n 'status.loading': '正在刷新模型列表…',\n 'error.action': '模型操作失败:{message}',\n 'error.sessionInUse': '当前会话已被占用,可能是其他正在运行的 DSH 导致的(如其他 dsh web、桌面端),请退出其他正在运行的 DSH 后重试。',\n 'warning.groupLoad': '{name} 加载失败:{message}',\n 'empty.models': '没有可用的模型。',\n 'empty.efforts': '当前模型未提供推理等级。',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: Record<ModelSubmenuLocaleKey, string> = {\n 'back': 'Back',\n 'provider.modelCount': '{count} models',\n 'action.reload': 'Reload',\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}, reasoning effort {effort}',\n 'menu.aria': 'Provider and reasoning effort',\n 'menu.provider': 'Provider',\n 'menu.effort': 'Effort',\n 'effort.providerDefault': 'Default',\n 'status.loading': 'Refreshing model list…',\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 'warning.groupLoad': '{name} failed to load: {message}',\n 'empty.models': 'No models available.',\n 'empty.efforts': 'This model provides no reasoning effort levels.',\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.\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 { ModelSubmenu } from './ModelSubmenu.tsx'\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, and\n * `modelDirectories` owns the per-session catalog snapshot this seat renders\n * from. `remote` / `remote.session` are declared because a service method runs\n * on the calling context: `directoryFor` reads `this.ctx.remote.session` while\n * building the directory, so the seat must carry that service too.\n */\nexport const inject = ['locale', 'modelDirectories', 'remote', 'remote.session', 'sessions', 'slots']\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'], (scope) => {\n const models = scope.modelDirectories\n const sessions = scope.sessions\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 load: () => {\n if (available) directory.load().catch(() => {})\n },\n select: (selection) => available ? directory.select(selection) : Promise.resolve(undefined),\n }\n },\n }, ModelSubmenu))\n })\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BA,MAAM,gBAAgB;GACpB,YAAY;GACZ,MAAM;GACN,KAAK;EACP;EAEA,MAAM,OAAO,GAAG,UAA2D,MAAM,QAAQ,SAAS,SAAS,SAAS,SAAS,KAAA,CAAS,CAAC,CAAC,KAAK,GAAG;;;;;;;;;;EAWhJ,SAAgB,aAAa,EAAE,QAAQ,WAAW,WAAW,MAAM,QAAQ,KAAwB;GACjG,MAAM,SAAA,GAAQA,MAAAA,qBAAAA,EAAsB,OAAO,UAAU,UAAU,EAAE,SAAS,UAAU,YAAY,CAAC;GACjG,MAAM,CAAC,MAAM,YAAA,GAAWC,MAAAA,SAAAA,CAAS,KAAK;GACtC,MAAM,CAAC,MAAM,YAAA,GAAWA,MAAAA,SAAAA,CAAe,MAAM;GAC7C,MAAM,CAAC,YAAY,kBAAA,GAAiBA,MAAAA,SAAAA,CAAwB,IAAI;GAChE,MAAM,iBAAA,GAAgBC,MAAAA,OAAAA,CAA0B,MAAM;GACtD,MAAM,CAAC,OAAO,aAAA,GAAYD,MAAAA,SAAAA,CAA+C,IAAI;GAC7E,MAAM,YAAA,GAAWC,MAAAA,OAAAA,CAAO,CAAC;GACzB,MAAM,WAAA,GAAUA,MAAAA,OAAAA,CAA8B,IAAI;GAClD,MAAM,cAAA,GAAaA,MAAAA,OAAAA,CAAiC,IAAI;GACxD,MAAM,WAAA,GAAUA,MAAAA,OAAAA,CAA8B,IAAI;GAClD,MAAM,CAAC,SAAS,eAAA,GAAcD,MAAAA,SAAAA,CAA+C,IAAI;GACjF,MAAM,YAAA,GAAWC,MAAAA,OAAAA,iBAAO,IAAI,IAA+B,CAAC;GAC5D,MAAM,eAAA,GAAcA,MAAAA,OAAAA,CAAsB,IAAI;GAC9C,MAAM,MAAA,GAAKC,MAAAA,MAAAA,CAAM;GAEjB,MAAM,SAAS,MAAM;GACrB,MAAM,UAAU,MAAM;GACtB,MAAM,eAAe,YAAY,OAAO,KAAA,IAAY,OAAO,MAAM,UAAU,MAAM,OAAO,QAAQ,QAAQ;GACxG,MAAM,eAAe,cAAc,OAAO,MAAM,UAAU,MAAM,OAAO,SAAS,KAAK;GACrF,MAAM,YAAY,cAAc;GAChC,MAAM,kBAAkB,SAAS,mBAAmB,WAAW;GAC/D,MAAM,cAAc,cAAc,KAAA,IAC9B,KAAA,IACA,oBAAoB,KAAA,IAClB,EAAE,wBAAwB,IAC1B,UAAU,QAAQ,MAAM,UAAU,MAAM,OAAO,eAAe,CAAC,EAAE,QAAQ;GAC/E,MAAM,iBAAA,GAAgBC,MAAAA,QAAAA,OAAc,cAAc,KAAA,IAAY,CAAC,IAAI,CACjE,GAAG,UAAU,kBAAkB,KAAA,IAC3B,CAAC;IAAE,KAAK;IAAoB,QAAQ,KAAA;IAAiC,OAAO,EAAE,wBAAwB;GAAE,CAAC,IACzG,CAAC,GACL,GAAG,UAAU,QAAQ,KAAK,WAAW;IAAE,KAAK,UAAU,MAAM;IAAM,QAAQ,MAAM;IAA0B,OAAO,MAAM;GAAK,EAAE,CAChI,GAAG,CAAC,WAAW,CAAC,CAAC;GAEjB,MAAM,aAAa,SAAS,YAAY,eAAe,OAAO,OAAO,MAAM,UAAU,MAAM,OAAO,UAAU,IAAI,KAAA;GAChH,MAAM,OAAO,MAAM,WAAW;GAE9B,MAAM,eAAe;IACnB,cAAc,UAAU;IACxB,KAAK;GACP;GAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,IAAI,CAAC,MAAM;IACX,MAAM,gBAAgB,UAAsB;KAC1C,IAAI,QAAQ,SAAS,SAAS,MAAM,MAAc,MAAM,MAAM;KAC9D,IAAI,QAAQ,SAAS,SAAS,MAAM,MAAc,MAAM,MAAM;KAC9D,QAAQ,KAAK;KACb,QAAQ,MAAM;IAChB;IACA,SAAS,iBAAiB,aAAa,YAAY;IACnD,aAAa;KACX,SAAS,oBAAoB,aAAa,YAAY;IACxD;GACF,GAAG,CAAC,IAAI,CAAC;GAET,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,SAAS,YAAY;IAC3B,YAAY,UAAU;IACtB,IAAI,CAAC,QAAQ,WAAW,MAAM;IAC9B,IAAI,WAAW,WAAW;KACxB,MAAM,UAAU,QAAQ,SAAS,cAA2B,6HAAqH;KACjL,MAAM,QAAQ,CAAC,GAAG,SAAS,OAAO,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,WAAW,OAAO,CAAC,CAAC,GAAG;KAC/E,CAAC,WAAW,SAAS,WAAW,QAAA,EAAU,MAAM;KACjD;IACF;IACC,CAAC,SAAS,QAAQ,IAAI,MAAM,KAAK,WAAW,QAAA,EAAU,MAAM;GAC/D,GAAG,CAAC,MAAM,IAAI,CAAC;GAEf,CAAA,GAAA,MAAA,gBAAA,OAAsB;IACpB,IAAI,CAAC,MAAM;KACT,WAAW,IAAI;KACf;IACF;IACA,MAAM,cAAc;KAClB,MAAM,OAAO,WAAW,SAAS,sBAAsB;KACvD,IAAI,SAAS,KAAA,GAAW;KACxB,MAAM,SAAS;KACf,MAAM,KAAK,QAAQ,SAAS,eAAe;KAC3C,MAAM,KAAK,QAAQ,SAAS,gBAAgB;KAC5C,IAAI,IAAI,KAAK,QAAQ;KACrB,IAAI,IAAI,KAAK,MAAM,IAAI;KACvB,IAAI,KAAK,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,OAAO,aAAa,KAAK,MAAM;KAC7E,IAAI,KAAK,GAAG,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,OAAO,cAAc,KAAK,MAAM;KAC9E,WAAW;MAAE,MAAM;MAAG,KAAK;KAAE,CAAC;IAChC;IACA,MAAM;IACN,OAAO,iBAAiB,UAAU,OAAO,IAAI;IAC7C,OAAO,iBAAiB,UAAU,KAAK;IACvC,aAAa;KACX,OAAO,oBAAoB,UAAU,OAAO,IAAI;KAChD,OAAO,oBAAoB,UAAU,KAAK;IAC5C;GACF,GAAG;IAAC;IAAM;IAAM;GAAK,CAAC;GAEtB,IAAI,CAAC,WAAW,OAAO;GAEvB,MAAM,aAAa;IACjB,QAAQ,MAAM;IACd,cAAc,IAAI;IAClB,QAAQ,IAAI;IACZ,OAAO;GACT;GACA,MAAM,SAAS,eAAe,UAAU;IACtC,QAAQ,KAAK;IACb,QAAQ,MAAM;IACd,cAAc,IAAI;IAClB,IAAI,cAAc,qBAAqB;KACrC,WAAW,SAAS,MAAM;IAC5B,CAAC;GACH;GACA,MAAM,SAAS,SAAe;IAC5B,YAAY,UAAU;IACtB,QAAQ,IAAI;GACd;;GAEA,MAAM,aAAa;IACjB,IAAI,SAAS,UAAU;KACrB,YAAY,UAAU,eAAe,OAAO,OAAO,YAAY;KAC/D,QAAQ,WAAW;KACnB;IACF;IACA,YAAY,UAAU,SAAS,WAAW,gBAAgB;IAC1D,QAAQ,MAAM;GAChB;GACA,MAAM,aAAa,WAAmB;IACpC,MAAM,QAAQ,CAAC,GAAG,SAAS,QAAQ,OAAO,CAAC;IAC3C,IAAI,MAAM,WAAW,GAAG;IACxB,MAAM,SAAS,MAAM,WAAW,SAAS,SAAS,SAAS,aAAa;IACxE,MAAM,WAAW,KAAK,SAAS,IAAI,IAAI,MAAM,SAAS,KAAK,SAAS,SAAS,MAAM,UAAU,MAAM,OAAO,EAAE,MAAM;GACpH;GACA,MAAM,iBAAiB,UAA+B;IACpD,IAAI,MAAM,QAAQ,YAAY,MAAM;KAClC,MAAM,eAAe;KACrB,IAAI,SAAS,QAAQ,KAAK;UACrB,MAAM,IAAI;KACf;IACF;IACA,IAAI,CAAC,MAAM;IACX,IAAI,MAAM,QAAQ,OAAO;KACvB,IAAI,MAAM,UAAU;MAClB,MAAM,eAAe;MACrB,IAAI,SAAS,QAAQ,KAAK;WACrB,MAAM,IAAI;MACf;KACF;KACA,MAAM,UAAU,SAAS;KACzB,MAAM,OAAO,CAAC,GAAG,SAAS,QAAQ,OAAO,CAAC;KAC1C,IAAI,mBAAmB,qBAAqB,KAAK,SAAS,OAAO,GAAG;MAClE,MAAM,eAAe;MACrB,QAAQ,MAAM;MACd;KACF;KACA,IAAI,YAAY,WAAW,SAAS;KACpC,MAAM,eAAe;KAEpB,CADe,QAAQ,SAAS,cAA2B,6HAAqH,KACpK,KAAK,MAAM,SAAS,CAAC,KAAK,QAAQ,EAAA,EAAI,MAAM;KACzD;IACF;IACA,IAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,WAAW;KACxD,MAAM,eAAe;KACrB,UAAU,MAAM,QAAQ,cAAc,IAAI,EAAE;IAC9C;GACF;GACA,MAAM,UAAU,UAA4B;IAC1C,IAAI,MAAM,yBAAyB,SAAS,QAAQ,SAAS,SAAS,MAAM,aAAa,MAAM,QAAQ,QAAQ,SAAS,SAAS,MAAM,aAAa,MAAM,OAAO;IACjK,MAAM;GACR;GACA,MAAM,mBAAmB,WAA+D;IACtF,IAAI,WAAW,KAAA,GAAW;IAC1B,IAAI,OAAO,IAAI;KACb,IAAI,QAAQ,YAAY,MAAM,MAAM,IAAI;KACxC;IACF;IACA,MAAM,EAAE,UAAU;IAClB,SAAS,WAAW;IACpB,SAAS;KACP,KAAK,SAAS;KACd,MAAM,MAAM,SAAS,wBAAwB,EAAE,oBAAoB,IAAI,EAAE,gBAAgB,EAAE,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU,CAAC;IACzI,CAAC;GACH;GACA,MAAM,UAAU,cAAyB;IACvC,cAAc,UAAU;IACxB,OAAO,SAAS,CAAC,CAAC,KAAK,eAAe;GACxC;;GAEA,MAAM,eAAe,UAAkB,UAAwB;IAC7D,IAAI,SAAS,aAAa,YAAY,QAAQ,UAAU,MAAM,IAAI;KAChE,MAAM,IAAI;KACV;IACF;IACA,OAAO;KAAE;KAAU,OAAO,MAAM;IAAG,CAAC;GACtC;GACA,MAAM,gBAAgB,WAA+B;IACnD,IAAI,YAAY,MAAM;IACtB,IAAI,oBAAoB,QAAQ;KAC9B,MAAM,IAAI;KACV;IACF;IACA,OAAO;KAAE,UAAU,QAAQ;KAAU,OAAO,QAAQ;KAAO,GAAG,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,iBAAiB,OAAO;IAAE,CAAC;GACzH;GACA,MAAM,UAAU,YAAY,QAAQ,MAAM,WAAW;GACrD,MAAM,aAAa,UAAU,EAAE,iBAAiB,IAAI,cAAc,SAAS,YAAY,OAAO,EAAE,kBAAkB,IAAI,GAAG,QAAQ,SAAS,GAAG,QAAQ;GACrJ,MAAM,eAAe,gBAAgB,KAAA,IAAY,aAAa,GAAG,WAAW,KAAK;GACjF,MAAM,cAAc,UAChB,EAAE,iBAAiB,IACnB,YAAY,OACV,EAAE,oBAAoB,IACtB,gBAAgB,KAAA,IACd,EAAE,gBAAgB,EAAE,OAAO,WAAW,CAAC,IACvC,EAAE,sBAAsB;IAAE,OAAO;IAAY,QAAQ;GAAY,CAAC;GAE1E,SAAS,0BAAU,IAAI,IAAI;GAC3B,MAAM,WAAW,SAAiB,SAAmC;IACnE,IAAI,SAAS,MAAM,SAAS,QAAQ,OAAO,GAAG;SACzC,SAAS,QAAQ,IAAI,KAAK,IAAI;GACrC;GACA,MAAM,gBACJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;IAAQ,KAAK,QAAQ,MAAM;IAAG,MAAK;IAAS,MAAK;IAAW,WAAWC,gCAAI;IAAM,SAAS;IAA1F,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,+BAAD,EAA+B,WAAWD,gCAAI,YAAc,CAAA,GAC5D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,gCAAI;KAAY,UAAA,EAAE,MAAM;IAAQ,CAAA,CAC3C;;GAEV,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,KAAK;IAAS,WAAWA,gCAAI;IAAM,WAAW;IAAuB;IAA1E,UAAA;KACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,KAAK;MACL,MAAK;MACL,WAAWA,gCAAI;MACf,cAAY;MACZ,iBAAc;MACd,iBAAe;MACf,iBAAe,OAAO,GAAG,GAAG,SAAS,KAAA;MACrC,OAAO;MACP,UAAU;MACV,eAAe;OACb,IAAI,MAAM,MAAM;YACX,KAAK;MACZ;MAbF,UAAA;OAeE,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,wBAAD;QAAwB,WAAWF,gCAAI;QAAa,MAAM;OAAK,CAAA;OAC/D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,gCAAI;QAAe,UAAA;OAAiB,CAAA;OACpD,gBAAgB,KAAA,KAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,gCAAI;QAAgB,UAAA;OAAkB,CAAA;OACrF,iBAAA,GAAA,kBAAA,IAAA,CAACG,sCAAAA,+BAAD,EAA+B,WAAW,IAAIH,gCAAI,SAAS,QAAQA,gCAAI,WAAW,EAAI,CAAA;MAChF;;KACP,SAAA,GAAQI,UAAAA,aAAAA,CACP,iBAAA,GAAA,kBAAA,KAAA,CAACC,sCAAAA,aAAD;MACE,KAAK;MACL,IAAI,GAAG,GAAG;MACV,WAAWL,gCAAI;MACf,OAAO,WAAW;MAClB,MAAK;MACL,cAAY,SAAS,YAAY,eAAe,KAAA,IAAY,WAAW,OAAO,SAAS,WAAW,EAAE,aAAa,IAAI,EAAE,WAAW;MAClI,aAAW,MAAM,WAAW,aAAa;MAP3C,UAAA;OASG,SAAS,UACR,iBAAA,GAAA,kBAAA,KAAA,CAACM,MAAAA,UAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,KAAK,QAAQ,eAAe;QAAG,MAAK;QAAS,MAAK;QAAW,WAAWN,gCAAI;QAAM,eAAe,MAAM,WAAW;QAA1H,UAAA;SACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAY,UAAA,EAAE,eAAe;SAAQ,CAAA;SAC1D,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAY,UAAA,cAAc,QAAQ,SAAS,YAAY;SAAS,CAAA;SACrF,iBAAA,GAAA,kBAAA,IAAA,CAACO,sCAAAA,gCAAD,EAAgC,WAAWP,gCAAI,YAAc,CAAA;QACvD;OACP,CAAA,GAAA,cAAc,KAAA,KACb,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;QAAQ,KAAK,QAAQ,aAAa;QAAG,MAAK;QAAS,MAAK;QAAW,WAAWA,gCAAI;QAAM,eAAe,MAAM,QAAQ;QAArH,UAAA;SACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAY,UAAA,EAAE,aAAa;SAAQ,CAAA;SACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAY,UAAA;SAAkB,CAAA;SACnD,iBAAA,GAAA,kBAAA,IAAA,CAACO,sCAAAA,gCAAD,EAAgC,WAAWP,gCAAI,YAAc,CAAA;QACvD;OAEF,CAAA,CAAA,EAAA,CAAA;OAEX,SAAS,eACR,iBAAA,GAAA,kBAAA,KAAA,CAACM,MAAAA,UAAD,EAAA,UAAA;QACG,MAAM,WAAW,aAAa,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWN,gCAAI;SAAS,UAAA,EAAE,gBAAgB;QAAO,CAAA;QACpF,MAAM,UAAU,QAAQ,cAAc,YAAY,UACjD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,gCAAI;SAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,gBAAgB,EAAE,SAAS,MAAM,MAAM,CAAC,EAAQ,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,MAAK;UAAS,WAAWA,gCAAI;UAAO,SAAS;UAAS,UAAA,EAAE,eAAe;SAAU,CAAA,CACtF;;QAEN,MAAM,SAAS,KAAK,YACnB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,gCAAI;SAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,qBAAqB;UAAE,MAAM,QAAQ;UAAM,SAAS,QAAQ;SAAQ,CAAC,EAAQ,CAAA,GACtF,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,MAAK;UAAS,WAAWA,gCAAI;UAAO,SAAS;UAAS,UAAA,EAAE,eAAe;SAAU,CAAA,CACtF;QAH6B,GAAA,QAAQ,EAGrC,CACN;QACA,MAAM,WAAW,WAAW,OAAO,WAAW,KAAK,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,gCAAI;SAAQ,UAAA,EAAE,cAAc;QAAO,CAAA;QACvG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAW,IAAIA,gCAAI,QAAQ,YAAY;SACzC,UAAA,OAAO,KAAK,UAAU;UACrB,MAAM,OAAO,SAAS,aAAa,MAAM;UACzC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;WAEE,KAAK,QAAQ,YAAY,MAAM,IAAI;WACnC,MAAK;WACL,MAAK;WACL,gBAAc,OAAO,SAAS,KAAA;WAC9B,WAAWA,gCAAI;WACf,OAAO,MAAM;WACb,eAAe;YACb,cAAc,MAAM,EAAE;YACtB,MAAM,QAAQ;WAChB;WAXF,UAAA;YAaE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;aAAM,WAAWA,gCAAI;aAAY,UAAA,MAAM;YAAW,CAAA;YAClD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;aAAM,WAAWA,gCAAI;aAAY,UAAA,OAAO,cAAc,QAAQ,SAAS,SAAS,KAAK,EAAE,uBAAuB,EAAE,OAAO,OAAO,MAAM,OAAO,MAAM,EAAE,CAAC;YAAQ,CAAA;YAC3J,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;aAAM,WAAWA,gCAAI;aAAO,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACQ,sCAAAA,yBAAD,CAA0B,CAAA;YAAO,CAAA;YACtE,iBAAA,GAAA,kBAAA,IAAA,CAACD,sCAAAA,gCAAD,EAAgC,WAAWP,gCAAI,YAAc,CAAA;WACvD;UAhBD,GAAA,MAAM,EAgBL;SAEZ,CAAC;QACE,CAAA;OACG,EAAA,CAAA;OAEX,SAAS,YAAY,eAAe,KAAA,KACnC,iBAAA,GAAA,kBAAA,KAAA,CAACM,MAAAA,UAAD,EAAA,UAAA,CACG,QAAQ,GACT,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;QAAK,WAAW,IAAIN,gCAAI,QAAQ,YAAY;QACzC,UAAA,WAAW,OAAO,KAAK,UAAU;SAChC,MAAM,WAAW,SAAS,aAAa,WAAW,MAAM,QAAQ,UAAU,MAAM;SAChF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;UAEE,KAAK,QAAQ,SAAS,WAAW,GAAG,GAAG,MAAM,IAAI;UACjD,MAAK;UACL,MAAK;UACL,gBAAc;UACd,WAAW,IAAIA,gCAAI,QAAQ,YAAYA,gCAAI,QAAQ;UACnD,OAAO,MAAM;UACb,UAAU;UACV,eAAe,YAAY,WAAW,IAAI,KAAK;UATjD,UAAA,CAWE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,gCAAI;WAAY,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;YAAM,WAAWA,gCAAI;YAAY,UAAA,MAAM;WAAW,CAAA;UAAO,CAAA,GAC1F,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,gCAAI;WAAQ,UAAA,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAACQ,sCAAAA,yBAAD,CAA0B,CAAA,IAAI;UAAW,CAAA,CAC3E;SAZD,GAAA,MAAM,EAYL;QAEZ,CAAC;OACE,CAAA,CACG,EAAA,CAAA;OAEX,SAAS,YACR,iBAAA,GAAA,kBAAA,KAAA,CAACF,MAAAA,UAAD,EAAA,UAAA;QACG,QAAQ;QACR,MAAM,UAAU,QAAQ,cAAc,YAAY,UACjD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWN,gCAAI;SAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,EAAE,gBAAgB,EAAE,SAAS,MAAM,MAAM,CAAC,EAAQ,CAAA,GACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;UAAQ,MAAK;UAAS,WAAWA,gCAAI;UAAO,SAAS;UAAS,UAAA,EAAE,eAAe;SAAU,CAAA,CACtF;;QAEN,cAAc,WAAW,IACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,gCAAI;SAAQ,UAAA,EAAE,eAAe;QAAO,CAAA,IACpD,cAAc,KAAK,UACnB,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;SAEE,KAAK,QAAQ,UAAU,MAAM,KAAK;SAClC,MAAK;SACL,MAAK;SACL,gBAAc,oBAAoB,MAAM;SACxC,WAAW,IAAIA,gCAAI,QAAQ,oBAAoB,MAAM,UAAUA,gCAAI,QAAQ;SAC3E,UAAU;SACV,eAAe,aAAa,MAAM,MAAM;SAR1C,UAAA,CAUE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAY,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,gCAAI;WAAY,UAAA,MAAM;UAAY,CAAA;SAAO,CAAA,GAC3F,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAM,WAAWA,gCAAI;UAAQ,UAAA,oBAAoB,MAAM,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAACQ,sCAAAA,yBAAD,CAA0B,CAAA,IAAI;SAAW,CAAA,CACnG;QAXD,GAAA,MAAM,GAWL,CACT;OACK,EAAA,CAAA;MAED;KACZ,CAAA,GAAA,SAAS,IAAI;KACf,UAAU,QACT,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,OAAD;MAEE,MAAM,MAAM;MACZ,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,2BAAD,CAA4B,CAAA;MAClC,QAAQ,QAAQ,SAAS,QAAQ,sBAAsB,KAAK;MAC5D,cAAc;OACZ,SAAS,IAAI;MACf;KACD,GAPM,MAAM,GAOZ;IAEA;;EAET;;;;;ECvaA,MAAa,KAAK;;EA+BlB,MAAa,KAA4C;GACvD,QAAQ;GACR,uBAAuB;GACvB,iBAAiB;GACjB,oBAAoB;GACpB,mBAAmB;GACnB,sBAAsB;GACtB,gBAAgB;GAChB,sBAAsB;GACtB,aAAa;GACb,iBAAiB;GACjB,eAAe;GACf,0BAA0B;GAC1B,kBAAkB;GAClB,gBAAgB;GAChB,sBAAsB;GACtB,qBAAqB;GACrB,gBAAgB;GAChB,iBAAiB;EACnB;;EAGA,MAAa,KAA4C;GACvD,QAAQ;GACR,uBAAuB;GACvB,iBAAiB;GACjB,oBAAoB;GACpB,mBAAmB;GACnB,sBAAsB;GACtB,gBAAgB;GAChB,sBAAsB;GACtB,aAAa;GACb,iBAAiB;GACjB,eAAe;GACf,0BAA0B;GAC1B,kBAAkB;GAClB,gBAAgB;GAChB,sBAAsB;GACtB,qBAAqB;GACrB,gBAAgB;GAChB,iBAAiB;EACnB;;;;;;;;;;;ECpDA,MAAa,SAAS;GAAC;GAAU;GAAoB;GAAU;GAAkB;GAAY;EAAO;;;;;;;EAQpG,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI;IAAE;IAAI;GAAG,CAAC,GAAG,iCAAiC;GACvF,IAAI,OAAO,CAAC,SAAS,kBAAkB,IAAI,UAAU;IACnD,MAAM,SAAS,MAAM;IACrB,MAAM,WAAW,MAAM;IACvB,MAAM,MAAM,OAAO,kCAAkC,MAAM,MAAM,SAAS;KACxE,MAAM;KACN,UAAU;KACV,YAAY;KACZ,QAAQ;KACR,SAAS,cAAc;MAGrB,MAAM,MAAM;MACZ,MAAM,YAAY,OAAO,aAAa,GAAG;MACzC,MAAM,YAAY,SAAS,gBAAgB,GAAG,MAAM,KAAA;MACpD,OAAO;OACL;OACA,WAAW,UAAU;OACrB,YAAY;QACV,IAAI,WAAW,UAAU,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC;OAChD;OACA,SAAS,cAAc,YAAY,UAAU,OAAO,SAAS,IAAI,QAAQ,QAAQ,KAAA,CAAS;MAC5F;KACF;IACF,GAAG,YAAY,CAAC;GAClB,CAAC;EACH"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["css","IconCheckOutlineRegular","getItem","useId","useRef","useState","useMemo","rankByName","Modal","css","Input","IconSearchOutlineRegular","ShortcutKeys","useSyncExternalStore","useState","useRef","useId","useMemo","useCallback","css","IconFlatListOutlineRegular","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 /** 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, 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 {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 ModelRow as CatalogRow,\n type PickerTab,\n} from './rows.ts'\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 /** 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, 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 const frame = requestAnimationFrame(() => { searchRef.current?.focus() })\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 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, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport { createPortal } from 'react-dom'\nimport {\n IconChevronDownOutlineRegular,\n IconFlatListOutlineRegular,\n IconWarningOutlineRegular,\n MenuSurface,\n Toast,\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, 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 [menuPos, setMenuPos] = useState<{ left: number; top: number } | 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 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 useLayoutEffect(() => {\n if (!open) {\n setMenuPos(null)\n return\n }\n const place = () => {\n const rect = triggerRef.current?.getBoundingClientRect()\n if (rect === undefined) return\n const MARGIN = 12\n const lw = menuRef.current?.offsetWidth ?? 0\n const lh = menuRef.current?.offsetHeight ?? 0\n // Right edges align, so the card grows leftward from the trigger's corner.\n let x = rect.right - lw\n let y = rect.top - 8 - lh\n if (lw > 0) x = Math.min(Math.max(x, MARGIN), window.innerWidth - lw - MARGIN)\n if (lh > 0) y = Math.min(Math.max(y, MARGIN), window.innerHeight - lh - MARGIN)\n setMenuPos({ left: x, top: y })\n }\n place()\n window.addEventListener('scroll', place, true)\n window.addEventListener('resize', place)\n return () => {\n window.removeEventListener('scroll', place, true)\n window.removeEventListener('resize', place)\n }\n }, [open, state])\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 <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\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 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 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 select: (selection) => available ? directory.select(selection) : Promise.resolve(undefined),\n }\n },\n }, ModelSubmenu))\n })\n}\n"],"mappings":"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"}
|
package/locale/en.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"meta": {
|
|
3
|
-
"title": "Model
|
|
4
|
-
"description": "
|
|
3
|
+
"title": "Model picker",
|
|
4
|
+
"description": "The composer's model picker: one menu for the current provider's models and effort, one dialog for every provider's models with search and favorites."
|
|
5
5
|
}
|
|
6
6
|
}
|
package/locale/zh.json
CHANGED
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynn123411/dsh-model-submenu",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "给输入框的模型选择器换成两层:一层只列当前供应商的模型与思考等级,一层弹窗列全部供应商的模型。",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"packageManager": "pnpm@11.7.0",
|
|
6
7
|
"publishConfig": {
|
|
7
8
|
"access": "public"
|
|
8
9
|
},
|
|
9
10
|
"type": "module",
|
|
10
11
|
"engines": {
|
|
11
12
|
"node": "^22.19.0 || >=24.0.0",
|
|
12
|
-
"dsh": ">=0.2.1-
|
|
13
|
+
"dsh": ">=0.2.1-rc.2"
|
|
13
14
|
},
|
|
14
15
|
"main": "lib/index.js",
|
|
15
16
|
"exports": {
|
|
@@ -45,9 +46,11 @@
|
|
|
45
46
|
"client": {
|
|
46
47
|
"platform": "web",
|
|
47
48
|
"inject": [
|
|
48
|
-
"@deepseek-ai/dsh-
|
|
49
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
49
50
|
"@deepseek-ai/dsh-client-locale",
|
|
50
|
-
"@deepseek-ai/dsh-client-ui-model-selection"
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
51
54
|
]
|
|
52
55
|
}
|
|
53
56
|
},
|
|
@@ -56,11 +59,12 @@
|
|
|
56
59
|
"typecheck": "tsc -p tsconfig.json --pretty false",
|
|
57
60
|
"smoke": "node scripts/smoke-client.mjs",
|
|
58
61
|
"assert:lib-untracked": "node scripts/assert-lib-untracked.mjs",
|
|
59
|
-
"check": "pnpm typecheck && pnpm build && pnpm smoke && pnpm assert:lib-untracked"
|
|
62
|
+
"check": "pnpm typecheck && pnpm build && pnpm smoke && pnpm test && pnpm assert:lib-untracked",
|
|
63
|
+
"test": "node scripts/test-favorites.mjs && node scripts/test-facts.mjs && node scripts/test-commit.mjs && node scripts/test-rows.mjs && node scripts/test-effort-memory.mjs && node scripts/test-render.mjs"
|
|
60
64
|
},
|
|
61
65
|
"peerDependencies": {
|
|
62
|
-
"@deepseek-ai/cordis": "^4.0.5
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.2.1-
|
|
66
|
+
"@deepseek-ai/cordis": "^4.0.5",
|
|
67
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.2.1-rc.2",
|
|
64
68
|
"react": "^18.2.0"
|
|
65
69
|
},
|
|
66
70
|
"peerDependenciesMeta": {
|
|
@@ -69,21 +73,23 @@
|
|
|
69
73
|
}
|
|
70
74
|
},
|
|
71
75
|
"devDependencies": {
|
|
72
|
-
"@deepseek-ai/cordis": "^4.0.5
|
|
73
|
-
"@deepseek-ai/dsh-api-remotes": ">=0.2.1-
|
|
74
|
-
"@deepseek-ai/dsh-api-session-controller": ">=0.2.1-
|
|
75
|
-
"@deepseek-ai/dsh-client-locale": ">=0.2.1-
|
|
76
|
-
"@deepseek-ai/dsh-client-store": ">=0.2.1-
|
|
77
|
-
"@deepseek-ai/dsh-client-ui-conversation": ">=0.2.1-
|
|
78
|
-
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.2.1-
|
|
79
|
-
"@deepseek-ai/dsh-client-ui-primitives": ">=0.2.1-
|
|
80
|
-
"@deepseek-ai/dsh-client-ui-renderer": ">=0.2.1-
|
|
81
|
-
"@deepseek-ai/dsh-client-ui-
|
|
82
|
-
"@deepseek-ai/dsh-
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
76
|
+
"@deepseek-ai/cordis": "^4.0.5",
|
|
77
|
+
"@deepseek-ai/dsh-api-remotes": ">=0.2.1-rc.2",
|
|
78
|
+
"@deepseek-ai/dsh-api-session-controller": ">=0.2.1-rc.2",
|
|
79
|
+
"@deepseek-ai/dsh-client-locale": ">=0.2.1-rc.2",
|
|
80
|
+
"@deepseek-ai/dsh-client-store": ">=0.2.1-rc.2",
|
|
81
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.2.1-rc.2",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-model-selection": ">=0.2.1-rc.2",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-primitives": ">=0.2.1-rc.2",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-renderer": ">=0.2.1-rc.2",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.2.1-rc.2",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.2.1-rc.2",
|
|
87
|
+
"@deepseek-ai/dsh-session": ">=0.2.1-rc.2",
|
|
88
|
+
"@deepseek-ai/dsh-typert-protocol": ">=0.2.1-rc.2",
|
|
84
89
|
"@types/node": "^22.20.0",
|
|
85
90
|
"@types/react": "~18.3.1",
|
|
86
91
|
"@types/react-dom": "~18.3.0",
|
|
92
|
+
"jsdom": "^26.1.0",
|
|
87
93
|
"lightningcss": "^1.30.1",
|
|
88
94
|
"react": "^18.3.1",
|
|
89
95
|
"react-dom": "^18.3.1",
|