@bittersmilezzz/dsh-model-selector 0.2.0 → 0.3.0
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
CHANGED
|
@@ -760,9 +760,9 @@ window.__ModuleLoader__.load({
|
|
|
760
760
|
* reused from @deepseek-ai/dsh-client-ui-primitives at runtime; colors
|
|
761
761
|
* come from `--dsw-*` tokens in the injected stylesheet.
|
|
762
762
|
*/
|
|
763
|
-
const IconChevronDown = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
764
|
-
const IconCheck = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
765
|
-
const IconClear = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
763
|
+
const IconChevronDown = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { size: 14 });
|
|
764
|
+
const IconCheck = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 });
|
|
765
|
+
const IconClear = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseFillRegular, { size: 14 });
|
|
766
766
|
/**
|
|
767
767
|
* How long a successfully loaded directory snapshot is trusted before the
|
|
768
768
|
* menu re-fetches it over RPC. The snapshot lives in the per-session store,
|
|
@@ -877,7 +877,7 @@ window.__ModuleLoader__.load({
|
|
|
877
877
|
const current = state.current;
|
|
878
878
|
if (current === null) throw new Error(t("empty.efforts"));
|
|
879
879
|
const modelKeyAtCommit = dmsRowKey(current.provider, current.model);
|
|
880
|
-
|
|
880
|
+
const result = await new Promise((resolve, reject) => {
|
|
881
881
|
let settled = false;
|
|
882
882
|
const timer = window.setTimeout(() => {
|
|
883
883
|
if (settled) return;
|
|
@@ -890,11 +890,11 @@ window.__ModuleLoader__.load({
|
|
|
890
890
|
provider: current.provider,
|
|
891
891
|
model: current.model,
|
|
892
892
|
reasoningEffort: next
|
|
893
|
-
}).then((
|
|
893
|
+
}).then((result) => {
|
|
894
894
|
if (settled) {
|
|
895
895
|
const latest = stateRef.current.current;
|
|
896
896
|
const sameModel = latest !== null && dmsRowKey(latest.provider, latest.model) === modelKeyAtCommit;
|
|
897
|
-
if (
|
|
897
|
+
if (result?.ok === true && mountedRef.current && dmsShouldAdoptLateSuccess(committedRef.current, previous, draggingRef.current, committingRef.current, commitEpochRef.current, epochAtCommit, sameModel)) {
|
|
898
898
|
committedRef.current = next;
|
|
899
899
|
previewRef.current = index;
|
|
900
900
|
setEffort(next);
|
|
@@ -906,7 +906,7 @@ window.__ModuleLoader__.load({
|
|
|
906
906
|
settled = true;
|
|
907
907
|
window.clearTimeout(timer);
|
|
908
908
|
commitTimerRef.current = null;
|
|
909
|
-
resolve(
|
|
909
|
+
resolve(result);
|
|
910
910
|
}, (cause) => {
|
|
911
911
|
if (settled) return;
|
|
912
912
|
settled = true;
|
|
@@ -914,7 +914,11 @@ window.__ModuleLoader__.load({
|
|
|
914
914
|
commitTimerRef.current = null;
|
|
915
915
|
reject(cause);
|
|
916
916
|
});
|
|
917
|
-
})
|
|
917
|
+
});
|
|
918
|
+
if (result === void 0 || !result.ok) {
|
|
919
|
+
if (result !== void 0) console.warn("[dsh-model-selector] effort select failed:", result.error);
|
|
920
|
+
throw new Error(t("effort.failed"));
|
|
921
|
+
}
|
|
918
922
|
if (mountedRef.current) {
|
|
919
923
|
committedRef.current = next;
|
|
920
924
|
previewRef.current = index;
|
|
@@ -922,18 +926,22 @@ window.__ModuleLoader__.load({
|
|
|
922
926
|
setPreview(index);
|
|
923
927
|
}
|
|
924
928
|
} catch (cause) {
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
929
|
+
if (commitEpochRef.current === epochAtCommit) {
|
|
930
|
+
onSelectFailure();
|
|
931
|
+
const restore = Math.max(0, dmsEffortIndex(levels, previous));
|
|
932
|
+
committedRef.current = previous;
|
|
933
|
+
previewRef.current = restore;
|
|
934
|
+
if (mountedRef.current) {
|
|
935
|
+
setEffort(previous);
|
|
936
|
+
setPreview(restore);
|
|
937
|
+
setLocalError(cause instanceof Error ? cause.message : String(cause));
|
|
938
|
+
}
|
|
933
939
|
}
|
|
934
940
|
} finally {
|
|
935
|
-
|
|
936
|
-
|
|
941
|
+
if (commitEpochRef.current === epochAtCommit) {
|
|
942
|
+
committingRef.current = false;
|
|
943
|
+
if (mountedRef.current) setCommitting(false);
|
|
944
|
+
}
|
|
937
945
|
}
|
|
938
946
|
}, [
|
|
939
947
|
levels,
|
|
@@ -1049,7 +1057,7 @@ window.__ModuleLoader__.load({
|
|
|
1049
1057
|
* 但 100 条命中里绝大多数命中区间不变——按值比较 start/end,值相同即跳过
|
|
1050
1058
|
* 重渲染,搜索才不卡顿。
|
|
1051
1059
|
*/
|
|
1052
|
-
const ModelOption = react.memo(function ModelOption({ group, model, showProvider, selected, busy, rowKey, active, searchMode, onRowFocus, nameHit, t, onChoose }) {
|
|
1060
|
+
const ModelOption = react.memo(function ModelOption({ group, model, showProvider, selected, busy, rowKey, active, searchMode, onRowFocus, nameHit, setsize, posinset, t, onChoose }) {
|
|
1053
1061
|
const hit = nameHit === void 0 || nameHit === null || nameHit.start === nameHit.end ? null : [
|
|
1054
1062
|
model.name.slice(0, nameHit.start),
|
|
1055
1063
|
model.name.slice(nameHit.start, nameHit.end),
|
|
@@ -1060,6 +1068,9 @@ window.__ModuleLoader__.load({
|
|
|
1060
1068
|
role: searchMode ? "option" : "menuitemradio",
|
|
1061
1069
|
"aria-checked": searchMode ? void 0 : selected,
|
|
1062
1070
|
"aria-selected": searchMode ? selected : void 0,
|
|
1071
|
+
id: searchMode ? `dms-opt-${encodeURIComponent(rowKey)}` : void 0,
|
|
1072
|
+
"aria-setsize": searchMode && setsize !== void 0 && setsize > posinset ? setsize : void 0,
|
|
1073
|
+
"aria-posinset": searchMode && posinset !== void 0 ? posinset : void 0,
|
|
1063
1074
|
"data-row-key": rowKey,
|
|
1064
1075
|
tabIndex: active ? 0 : -1,
|
|
1065
1076
|
className: `dms-model-option${selected ? " dms-model-optionSelected" : ""}`,
|
|
@@ -1118,6 +1129,8 @@ window.__ModuleLoader__.load({
|
|
|
1118
1129
|
if (prev.onRowFocus !== next.onRowFocus) return false;
|
|
1119
1130
|
if (prev.t !== next.t) return false;
|
|
1120
1131
|
if (prev.onChoose !== next.onChoose) return false;
|
|
1132
|
+
if (prev.setsize !== next.setsize) return false;
|
|
1133
|
+
if (prev.posinset !== next.posinset) return false;
|
|
1121
1134
|
if (prev.nameHit === next.nameHit) return true;
|
|
1122
1135
|
if (prev.nameHit === null || prev.nameHit === void 0) return false;
|
|
1123
1136
|
if (next.nameHit === null || next.nameHit === void 0) return false;
|
|
@@ -1363,26 +1376,27 @@ window.__ModuleLoader__.load({
|
|
|
1363
1376
|
const autoName = plan.effort === void 0 ? "" : target?.model.reasoning?.efforts.find((level) => level.id === plan.effort)?.name ?? plan.effort;
|
|
1364
1377
|
(async () => {
|
|
1365
1378
|
try {
|
|
1366
|
-
|
|
1379
|
+
const result = await new Promise((resolve, reject) => {
|
|
1367
1380
|
let settled = false;
|
|
1368
1381
|
const timer = window.setTimeout(() => {
|
|
1369
1382
|
if (settled) return;
|
|
1370
1383
|
settled = true;
|
|
1371
1384
|
reject(new Error(t("notice.selectFailed")));
|
|
1372
1385
|
}, EFFORT_COMMIT_TIMEOUT_MS);
|
|
1373
|
-
select(full).then((
|
|
1386
|
+
select(full).then((settledResult) => {
|
|
1374
1387
|
if (settled) return;
|
|
1375
1388
|
settled = true;
|
|
1376
1389
|
window.clearTimeout(timer);
|
|
1377
|
-
resolve(
|
|
1390
|
+
resolve(settledResult);
|
|
1378
1391
|
}, (cause) => {
|
|
1379
1392
|
if (settled) return;
|
|
1380
1393
|
settled = true;
|
|
1381
1394
|
window.clearTimeout(timer);
|
|
1382
1395
|
reject(cause);
|
|
1383
1396
|
});
|
|
1384
|
-
})
|
|
1385
|
-
|
|
1397
|
+
});
|
|
1398
|
+
if (result === void 0 || !result.ok) {
|
|
1399
|
+
const message = result !== void 0 ? `${result.error.code}: ${result.error.message}` : directory.getSnapshot().error;
|
|
1386
1400
|
showToast(message !== null ? t("error.action", { message }) : t("notice.selectFailed"));
|
|
1387
1401
|
return;
|
|
1388
1402
|
}
|
|
@@ -1472,7 +1486,7 @@ window.__ModuleLoader__.load({
|
|
|
1472
1486
|
close();
|
|
1473
1487
|
return;
|
|
1474
1488
|
}
|
|
1475
|
-
if (
|
|
1489
|
+
if (document.visibilityState === "hidden") close();
|
|
1476
1490
|
};
|
|
1477
1491
|
const trigger = dmsTriggerCopy({
|
|
1478
1492
|
current: state.current,
|
|
@@ -1583,7 +1597,7 @@ window.__ModuleLoader__.load({
|
|
|
1583
1597
|
placeholder: t("search.placeholder"),
|
|
1584
1598
|
"aria-label": t("search.placeholder"),
|
|
1585
1599
|
role: "combobox",
|
|
1586
|
-
"aria-expanded": hits !== null,
|
|
1600
|
+
"aria-expanded": hits !== null && hits.total > 0,
|
|
1587
1601
|
"aria-autocomplete": "list",
|
|
1588
1602
|
"aria-controls": emptyState === null ? `${id}-groups` : void 0,
|
|
1589
1603
|
autoComplete: "off",
|
|
@@ -1635,7 +1649,7 @@ window.__ModuleLoader__.load({
|
|
|
1635
1649
|
role: hits !== null ? "listbox" : "menu",
|
|
1636
1650
|
"aria-busy": state.status === "loading" || busy,
|
|
1637
1651
|
"aria-label": t("menu.aria"),
|
|
1638
|
-
children: hits !== null ? hits.items.map((hit) => {
|
|
1652
|
+
children: hits !== null ? hits.items.map((hit, index) => {
|
|
1639
1653
|
const rowKey = dmsRowKey(hit.group.id, hit.model.id);
|
|
1640
1654
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelOption, {
|
|
1641
1655
|
group: hit.group,
|
|
@@ -1648,6 +1662,8 @@ window.__ModuleLoader__.load({
|
|
|
1648
1662
|
searchMode: true,
|
|
1649
1663
|
onRowFocus,
|
|
1650
1664
|
nameHit: hit.nameHit,
|
|
1665
|
+
setsize: hits.total,
|
|
1666
|
+
posinset: index + 1,
|
|
1651
1667
|
t,
|
|
1652
1668
|
onChoose: choose
|
|
1653
1669
|
}, rowKey);
|
|
@@ -1737,7 +1753,7 @@ window.__ModuleLoader__.load({
|
|
|
1737
1753
|
}) : null,
|
|
1738
1754
|
toast !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
1739
1755
|
text: toast.text,
|
|
1740
|
-
icon: toast.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
1756
|
+
icon: toast.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, { size: 14 }) : void 0,
|
|
1741
1757
|
anchor: rootRef.current?.closest("[data-composer-card]") ?? null,
|
|
1742
1758
|
onDone: dismissToast
|
|
1743
1759
|
}, toast.seq)
|
|
@@ -1859,9 +1875,20 @@ window.__ModuleLoader__.load({
|
|
|
1859
1875
|
animation-name: dms-menu-in-below;
|
|
1860
1876
|
}
|
|
1861
1877
|
|
|
1878
|
+
/* 菜单头部的「非列表」栏(loading / 空态 / 错误条 / 失败条 / 截断提示):
|
|
1879
|
+
一律允许收缩(flex-shrink 1)且各自限高,让 .dms-groups 始终保住可滚动
|
|
1880
|
+
的最小可视高度。2026-09-21 修复的 P0:向上弹时 useAnchoredMaxHeight 会把
|
|
1881
|
+
maxHeight 钳到「trigger 底缘 - 12px」(底缘固定、向上生长的语义),trigger
|
|
1882
|
+
靠近视口顶部时该值很小;原先这些栏是 flex: 0 0 auto 完全不收缩,头部
|
|
1883
|
+
40-100px 全部占完后 .dms-groups 的可视高度趋近 0,而 .dms-menu 是
|
|
1884
|
+
overflow:hidden —— 用户看到错误条却看不到也滚不到任何模型行。
|
|
1885
|
+
现在给它们统一的上限(相对菜单高度)+ overflow,最坏情况是栏内自己滚动。 */
|
|
1862
1886
|
.dms-status,
|
|
1863
1887
|
.dms-empty {
|
|
1864
|
-
flex: 0
|
|
1888
|
+
flex: 0 1 auto;
|
|
1889
|
+
min-height: 0;
|
|
1890
|
+
max-height: 40%;
|
|
1891
|
+
overflow-y: auto;
|
|
1865
1892
|
padding: 10px;
|
|
1866
1893
|
color: var(--dsw-alias-label-tertiary);
|
|
1867
1894
|
font-size: 13px;
|
|
@@ -1869,7 +1896,10 @@ window.__ModuleLoader__.load({
|
|
|
1869
1896
|
}
|
|
1870
1897
|
|
|
1871
1898
|
.dms-more {
|
|
1872
|
-
flex: 0
|
|
1899
|
+
flex: 0 1 auto;
|
|
1900
|
+
min-height: 0;
|
|
1901
|
+
max-height: 20%;
|
|
1902
|
+
overflow-y: auto;
|
|
1873
1903
|
padding: 8px 12px;
|
|
1874
1904
|
border-top: 1px solid var(--dsw-alias-border-l1, transparent);
|
|
1875
1905
|
color: var(--dsw-alias-label-tertiary);
|
|
@@ -1880,15 +1910,18 @@ window.__ModuleLoader__.load({
|
|
|
1880
1910
|
/* Provider-load failure strip: capped and scrollable so a long list of failed
|
|
1881
1911
|
groups can never squeeze the model list out of the menu (E4). */
|
|
1882
1912
|
.dms-failures {
|
|
1883
|
-
flex: 0
|
|
1884
|
-
max-height: 96px;
|
|
1913
|
+
flex: 0 1 auto;
|
|
1914
|
+
max-height: min(96px, 30%);
|
|
1885
1915
|
min-height: 0;
|
|
1886
1916
|
overflow-y: auto;
|
|
1887
1917
|
}
|
|
1888
1918
|
|
|
1889
1919
|
.dms-error,
|
|
1890
1920
|
.dms-warning {
|
|
1891
|
-
flex: 0
|
|
1921
|
+
flex: 0 1 auto;
|
|
1922
|
+
min-height: 0;
|
|
1923
|
+
max-height: 40%;
|
|
1924
|
+
overflow-y: auto;
|
|
1892
1925
|
display: flex;
|
|
1893
1926
|
align-items: flex-start;
|
|
1894
1927
|
justify-content: space-between;
|
|
@@ -1963,7 +1996,10 @@ window.__ModuleLoader__.load({
|
|
|
1963
1996
|
/* 图标组件只收 size/className,装饰性 aria-hidden 只能包一层 span;contents 让它不占布局。 */
|
|
1964
1997
|
.dms-icon-slot { display: contents; }
|
|
1965
1998
|
|
|
1966
|
-
|
|
1999
|
+
/* 列表区:菜单里唯一的弹性主体。max-height 被 useAnchoredMaxHeight 钳得很小
|
|
2000
|
+
(trigger 靠近视口顶 + 向上弹)时,32px 保底让「至少见到一行模型」始终成立
|
|
2001
|
+
—— 头部各栏此时按自己的 max-height 百分比上限收缩(见 .dms-status 等)。 */
|
|
2002
|
+
.dms-groups { flex: 1 1 auto; min-height: 32px; overflow-y: auto; contain: content; }
|
|
1967
2003
|
/* 空态占位:空态播报节点在 role=menu 容器外,用与 .dms-groups 同款弹性布局
|
|
1968
2004
|
补回列表区本来的位置(不挤压其余栏,消息也不会贴到菜单顶部)。 */
|
|
1969
2005
|
.dms-groupsFill { flex: 1 1 auto; min-height: 0; overflow-y: auto; contain: content; }
|
|
@@ -2421,10 +2457,7 @@ body:not([data-ds-dark-theme]) .dms-effort.is-dragging .dms-effort-knob {
|
|
|
2421
2457
|
console.warn("[dsh-model-selector] directory.load failed:", error);
|
|
2422
2458
|
});
|
|
2423
2459
|
},
|
|
2424
|
-
select: (selection) => available ? directory.select(selection).
|
|
2425
|
-
console.warn("[dsh-model-selector] select failed:", error);
|
|
2426
|
-
return false;
|
|
2427
|
-
}) : Promise.resolve(false)
|
|
2460
|
+
select: (selection) => available ? directory.select(selection) : Promise.resolve(void 0)
|
|
2428
2461
|
};
|
|
2429
2462
|
}
|
|
2430
2463
|
}, ModelSelect));
|
|
@@ -2435,7 +2468,7 @@ body:not([data-ds-dark-theme]) .dms-effort.is-dragging .dms-effort-knob {
|
|
|
2435
2468
|
exports.apply = apply;
|
|
2436
2469
|
exports.inject = inject;
|
|
2437
2470
|
return module.exports;
|
|
2438
|
-
/* __DMS_SRC_HASH__ = "
|
|
2471
|
+
/* __DMS_SRC_HASH__ = "86fa33a484beb4717e3ba62f62d7834bd0be9438ebf41565218cd94a6da91e19" */ }
|
|
2439
2472
|
});
|
|
2440
2473
|
|
|
2441
2474
|
//# sourceMappingURL=client.js.map
|