@lynn123411/dsh-model-submenu 0.1.0 → 0.1.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/lib/client.js +10 -10
- package/lib/client.js.map +1 -1
- package/package.json +15 -15
- package/src/client/ModelSubmenu.tsx +16 -16
package/lib/client.js
CHANGED
|
@@ -287,7 +287,7 @@ window.__ModuleLoader__.load({
|
|
|
287
287
|
role: "menuitem",
|
|
288
288
|
className: ModelSubmenu_module_css_default.cell,
|
|
289
289
|
onClick: back,
|
|
290
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
290
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronLeftOutlineRegular, { className: ModelSubmenu_module_css_default.cellChevron }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
291
291
|
className: ModelSubmenu_module_css_default.cellLabel,
|
|
292
292
|
children: t("back")
|
|
293
293
|
})]
|
|
@@ -313,7 +313,7 @@ window.__ModuleLoader__.load({
|
|
|
313
313
|
else show();
|
|
314
314
|
},
|
|
315
315
|
children: [
|
|
316
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
316
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconDataOutlineRegular, {
|
|
317
317
|
className: ModelSubmenu_module_css_default.triggerIcon,
|
|
318
318
|
size: 16
|
|
319
319
|
}),
|
|
@@ -325,7 +325,7 @@ window.__ModuleLoader__.load({
|
|
|
325
325
|
className: ModelSubmenu_module_css_default.triggerEffort,
|
|
326
326
|
children: effortLabel
|
|
327
327
|
}),
|
|
328
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
328
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: cls(ModelSubmenu_module_css_default.chevron, open && ModelSubmenu_module_css_default.chevronOpen) })
|
|
329
329
|
]
|
|
330
330
|
}),
|
|
331
331
|
open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -352,7 +352,7 @@ window.__ModuleLoader__.load({
|
|
|
352
352
|
className: ModelSubmenu_module_css_default.cellValue,
|
|
353
353
|
children: currentGroup?.name ?? current?.provider ?? ""
|
|
354
354
|
}),
|
|
355
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
355
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { className: ModelSubmenu_module_css_default.cellChevron })
|
|
356
356
|
]
|
|
357
357
|
}), reasoning !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
358
358
|
ref: itemRef("root:effort"),
|
|
@@ -369,7 +369,7 @@ window.__ModuleLoader__.load({
|
|
|
369
369
|
className: ModelSubmenu_module_css_default.cellValue,
|
|
370
370
|
children: effortLabel
|
|
371
371
|
}),
|
|
372
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
372
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { className: ModelSubmenu_module_css_default.cellChevron })
|
|
373
373
|
]
|
|
374
374
|
})] }),
|
|
375
375
|
pane === "providers" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
|
|
@@ -428,9 +428,9 @@ window.__ModuleLoader__.load({
|
|
|
428
428
|
}),
|
|
429
429
|
mine && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
430
430
|
className: ModelSubmenu_module_css_default.check,
|
|
431
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
431
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {})
|
|
432
432
|
}),
|
|
433
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
433
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { className: ModelSubmenu_module_css_default.cellChevron })
|
|
434
434
|
]
|
|
435
435
|
}, group.id);
|
|
436
436
|
})
|
|
@@ -457,7 +457,7 @@ window.__ModuleLoader__.load({
|
|
|
457
457
|
})
|
|
458
458
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
459
459
|
className: ModelSubmenu_module_css_default.check,
|
|
460
|
-
children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
460
|
+
children: selected ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {}) : null
|
|
461
461
|
})]
|
|
462
462
|
}, model.id);
|
|
463
463
|
})
|
|
@@ -492,7 +492,7 @@ window.__ModuleLoader__.load({
|
|
|
492
492
|
})
|
|
493
493
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
494
494
|
className: ModelSubmenu_module_css_default.check,
|
|
495
|
-
children: effectiveEffort === level.effort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
495
|
+
children: effectiveEffort === level.effort ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {}) : null
|
|
496
496
|
})]
|
|
497
497
|
}, level.key))
|
|
498
498
|
] })
|
|
@@ -500,7 +500,7 @@ window.__ModuleLoader__.load({
|
|
|
500
500
|
}), document.body),
|
|
501
501
|
toast !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
502
502
|
text: toast.text,
|
|
503
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
503
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
|
|
504
504
|
anchor: rootRef.current?.closest("[data-composer-card]") ?? null,
|
|
505
505
|
onDone: () => {
|
|
506
506
|
setToast(null);
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","useId","useMemo","css","IconChevronLeftOutline14","IconDataOutline16","IconChevronDownOutline14","createPortal","Fragment","IconChevronRightOutline14","IconCheckOutline16","Toast","IconWarningOutline16"],"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 IconCheckOutline16,\n IconChevronDownOutline14,\n IconChevronLeftOutline14,\n IconChevronRightOutline14,\n IconDataOutline16,\n IconWarningOutline16,\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 <IconChevronLeftOutline14 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 <IconDataOutline16 className={css.triggerIcon} size={16} />\n <span className={css.triggerLabel}>{modelLabel}</span>\n {effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}\n <IconChevronDownOutline14 className={cls(css.chevron, open && css.chevronOpen)} />\n </button>\n {open && createPortal((\n <div\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 <IconChevronRightOutline14 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 <IconChevronRightOutline14 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}><IconCheckOutline16 /></span>}\n <IconChevronRightOutline14 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 ? <IconCheckOutline16 /> : 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 ? <IconCheckOutline16 /> : null}</span>\n </button>\n ))}\n </Fragment>\n )}\n </div>\n ), document.body)}\n {toast !== null && (\n <Toast\n key={toast.seq}\n text={toast.text}\n icon={<IconWarningOutline16 />}\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":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useRef","useId","useMemo","css","IconChevronLeftOutlineRegular","IconDataOutlineRegular","IconChevronDownOutlineRegular","createPortal","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 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 <div\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 </div>\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":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynn123411/dsh-model-submenu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0",
|
|
8
|
-
"dsh": "0.1.
|
|
8
|
+
"dsh": "0.1.7-rc.2"
|
|
9
9
|
},
|
|
10
10
|
"main": "lib/index.js",
|
|
11
11
|
"exports": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"check": "pnpm typecheck && pnpm build && pnpm smoke && pnpm assert:lib-untracked"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
53
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
54
54
|
"@deepseek-ai/dsh-client-ui-primitives": "*",
|
|
55
55
|
"react": "^18.2.0"
|
|
56
56
|
},
|
|
@@ -60,18 +60,18 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"@deepseek-ai/cordis": "4.0.
|
|
64
|
-
"@deepseek-ai/dsh-api-remotes": "0.1.
|
|
65
|
-
"@deepseek-ai/dsh-api-session-controller": "0.1.
|
|
66
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
67
|
-
"@deepseek-ai/dsh-client-store": "0.1.
|
|
68
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.
|
|
69
|
-
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.
|
|
70
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
71
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.
|
|
72
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
73
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
74
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.
|
|
63
|
+
"@deepseek-ai/cordis": "^4.0.4",
|
|
64
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
|
|
65
|
+
"@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2",
|
|
66
|
+
"@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
|
|
67
|
+
"@deepseek-ai/dsh-client-store": "0.1.7-rc.2",
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.7-rc.2",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-session": "0.1.7-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2",
|
|
75
75
|
"@types/node": "^22.20.0",
|
|
76
76
|
"@types/react": "~18.3.1",
|
|
77
77
|
"@types/react-dom": "~18.3.0",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
|
|
2
2
|
import { createPortal } from 'react-dom'
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
IconCheckOutlineRegular,
|
|
5
|
+
IconChevronDownOutlineRegular,
|
|
6
|
+
IconChevronLeftOutlineRegular,
|
|
7
|
+
IconChevronRightOutlineRegular,
|
|
8
|
+
IconDataOutlineRegular,
|
|
9
|
+
IconWarningOutlineRegular,
|
|
10
10
|
Toast,
|
|
11
11
|
} from '@deepseek-ai/dsh-client-ui-primitives'
|
|
12
12
|
import type { ModelDirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'
|
|
@@ -259,7 +259,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
259
259
|
}
|
|
260
260
|
const backRow = () => (
|
|
261
261
|
<button ref={itemRef('back')} type="button" role="menuitem" className={css.cell} onClick={back}>
|
|
262
|
-
<
|
|
262
|
+
<IconChevronLeftOutlineRegular className={css.cellChevron} />
|
|
263
263
|
<span className={css.cellLabel}>{t('back')}</span>
|
|
264
264
|
</button>
|
|
265
265
|
)
|
|
@@ -280,10 +280,10 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
280
280
|
else show()
|
|
281
281
|
}}
|
|
282
282
|
>
|
|
283
|
-
<
|
|
283
|
+
<IconDataOutlineRegular className={css.triggerIcon} size={16} />
|
|
284
284
|
<span className={css.triggerLabel}>{modelLabel}</span>
|
|
285
285
|
{effortLabel !== undefined && <span className={css.triggerEffort}>{effortLabel}</span>}
|
|
286
|
-
<
|
|
286
|
+
<IconChevronDownOutlineRegular className={cls(css.chevron, open && css.chevronOpen)} />
|
|
287
287
|
</button>
|
|
288
288
|
{open && createPortal((
|
|
289
289
|
<div
|
|
@@ -300,13 +300,13 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
300
300
|
<button ref={itemRef('root:provider')} type="button" role="menuitem" className={css.cell} onClick={() => drill('providers')}>
|
|
301
301
|
<span className={css.cellLabel}>{t('menu.provider')}</span>
|
|
302
302
|
<span className={css.cellValue}>{currentGroup?.name ?? current?.provider ?? ''}</span>
|
|
303
|
-
<
|
|
303
|
+
<IconChevronRightOutlineRegular className={css.cellChevron} />
|
|
304
304
|
</button>
|
|
305
305
|
{reasoning !== undefined && (
|
|
306
306
|
<button ref={itemRef('root:effort')} type="button" role="menuitem" className={css.cell} onClick={() => drill('effort')}>
|
|
307
307
|
<span className={css.cellLabel}>{t('menu.effort')}</span>
|
|
308
308
|
<span className={css.cellValue}>{effortLabel}</span>
|
|
309
|
-
<
|
|
309
|
+
<IconChevronRightOutlineRegular className={css.cellChevron} />
|
|
310
310
|
</button>
|
|
311
311
|
)}
|
|
312
312
|
</Fragment>
|
|
@@ -346,8 +346,8 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
346
346
|
>
|
|
347
347
|
<span className={css.cellLabel}>{group.name}</span>
|
|
348
348
|
<span className={css.cellValue}>{mine ? currentModel?.name ?? current?.model ?? '' : t('provider.modelCount', { count: String(group.models.length) })}</span>
|
|
349
|
-
{mine && <span className={css.check}><
|
|
350
|
-
<
|
|
349
|
+
{mine && <span className={css.check}><IconCheckOutlineRegular /></span>}
|
|
350
|
+
<IconChevronRightOutlineRegular className={css.cellChevron} />
|
|
351
351
|
</button>
|
|
352
352
|
)
|
|
353
353
|
})}
|
|
@@ -373,7 +373,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
373
373
|
onClick={() => chooseModel(shownGroup.id, model)}
|
|
374
374
|
>
|
|
375
375
|
<span className={css.optionCopy}><span className={css.modelName}>{model.name}</span></span>
|
|
376
|
-
<span className={css.check}>{selected ? <
|
|
376
|
+
<span className={css.check}>{selected ? <IconCheckOutlineRegular /> : null}</span>
|
|
377
377
|
</button>
|
|
378
378
|
)
|
|
379
379
|
})}
|
|
@@ -403,7 +403,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
403
403
|
onClick={() => chooseEffort(level.effort)}
|
|
404
404
|
>
|
|
405
405
|
<span className={css.optionCopy}><span className={css.modelName}>{level.label}</span></span>
|
|
406
|
-
<span className={css.check}>{effectiveEffort === level.effort ? <
|
|
406
|
+
<span className={css.check}>{effectiveEffort === level.effort ? <IconCheckOutlineRegular /> : null}</span>
|
|
407
407
|
</button>
|
|
408
408
|
))}
|
|
409
409
|
</Fragment>
|
|
@@ -414,7 +414,7 @@ export function ModelSubmenu({ locked, available, directory, load, select, t }:
|
|
|
414
414
|
<Toast
|
|
415
415
|
key={toast.seq}
|
|
416
416
|
text={toast.text}
|
|
417
|
-
icon={<
|
|
417
|
+
icon={<IconWarningOutlineRegular />}
|
|
418
418
|
anchor={rootRef.current?.closest('[data-composer-card]') ?? null}
|
|
419
419
|
onDone={() => {
|
|
420
420
|
setToast(null)
|