dsh-llm-verifier 0.2.0 → 0.2.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 +114 -10
- package/lib/client.js.map +1 -1
- package/lib/types/client-i18n.d.ts +29 -0
- package/lib/types/client-i18n.d.ts.map +1 -1
- package/lib/types/client-i18n.js +61 -0
- package/lib/types/client-i18n.js.map +1 -1
- package/lib/types/client.d.ts +2 -2
- package/lib/types/client.d.ts.map +1 -1
- package/lib/types/client.js +80 -31
- package/lib/types/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client-i18n.ts +61 -0
- package/src/client.test.ts +86 -0
- package/src/client.tsx +59 -4
package/lib/client.js
CHANGED
|
@@ -111,6 +111,7 @@ window.__ModuleLoader__.load({
|
|
|
111
111
|
"settings.catalogFailures": "部分模型目录读取失败",
|
|
112
112
|
"settings.saved": "设置已保存。",
|
|
113
113
|
"settings.reload": "重新载入",
|
|
114
|
+
"settings.unsaved": "当前页面有未保存的修改:点击「保存」后才会写入设置;「重新载入」会丢弃这些修改。",
|
|
114
115
|
"settings.save": "保存设置",
|
|
115
116
|
"settings.saving": "保存中…",
|
|
116
117
|
"stats.pageTitle": "Verifier 工具统计",
|
|
@@ -291,6 +292,7 @@ window.__ModuleLoader__.load({
|
|
|
291
292
|
"settings.catalogFailures": "Some model catalogs failed to load",
|
|
292
293
|
"settings.saved": "Settings saved.",
|
|
293
294
|
"settings.reload": "Reload",
|
|
295
|
+
"settings.unsaved": "This page has unsaved changes: click Save to write them; Reload discards them.",
|
|
294
296
|
"settings.save": "Save Settings",
|
|
295
297
|
"settings.saving": "Saving…",
|
|
296
298
|
"stats.pageTitle": "Verifier Tool Statistics",
|
|
@@ -447,6 +449,55 @@ window.__ModuleLoader__.load({
|
|
|
447
449
|
if (typeof draft === "string" && draft.trim()) return draft.trim();
|
|
448
450
|
if (typeof previous === "string" && previous.trim()) return previous.trim();
|
|
449
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Deep equality for JSON-shaped settings values, insensitive to object key
|
|
454
|
+
* order and treating a missing key as `undefined`. The settings page compares a
|
|
455
|
+
* draft against a resolved view that was built from a different object shape,
|
|
456
|
+
* so identity comparison is never enough.
|
|
457
|
+
*/
|
|
458
|
+
function sameSettingValue(left, right) {
|
|
459
|
+
if (left === right) return true;
|
|
460
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
461
|
+
if (left.length !== right.length) return false;
|
|
462
|
+
for (let index = 0; index < left.length; index += 1) if (!sameSettingValue(left[index], right[index])) return false;
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
if (Array.isArray(left) || Array.isArray(right)) return false;
|
|
466
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
|
|
467
|
+
const a = left;
|
|
468
|
+
const b = right;
|
|
469
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) if (!sameSettingValue(a[key], b[key])) return false;
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Build the user layer for one settings save.
|
|
474
|
+
*
|
|
475
|
+
* Keys this client does not own survive untouched and every draft field is
|
|
476
|
+
* written, but a field that only repeats the base composition is *dropped*
|
|
477
|
+
* rather than pinned. Pinning is what makes a shipped default change
|
|
478
|
+
* unreachable: the budget fields once defaulted to 48/160, and a section that
|
|
479
|
+
* stored those numbers kept overriding 64/240 and then 96/240 forever. `base`
|
|
480
|
+
* is the descriptor's composition base (the resolved plugin config), so the
|
|
481
|
+
* stored section keeps exactly what the user really overrode.
|
|
482
|
+
*
|
|
483
|
+
* An explicit `undefined` draft value means "clear this override": it deletes
|
|
484
|
+
* the stored key instead of pinning a valueless one, which is how the form
|
|
485
|
+
* removes a judge label, a reasoning effort or a cache directory.
|
|
486
|
+
*
|
|
487
|
+
* A host that reports no `base` cannot be pruned against and keeps the old
|
|
488
|
+
* write-everything behavior.
|
|
489
|
+
*/
|
|
490
|
+
function sectionForSave(user, draft, base) {
|
|
491
|
+
const section = { ...user };
|
|
492
|
+
for (const [key, value] of Object.entries(draft)) {
|
|
493
|
+
if (value === void 0 || base !== void 0 && sameSettingValue(value, base[key])) {
|
|
494
|
+
delete section[key];
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
section[key] = value;
|
|
498
|
+
}
|
|
499
|
+
return section;
|
|
500
|
+
}
|
|
450
501
|
/** An eight-candidate select: ring + pivot rounds (18 pairs) x three criteria, one repeat. */
|
|
451
502
|
const WORST_CASE_ROUTE_CALLS_PER_JUDGE = 54;
|
|
452
503
|
/** Final acceptance: three criteria x the default two repeats (one per A/B position). */
|
|
@@ -836,6 +887,50 @@ window.__ModuleLoader__.load({
|
|
|
836
887
|
(0, react.useEffect)(() => {
|
|
837
888
|
load();
|
|
838
889
|
}, []);
|
|
890
|
+
const dirty = (0, react.useMemo)(() => loaded !== null && draft !== null && !sameSettingValue(draft, values(loaded.settings)), [loaded, draft]);
|
|
891
|
+
const latest = (0, react.useRef)({
|
|
892
|
+
loaded,
|
|
893
|
+
draft
|
|
894
|
+
});
|
|
895
|
+
latest.current = {
|
|
896
|
+
loaded,
|
|
897
|
+
draft
|
|
898
|
+
};
|
|
899
|
+
(0, react.useEffect)(() => {
|
|
900
|
+
const sync = () => {
|
|
901
|
+
if (document.visibilityState === "hidden") return;
|
|
902
|
+
const { loaded: at, draft: local } = latest.current;
|
|
903
|
+
if (!at || !local) return;
|
|
904
|
+
if (!sameSettingValue(local, values(at.settings))) return;
|
|
905
|
+
(async () => {
|
|
906
|
+
try {
|
|
907
|
+
const s = await remote.settings.describe();
|
|
908
|
+
if (!s.ok) return;
|
|
909
|
+
const view = s.value.namespaces.find((x) => x.ns === NS);
|
|
910
|
+
if (!view || view.revision === at.settings.revision) return;
|
|
911
|
+
const next = {
|
|
912
|
+
...at,
|
|
913
|
+
settings: view,
|
|
914
|
+
writable: s.value.writable
|
|
915
|
+
};
|
|
916
|
+
latest.current = {
|
|
917
|
+
loaded: next,
|
|
918
|
+
draft: values(view)
|
|
919
|
+
};
|
|
920
|
+
setLoaded(next);
|
|
921
|
+
setDraft(values(view));
|
|
922
|
+
setEditing({});
|
|
923
|
+
setSaved(false);
|
|
924
|
+
} catch {}
|
|
925
|
+
})();
|
|
926
|
+
};
|
|
927
|
+
window.addEventListener("focus", sync);
|
|
928
|
+
document.addEventListener("visibilitychange", sync);
|
|
929
|
+
return () => {
|
|
930
|
+
window.removeEventListener("focus", sync);
|
|
931
|
+
document.removeEventListener("visibilitychange", sync);
|
|
932
|
+
};
|
|
933
|
+
}, [remote]);
|
|
839
934
|
const models = (0, react.useMemo)(() => loaded?.groups.find((g) => g.id === draft?.provider)?.models ?? [], [loaded, draft?.provider]);
|
|
840
935
|
const efforts = models.find((m) => m.id === draft?.model)?.reasoning?.efforts ?? [];
|
|
841
936
|
const patch = (key, value) => {
|
|
@@ -894,17 +989,15 @@ window.__ModuleLoader__.load({
|
|
|
894
989
|
setSaved(false);
|
|
895
990
|
setError(null);
|
|
896
991
|
try {
|
|
897
|
-
const
|
|
898
|
-
...record(loaded.settings.user),
|
|
992
|
+
const editable = {
|
|
899
993
|
...draft,
|
|
900
|
-
extraJudges: serializeExtraJudges(draft.extraJudges)
|
|
994
|
+
extraJudges: serializeExtraJudges(draft.extraJudges),
|
|
995
|
+
reasoningEffort: draft.reasoningEffort || void 0,
|
|
996
|
+
label: draft.label?.trim() || void 0,
|
|
997
|
+
cacheDir: resolveCacheDirOnSave(draft.cacheDir, values(loaded.settings).cacheDir)
|
|
901
998
|
};
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
else section.label = draft.label.trim();
|
|
905
|
-
const resolvedCacheDir = resolveCacheDirOnSave(draft.cacheDir, values(loaded.settings).cacheDir);
|
|
906
|
-
if (!resolvedCacheDir) delete section.cacheDir;
|
|
907
|
-
else section.cacheDir = resolvedCacheDir;
|
|
999
|
+
const base = loaded.settings.base === void 0 ? void 0 : record(loaded.settings.base);
|
|
1000
|
+
const section = sectionForSave(record(loaded.settings.user), editable, base);
|
|
908
1001
|
const res = await remote.settings.update(NS, section, loaded.settings.revision);
|
|
909
1002
|
if (!res.ok) throw new Error(res.error.message);
|
|
910
1003
|
setLoaded((v) => v ? {
|
|
@@ -1629,7 +1722,7 @@ window.__ModuleLoader__.load({
|
|
|
1629
1722
|
},
|
|
1630
1723
|
children: error
|
|
1631
1724
|
}),
|
|
1632
|
-
saved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1725
|
+
saved && !dirty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1633
1726
|
style: {
|
|
1634
1727
|
margin: 0,
|
|
1635
1728
|
fontSize: 12,
|
|
@@ -1638,6 +1731,15 @@ window.__ModuleLoader__.load({
|
|
|
1638
1731
|
},
|
|
1639
1732
|
children: t["settings.saved"]
|
|
1640
1733
|
}),
|
|
1734
|
+
dirty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1735
|
+
style: {
|
|
1736
|
+
margin: 0,
|
|
1737
|
+
fontSize: 12,
|
|
1738
|
+
lineHeight: "18px",
|
|
1739
|
+
color: "var(--dsw-alias-state-warn-label)"
|
|
1740
|
+
},
|
|
1741
|
+
children: t["settings.unsaved"]
|
|
1742
|
+
}),
|
|
1641
1743
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1642
1744
|
style: {
|
|
1643
1745
|
display: "flex",
|
|
@@ -2633,6 +2735,8 @@ window.__ModuleLoader__.load({
|
|
|
2633
2735
|
exports.isVerdictFailed = isVerdictFailed;
|
|
2634
2736
|
exports.money = money;
|
|
2635
2737
|
exports.resolveCacheDirOnSave = resolveCacheDirOnSave;
|
|
2738
|
+
exports.sameSettingValue = sameSettingValue;
|
|
2739
|
+
exports.sectionForSave = sectionForSave;
|
|
2636
2740
|
exports.tFormat = tFormat;
|
|
2637
2741
|
exports.toolLabels = toolLabels;
|
|
2638
2742
|
exports.useLanguage = useLanguage;
|