dsh-llm-verifier 0.1.2 → 0.1.3
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 +187 -116
- package/lib/types/client.js +15 -10
- package/package.json +1 -1
- package/src/client.tsx +44 -25
package/lib/client.js
CHANGED
|
@@ -10,46 +10,87 @@ window.__ModuleLoader__.load({
|
|
|
10
10
|
//#region src/client.tsx
|
|
11
11
|
const NS = "llm-verifier";
|
|
12
12
|
const shell = {
|
|
13
|
+
width: "100%",
|
|
14
|
+
maxWidth: 720,
|
|
13
15
|
display: "flex",
|
|
14
16
|
flexDirection: "column",
|
|
15
|
-
gap:
|
|
16
|
-
padding: "
|
|
17
|
-
color: "var(--dsw-
|
|
17
|
+
gap: 12,
|
|
18
|
+
padding: "0 0 32px",
|
|
19
|
+
color: "var(--dsw-alias-label-primary)"
|
|
20
|
+
};
|
|
21
|
+
const settingsHeading = {
|
|
22
|
+
margin: 0,
|
|
23
|
+
fontSize: 16,
|
|
24
|
+
fontWeight: 500,
|
|
25
|
+
lineHeight: "24px",
|
|
26
|
+
color: "var(--dsw-alias-label-primary)"
|
|
18
27
|
};
|
|
19
|
-
const
|
|
28
|
+
const settingsIntro = {
|
|
29
|
+
margin: 0,
|
|
30
|
+
fontSize: 14,
|
|
31
|
+
lineHeight: "22px",
|
|
32
|
+
color: "var(--dsw-alias-label-tertiary)"
|
|
33
|
+
};
|
|
34
|
+
const group = {
|
|
35
|
+
width: "100%",
|
|
20
36
|
display: "flex",
|
|
21
37
|
flexDirection: "column",
|
|
22
|
-
|
|
23
|
-
padding: "16px 16px 0",
|
|
24
|
-
border: "1px solid var(--dsw-alias-border-l2, rgba(255, 255, 255, 0.16))",
|
|
25
|
-
borderRadius: 12,
|
|
26
|
-
background: "var(--dsw-alias-bg-module, rgba(20, 31, 57, 0.42))",
|
|
27
|
-
overflow: "hidden"
|
|
38
|
+
borderTop: "1px solid var(--dsw-alias-border-l2)"
|
|
28
39
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
const groupTitle = {
|
|
41
|
+
margin: 0,
|
|
42
|
+
padding: "18px 0 8px",
|
|
43
|
+
fontSize: 14,
|
|
44
|
+
fontWeight: 500,
|
|
45
|
+
lineHeight: "22px",
|
|
46
|
+
color: "var(--dsw-alias-label-primary)"
|
|
35
47
|
};
|
|
36
48
|
const row = {
|
|
49
|
+
minHeight: 64,
|
|
37
50
|
display: "grid",
|
|
38
|
-
gridTemplateColumns: "minmax(
|
|
39
|
-
gap:
|
|
51
|
+
gridTemplateColumns: "minmax(180px, 1fr) minmax(230px, 288px)",
|
|
52
|
+
gap: 24,
|
|
40
53
|
alignItems: "center",
|
|
41
|
-
padding: "
|
|
42
|
-
borderBottom: "1px solid var(--dsw-alias-border-l2
|
|
54
|
+
padding: "12px 0",
|
|
55
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2)"
|
|
43
56
|
};
|
|
44
57
|
const selectStyle = {
|
|
58
|
+
boxSizing: "border-box",
|
|
45
59
|
width: "100%",
|
|
46
|
-
|
|
47
|
-
padding: "0 12px",
|
|
48
|
-
borderRadius:
|
|
49
|
-
color: "var(--dsw-
|
|
50
|
-
background: "var(--dsw-
|
|
51
|
-
border: "1px solid var(--dsw-alias-border-l2
|
|
60
|
+
height: 36,
|
|
61
|
+
padding: "0 34px 0 12px",
|
|
62
|
+
borderRadius: 8,
|
|
63
|
+
color: "var(--dsw-alias-label-primary)",
|
|
64
|
+
background: "var(--dsw-alias-bg-input)",
|
|
65
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
66
|
+
font: "inherit",
|
|
67
|
+
fontSize: 14,
|
|
68
|
+
lineHeight: "22px",
|
|
69
|
+
outline: "none"
|
|
52
70
|
};
|
|
71
|
+
const toggleStyle = (enabled) => ({
|
|
72
|
+
position: "relative",
|
|
73
|
+
justifySelf: "end",
|
|
74
|
+
width: 40,
|
|
75
|
+
height: 22,
|
|
76
|
+
padding: 0,
|
|
77
|
+
border: 0,
|
|
78
|
+
borderRadius: 999,
|
|
79
|
+
cursor: "pointer",
|
|
80
|
+
transition: "background .15s ease",
|
|
81
|
+
background: enabled ? "var(--dsw-alias-state-success-primary)" : "var(--dsw-alias-bg-input)"
|
|
82
|
+
});
|
|
83
|
+
const toggleThumbStyle = (enabled) => ({
|
|
84
|
+
position: "absolute",
|
|
85
|
+
top: 3,
|
|
86
|
+
left: enabled ? 21 : 3,
|
|
87
|
+
width: 16,
|
|
88
|
+
height: 16,
|
|
89
|
+
borderRadius: "50%",
|
|
90
|
+
background: "var(--dsw-static-neutral-00, #fff)",
|
|
91
|
+
boxShadow: "0 1px 3px rgba(0,0,0,.28)",
|
|
92
|
+
transition: "left .15s ease"
|
|
93
|
+
});
|
|
53
94
|
const dashboardCard = {
|
|
54
95
|
border: "1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.13))",
|
|
55
96
|
background: "color-mix(in srgb, var(--dsw-alias-bg-module, #171925) 88%, transparent)",
|
|
@@ -95,17 +136,32 @@ window.__ModuleLoader__.load({
|
|
|
95
136
|
return error instanceof Error ? error.message : String(error);
|
|
96
137
|
}
|
|
97
138
|
function Label({ title, help }) {
|
|
98
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
99
|
-
style: {
|
|
100
|
-
children:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
139
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
140
|
+
style: { minWidth: 0 },
|
|
141
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
142
|
+
style: {
|
|
143
|
+
fontSize: 14,
|
|
144
|
+
fontWeight: 400,
|
|
145
|
+
lineHeight: "22px",
|
|
146
|
+
color: "var(--dsw-alias-label-primary)"
|
|
147
|
+
},
|
|
148
|
+
children: title
|
|
149
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
150
|
+
style: {
|
|
151
|
+
fontSize: 12,
|
|
152
|
+
lineHeight: "18px",
|
|
153
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
154
|
+
marginTop: 2
|
|
155
|
+
},
|
|
156
|
+
children: help
|
|
157
|
+
})]
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function GroupTitle({ children }) {
|
|
161
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
162
|
+
style: groupTitle,
|
|
163
|
+
children
|
|
164
|
+
});
|
|
109
165
|
}
|
|
110
166
|
function compact(value) {
|
|
111
167
|
return new Intl.NumberFormat("zh-CN", {
|
|
@@ -212,15 +268,27 @@ window.__ModuleLoader__.load({
|
|
|
212
268
|
if (!loaded || !draft) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
213
269
|
style: shell,
|
|
214
270
|
children: [
|
|
215
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
216
|
-
|
|
217
|
-
|
|
271
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
272
|
+
style: settingsHeading,
|
|
273
|
+
children: "LLM Verifier"
|
|
274
|
+
}),
|
|
275
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
276
|
+
style: settingsIntro,
|
|
277
|
+
children: error ?? "正在读取 DSH 模型和设置…"
|
|
278
|
+
}),
|
|
279
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
280
|
+
variant: "outline",
|
|
218
281
|
onClick: () => void load(),
|
|
219
282
|
children: "重试"
|
|
220
|
-
})
|
|
283
|
+
}) })
|
|
221
284
|
]
|
|
222
285
|
});
|
|
223
286
|
const numeric = (key, min = 0) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
287
|
+
style: {
|
|
288
|
+
width: "100%",
|
|
289
|
+
height: 36,
|
|
290
|
+
borderRadius: 8
|
|
291
|
+
},
|
|
224
292
|
type: "number",
|
|
225
293
|
min,
|
|
226
294
|
value: String(draft[key]),
|
|
@@ -229,66 +297,53 @@ window.__ModuleLoader__.load({
|
|
|
229
297
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
230
298
|
style: shell,
|
|
231
299
|
children: [
|
|
232
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
233
|
-
style:
|
|
300
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
301
|
+
style: settingsHeading,
|
|
234
302
|
children: "LLM Verifier"
|
|
235
|
-
}),
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
243
|
-
style: card,
|
|
303
|
+
}),
|
|
304
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
305
|
+
style: settingsIntro,
|
|
306
|
+
children: "选择已在 DSH「模型」中配置的模型作为独立裁判。修改后点击页面底部的保存按钮生效。"
|
|
307
|
+
}),
|
|
308
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
309
|
+
style: group,
|
|
244
310
|
children: [
|
|
245
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
246
|
-
style: sectionTitle,
|
|
247
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: draft.enabled ? "done" : "error" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "工具开关" })]
|
|
248
|
-
}),
|
|
311
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupTitle, { children: "工具" }),
|
|
249
312
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
250
313
|
style: row,
|
|
251
314
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
252
315
|
title: "启用 Verifier 工具",
|
|
253
|
-
help: draft.enabled ? "
|
|
316
|
+
help: draft.enabled ? "允许 Agent 调用四个 verifier 工具并向裁判模型发起请求。" : "停用后,所有 verifier 工具都会立即返回错误。"
|
|
254
317
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
318
|
+
type: "button",
|
|
319
|
+
role: "switch",
|
|
320
|
+
"aria-checked": draft.enabled,
|
|
321
|
+
"aria-label": "启用 Verifier 工具",
|
|
255
322
|
onClick: () => patch("enabled", !draft.enabled),
|
|
256
|
-
style:
|
|
257
|
-
|
|
258
|
-
height: 32,
|
|
259
|
-
borderRadius: 16,
|
|
260
|
-
border: "1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.16))",
|
|
261
|
-
background: draft.enabled ? "var(--dsw-success, #2f9e5b)" : "var(--dsw-surface-sunken)",
|
|
262
|
-
color: "#fff",
|
|
263
|
-
cursor: "pointer",
|
|
264
|
-
fontSize: 13,
|
|
265
|
-
fontWeight: 600
|
|
266
|
-
},
|
|
267
|
-
children: draft.enabled ? "已启用" : "已停用"
|
|
323
|
+
style: toggleStyle(draft.enabled),
|
|
324
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: toggleThumbStyle(draft.enabled) })
|
|
268
325
|
})]
|
|
269
326
|
}),
|
|
270
|
-
!draft.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
327
|
+
!draft.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
271
328
|
style: {
|
|
272
|
-
|
|
329
|
+
margin: "8px 0 0",
|
|
273
330
|
fontSize: 12,
|
|
274
|
-
|
|
331
|
+
lineHeight: "18px",
|
|
332
|
+
color: "var(--dsw-alias-state-warn-label)"
|
|
275
333
|
},
|
|
276
|
-
children: "
|
|
334
|
+
children: "verifier_compare、verifier_select、verifier_track 和 verifier_current_session 当前不可用。"
|
|
277
335
|
})
|
|
278
336
|
]
|
|
279
337
|
}),
|
|
280
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
281
|
-
style:
|
|
338
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
339
|
+
style: group,
|
|
282
340
|
children: [
|
|
283
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
284
|
-
style: sectionTitle,
|
|
285
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "done" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "裁判模型" })]
|
|
286
|
-
}),
|
|
341
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupTitle, { children: "裁判模型" }),
|
|
287
342
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
288
343
|
style: row,
|
|
289
344
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
290
345
|
title: "供应商",
|
|
291
|
-
help: "
|
|
346
|
+
help: "当前 DSH 中可路由的模型供应商。"
|
|
292
347
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
293
348
|
style: selectStyle,
|
|
294
349
|
value: draft.provider,
|
|
@@ -318,7 +373,7 @@ window.__ModuleLoader__.load({
|
|
|
318
373
|
style: row,
|
|
319
374
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
320
375
|
title: "模型",
|
|
321
|
-
help: "
|
|
376
|
+
help: "用作裁判的具体模型。"
|
|
322
377
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
323
378
|
style: selectStyle,
|
|
324
379
|
value: draft.model,
|
|
@@ -345,7 +400,7 @@ window.__ModuleLoader__.load({
|
|
|
345
400
|
style: row,
|
|
346
401
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
347
402
|
title: "推理强度",
|
|
348
|
-
help: "
|
|
403
|
+
help: "留空时使用所选模型的默认值。"
|
|
349
404
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
350
405
|
style: selectStyle,
|
|
351
406
|
value: draft.reasoningEffort ?? "",
|
|
@@ -363,101 +418,117 @@ window.__ModuleLoader__.load({
|
|
|
363
418
|
style: row,
|
|
364
419
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
365
420
|
title: "最大输出 Token",
|
|
366
|
-
help: "
|
|
421
|
+
help: "单次裁判请求允许生成的最大 Token 数。"
|
|
367
422
|
}), numeric("maxTokens", 1)]
|
|
368
423
|
})
|
|
369
424
|
]
|
|
370
425
|
}),
|
|
371
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
372
|
-
style:
|
|
426
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
427
|
+
style: group,
|
|
373
428
|
children: [
|
|
374
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
375
|
-
style: sectionTitle,
|
|
376
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "执行控制" })
|
|
377
|
-
}),
|
|
429
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupTitle, { children: "执行" }),
|
|
378
430
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
379
431
|
style: row,
|
|
380
432
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
381
433
|
title: "最大并发",
|
|
382
|
-
help: "所有 verifier
|
|
434
|
+
help: "所有 verifier 工具共享的请求并发上限。"
|
|
383
435
|
}), numeric("maxConcurrency", 1)]
|
|
384
436
|
}),
|
|
385
437
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
386
438
|
style: row,
|
|
387
439
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
388
440
|
title: "最多重试",
|
|
389
|
-
help: "
|
|
441
|
+
help: "限流、超时和短暂网络错误的重试次数。"
|
|
390
442
|
}), numeric("maxRetries", 0)]
|
|
391
443
|
}),
|
|
392
444
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
393
445
|
style: row,
|
|
394
446
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
395
|
-
title: "
|
|
396
|
-
help: "
|
|
447
|
+
title: "请求超时",
|
|
448
|
+
help: "单次模型请求的超时时间,单位为毫秒。"
|
|
397
449
|
}), numeric("timeoutMs", 1)]
|
|
398
450
|
}),
|
|
399
451
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
400
452
|
style: row,
|
|
401
453
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
402
454
|
title: "缓存条目上限",
|
|
403
|
-
help: "
|
|
455
|
+
help: "本地持久评分缓存保留的最大条目数。"
|
|
404
456
|
}), numeric("cacheMaxEntries", 1)]
|
|
405
457
|
})
|
|
406
458
|
]
|
|
407
459
|
}),
|
|
408
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
409
|
-
style:
|
|
460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
461
|
+
style: group,
|
|
410
462
|
children: [
|
|
411
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
412
|
-
style: sectionTitle,
|
|
413
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "费用估算(每百万 Token,USD)" })
|
|
414
|
-
}),
|
|
463
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupTitle, { children: "费用估算" }),
|
|
415
464
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
416
465
|
style: row,
|
|
417
466
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
418
467
|
title: "输入价格",
|
|
419
|
-
help: "
|
|
468
|
+
help: "每百万输入 Token 的美元价格,仅用于统计估算。"
|
|
420
469
|
}), numeric("estimatedInputUsdPerMillion", 0)]
|
|
421
470
|
}),
|
|
422
471
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
423
472
|
style: row,
|
|
424
473
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Label, {
|
|
425
474
|
title: "输出价格",
|
|
426
|
-
help: "
|
|
475
|
+
help: "每百万输出 Token 的美元价格,仅用于统计估算。"
|
|
427
476
|
}), numeric("estimatedOutputUsdPerMillion", 0)]
|
|
428
477
|
})
|
|
429
478
|
]
|
|
430
479
|
}),
|
|
431
480
|
loaded.failures.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
432
481
|
style: {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
482
|
+
padding: "10px 12px",
|
|
483
|
+
borderRadius: 8,
|
|
484
|
+
background: "var(--dsw-alias-state-warn-bg)",
|
|
485
|
+
color: "var(--dsw-alias-state-warn-label)",
|
|
486
|
+
fontSize: 12,
|
|
487
|
+
lineHeight: "18px"
|
|
436
488
|
},
|
|
437
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
489
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
490
|
+
style: {
|
|
491
|
+
fontWeight: 500,
|
|
492
|
+
marginBottom: 3
|
|
493
|
+
},
|
|
494
|
+
children: "部分模型目录读取失败"
|
|
495
|
+
}), loaded.failures.map((x) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: x }, x))]
|
|
438
496
|
}),
|
|
439
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
440
|
-
style: {
|
|
497
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
498
|
+
style: {
|
|
499
|
+
margin: 0,
|
|
500
|
+
fontSize: 12,
|
|
501
|
+
lineHeight: "18px",
|
|
502
|
+
color: "var(--dsw-alias-state-error-primary)"
|
|
503
|
+
},
|
|
441
504
|
children: error
|
|
442
505
|
}),
|
|
443
|
-
saved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
444
|
-
style: {
|
|
445
|
-
|
|
506
|
+
saved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
507
|
+
style: {
|
|
508
|
+
margin: 0,
|
|
509
|
+
fontSize: 12,
|
|
510
|
+
lineHeight: "18px",
|
|
511
|
+
color: "var(--dsw-alias-state-success-primary)"
|
|
512
|
+
},
|
|
513
|
+
children: "设置已保存。"
|
|
446
514
|
}),
|
|
447
515
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
448
516
|
style: {
|
|
449
517
|
display: "flex",
|
|
450
|
-
|
|
518
|
+
justifyContent: "flex-end",
|
|
519
|
+
gap: 8,
|
|
520
|
+
paddingTop: 4
|
|
451
521
|
},
|
|
452
522
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
453
|
-
disabled: busy || !loaded.writable,
|
|
454
|
-
onClick: () => void save(),
|
|
455
|
-
children: busy ? "保存中…" : "保存设置"
|
|
456
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
457
523
|
variant: "outline",
|
|
458
524
|
disabled: busy,
|
|
459
525
|
onClick: () => void load(),
|
|
460
526
|
children: "重新载入"
|
|
527
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
528
|
+
variant: "primary",
|
|
529
|
+
disabled: busy || !loaded.writable,
|
|
530
|
+
onClick: () => void save(),
|
|
531
|
+
children: busy ? "保存中…" : "保存设置"
|
|
461
532
|
})]
|
|
462
533
|
})
|
|
463
534
|
]
|
package/lib/types/client.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Button, IconDataOutline16, IconRefreshOutline16, Input
|
|
2
|
+
import { Button, IconDataOutline16, IconRefreshOutline16, Input } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
3
|
import { useEffect, useMemo, useState } from 'react';
|
|
4
4
|
const NS = 'llm-verifier';
|
|
5
|
-
const shell = { display: 'flex', flexDirection: 'column', gap:
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
5
|
+
const shell = { width: '100%', maxWidth: 720, display: 'flex', flexDirection: 'column', gap: 12, padding: '0 0 32px', color: 'var(--dsw-alias-label-primary)' };
|
|
6
|
+
const settingsHeading = { margin: 0, fontSize: 16, fontWeight: 500, lineHeight: '24px', color: 'var(--dsw-alias-label-primary)' };
|
|
7
|
+
const settingsIntro = { margin: 0, fontSize: 14, lineHeight: '22px', color: 'var(--dsw-alias-label-tertiary)' };
|
|
8
|
+
const group = { width: '100%', display: 'flex', flexDirection: 'column', borderTop: '1px solid var(--dsw-alias-border-l2)' };
|
|
9
|
+
const groupTitle = { margin: 0, padding: '18px 0 8px', fontSize: 14, fontWeight: 500, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' };
|
|
10
|
+
const row = { minHeight: 64, display: 'grid', gridTemplateColumns: 'minmax(180px, 1fr) minmax(230px, 288px)', gap: 24, alignItems: 'center', padding: '12px 0', borderBottom: '1px solid var(--dsw-alias-border-l2)' };
|
|
11
|
+
const selectStyle = { boxSizing: 'border-box', width: '100%', height: 36, padding: '0 34px 0 12px', borderRadius: 8, color: 'var(--dsw-alias-label-primary)', background: 'var(--dsw-alias-bg-input)', border: '1px solid var(--dsw-alias-border-l2)', font: 'inherit', fontSize: 14, lineHeight: '22px', outline: 'none' };
|
|
12
|
+
const toggleStyle = (enabled) => ({ position: 'relative', justifySelf: 'end', width: 40, height: 22, padding: 0, border: 0, borderRadius: 999, cursor: 'pointer', transition: 'background .15s ease', background: enabled ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-bg-input)' });
|
|
13
|
+
const toggleThumbStyle = (enabled) => ({ position: 'absolute', top: 3, left: enabled ? 21 : 3, width: 16, height: 16, borderRadius: '50%', background: 'var(--dsw-static-neutral-00, #fff)', boxShadow: '0 1px 3px rgba(0,0,0,.28)', transition: 'left .15s ease' });
|
|
10
14
|
const dashboardCard = { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.13))', background: 'color-mix(in srgb, var(--dsw-alias-bg-module, #171925) 88%, transparent)', borderRadius: 16, boxShadow: '0 12px 36px rgba(0,0,0,.12)' };
|
|
11
15
|
const muted = { color: 'var(--dsw-text-secondary)', fontSize: 12 };
|
|
12
16
|
const toolLabels = { verifier_compare: '两项对比', verifier_select: '多项优选', verifier_track: '进度跟踪', verifier_current_session: '会话验收' };
|
|
@@ -14,7 +18,8 @@ const toolColors = { verifier_compare: '#4f8cff', verifier_select: '#8b6df6', ve
|
|
|
14
18
|
function record(value) { return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {}; }
|
|
15
19
|
function values(view) { const v = record(view.value); return { enabled: v.enabled !== false, provider: String(v.provider ?? ''), model: String(v.model ?? ''), ...(typeof v.reasoningEffort === 'string' ? { reasoningEffort: v.reasoningEffort } : {}), maxTokens: Number(v.maxTokens ?? 32768), maxConcurrency: Number(v.maxConcurrency ?? 8), maxRetries: Number(v.maxRetries ?? 3), timeoutMs: Number(v.timeoutMs ?? 300000), cacheMaxEntries: Number(v.cacheMaxEntries ?? 10000), estimatedInputUsdPerMillion: Number(v.estimatedInputUsdPerMillion ?? 0), estimatedOutputUsdPerMillion: Number(v.estimatedOutputUsdPerMillion ?? 0) }; }
|
|
16
20
|
function message(error) { return error instanceof Error ? error.message : String(error); }
|
|
17
|
-
function Label({ title, help }) { return _jsxs("div", { children: [_jsx("div", { style: { fontWeight:
|
|
21
|
+
function Label({ title, help }) { return _jsxs("div", { style: { minWidth: 0 }, children: [_jsx("div", { style: { fontSize: 14, fontWeight: 400, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' }, children: title }), _jsx("div", { style: { fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-label-tertiary)', marginTop: 2 }, children: help })] }); }
|
|
22
|
+
function GroupTitle({ children }) { return _jsx("h3", { style: groupTitle, children: children }); }
|
|
18
23
|
function compact(value) { return new Intl.NumberFormat('zh-CN', { notation: value >= 10_000 ? 'compact' : 'standard', maximumFractionDigits: value >= 1_000 ? 1 : 0 }).format(value); }
|
|
19
24
|
function money(value) { return '$' + value.toLocaleString('en-US', { minimumFractionDigits: value < 0.01 ? 4 : 2, maximumFractionDigits: value < 0.01 ? 4 : 2 }); }
|
|
20
25
|
function duration(value) { if (value < 1000)
|
|
@@ -69,9 +74,9 @@ function VerifierSettings({ api }) {
|
|
|
69
74
|
setBusy(false);
|
|
70
75
|
} };
|
|
71
76
|
if (!loaded || !draft)
|
|
72
|
-
return _jsxs("div", { style: shell, children: [_jsx("h2", { children: "LLM Verifier" }), _jsx("p", { children: error ?? '正在读取 DSH 模型和设置…' }), error && _jsx(Button, { onClick: () => void load(), children: "\u91CD\u8BD5" })] });
|
|
73
|
-
const numeric = (key, min = 0) => _jsx(Input, { type: "number", min: min, value: String(draft[key]), onChange: e => patch(key, Number(e.target.value)) });
|
|
74
|
-
return _jsxs("div", { style: shell, children: [
|
|
77
|
+
return _jsxs("div", { style: shell, children: [_jsx("h2", { style: settingsHeading, children: "LLM Verifier" }), _jsx("p", { style: settingsIntro, children: error ?? '正在读取 DSH 模型和设置…' }), error && _jsx("div", { children: _jsx(Button, { variant: "outline", onClick: () => void load(), children: "\u91CD\u8BD5" }) })] });
|
|
78
|
+
const numeric = (key, min = 0) => _jsx(Input, { style: { width: '100%', height: 36, borderRadius: 8 }, type: "number", min: min, value: String(draft[key]), onChange: e => patch(key, Number(e.target.value)) });
|
|
79
|
+
return _jsxs("div", { style: shell, children: [_jsx("h2", { style: settingsHeading, children: "LLM Verifier" }), _jsx("p", { style: settingsIntro, children: "\u9009\u62E9\u5DF2\u5728 DSH\u300C\u6A21\u578B\u300D\u4E2D\u914D\u7F6E\u7684\u6A21\u578B\u4F5C\u4E3A\u72EC\u7ACB\u88C1\u5224\u3002\u4FEE\u6539\u540E\u70B9\u51FB\u9875\u9762\u5E95\u90E8\u7684\u4FDD\u5B58\u6309\u94AE\u751F\u6548\u3002" }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: "\u5DE5\u5177" }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u542F\u7528 Verifier \u5DE5\u5177", help: draft.enabled ? '允许 Agent 调用四个 verifier 工具并向裁判模型发起请求。' : '停用后,所有 verifier 工具都会立即返回错误。' }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.enabled, "aria-label": "\u542F\u7528 Verifier \u5DE5\u5177", onClick: () => patch('enabled', !draft.enabled), style: toggleStyle(draft.enabled), children: _jsx("span", { style: toggleThumbStyle(draft.enabled) }) })] }), !draft.enabled && _jsx("p", { style: { margin: '8px 0 0', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: "verifier_compare\u3001verifier_select\u3001verifier_track \u548C verifier_current_session \u5F53\u524D\u4E0D\u53EF\u7528\u3002" })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: "\u88C1\u5224\u6A21\u578B" }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u4F9B\u5E94\u5546", help: "\u5F53\u524D DSH \u4E2D\u53EF\u8DEF\u7531\u7684\u6A21\u578B\u4F9B\u5E94\u5546\u3002" }), _jsx("select", { style: selectStyle, value: draft.provider, onChange: e => { const provider = e.target.value; const first = loaded.groups.find(g => g.id === provider)?.models[0]; setDraft({ ...draft, provider, ...(first ? { model: first.id, reasoningEffort: first.reasoning?.defaultEffort } : {}) }); }, children: loaded.groups.map(g => _jsxs("option", { value: g.id, children: [g.name, " \u00B7 ", g.id] }, g.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u6A21\u578B", help: "\u7528\u4F5C\u88C1\u5224\u7684\u5177\u4F53\u6A21\u578B\u3002" }), _jsx("select", { style: selectStyle, value: draft.model, onChange: e => { const model = e.target.value; const found = models.find(m => m.id === model); setDraft({ ...draft, model, ...(found?.reasoning?.defaultEffort ? { reasoningEffort: found.reasoning.defaultEffort } : { reasoningEffort: undefined }) }); }, children: models.map(m => _jsxs("option", { value: m.id, children: [m.name, " \u00B7 ", m.id] }, m.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u63A8\u7406\u5F3A\u5EA6", help: "\u7559\u7A7A\u65F6\u4F7F\u7528\u6240\u9009\u6A21\u578B\u7684\u9ED8\u8BA4\u503C\u3002" }), _jsxs("select", { style: selectStyle, value: draft.reasoningEffort ?? '', onChange: e => patch('reasoningEffort', e.target.value || undefined), children: [_jsx("option", { value: "", children: "\u6A21\u578B\u9ED8\u8BA4" }), efforts.map(e => _jsx("option", { value: e.id, children: e.name }, e.id))] })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u6700\u5927\u8F93\u51FA Token", help: "\u5355\u6B21\u88C1\u5224\u8BF7\u6C42\u5141\u8BB8\u751F\u6210\u7684\u6700\u5927 Token \u6570\u3002" }), numeric('maxTokens', 1)] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: "\u6267\u884C" }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u6700\u5927\u5E76\u53D1", help: "\u6240\u6709 verifier \u5DE5\u5177\u5171\u4EAB\u7684\u8BF7\u6C42\u5E76\u53D1\u4E0A\u9650\u3002" }), numeric('maxConcurrency', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u6700\u591A\u91CD\u8BD5", help: "\u9650\u6D41\u3001\u8D85\u65F6\u548C\u77ED\u6682\u7F51\u7EDC\u9519\u8BEF\u7684\u91CD\u8BD5\u6B21\u6570\u3002" }), numeric('maxRetries', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u8BF7\u6C42\u8D85\u65F6", help: "\u5355\u6B21\u6A21\u578B\u8BF7\u6C42\u7684\u8D85\u65F6\u65F6\u95F4\uFF0C\u5355\u4F4D\u4E3A\u6BEB\u79D2\u3002" }), numeric('timeoutMs', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u7F13\u5B58\u6761\u76EE\u4E0A\u9650", help: "\u672C\u5730\u6301\u4E45\u8BC4\u5206\u7F13\u5B58\u4FDD\u7559\u7684\u6700\u5927\u6761\u76EE\u6570\u3002" }), numeric('cacheMaxEntries', 1)] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: "\u8D39\u7528\u4F30\u7B97" }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u8F93\u5165\u4EF7\u683C", help: "\u6BCF\u767E\u4E07\u8F93\u5165 Token \u7684\u7F8E\u5143\u4EF7\u683C\uFF0C\u4EC5\u7528\u4E8E\u7EDF\u8BA1\u4F30\u7B97\u3002" }), numeric('estimatedInputUsdPerMillion', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: "\u8F93\u51FA\u4EF7\u683C", help: "\u6BCF\u767E\u4E07\u8F93\u51FA Token \u7684\u7F8E\u5143\u4EF7\u683C\uFF0C\u4EC5\u7528\u4E8E\u7EDF\u8BA1\u4F30\u7B97\u3002" }), numeric('estimatedOutputUsdPerMillion', 0)] })] }), loaded.failures.length > 0 && _jsxs("div", { style: { padding: '10px 12px', borderRadius: 8, background: 'var(--dsw-alias-state-warn-bg)', color: 'var(--dsw-alias-state-warn-label)', fontSize: 12, lineHeight: '18px' }, children: [_jsx("div", { style: { fontWeight: 500, marginBottom: 3 }, children: "\u90E8\u5206\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" }), loaded.failures.map(x => _jsx("div", { children: x }, x))] }), error && _jsx("p", { style: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-error-primary)' }, children: error }), saved && _jsx("p", { style: { margin: 0, fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-success-primary)' }, children: "\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002" }), _jsxs("div", { style: { display: 'flex', justifyContent: 'flex-end', gap: 8, paddingTop: 4 }, children: [_jsx(Button, { variant: "outline", disabled: busy, onClick: () => void load(), children: "\u91CD\u65B0\u8F7D\u5165" }), _jsx(Button, { variant: "primary", disabled: busy || !loaded.writable, onClick: () => void save(), children: busy ? '保存中…' : '保存设置' })] })] });
|
|
75
80
|
}
|
|
76
81
|
function Metric({ label, value, note, accent }) {
|
|
77
82
|
return _jsxs("div", { style: { ...dashboardCard, padding: '16px 18px', minWidth: 0 }, children: [_jsx("div", { style: muted, children: label }), _jsx("div", { style: { fontSize: 25, fontWeight: 750, lineHeight: 1.2, margin: '7px 0 5px', color: accent }, children: value }), _jsx("div", { style: { ...muted, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: note })] });
|
package/package.json
CHANGED
package/src/client.tsx
CHANGED
|
@@ -3,7 +3,7 @@ import type { ModelProviderGroup, SettingsNamespaceView } from '@deepseek-ai/dsh
|
|
|
3
3
|
import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
|
|
4
4
|
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
5
5
|
import type {} from '@deepseek-ai/dsh-client-ui-slots'
|
|
6
|
-
import { Button, IconDataOutline16, IconRefreshOutline16, Input
|
|
6
|
+
import { Button, IconDataOutline16, IconRefreshOutline16, Input } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
7
7
|
import { useEffect, useMemo, useState } from 'react'
|
|
8
8
|
|
|
9
9
|
const NS = 'llm-verifier'
|
|
@@ -18,11 +18,15 @@ interface Totals extends RunStats { invocations: number; successes: number; fail
|
|
|
18
18
|
interface StatisticsOverview { generatedAt: number; fromMs: number; toMs: number; sessionId?: string; totals: Totals; daily: DailyStatistics[]; tools: ToolStatistics[]; models: ModelStatistics[]; recent: InvocationRecord[] }
|
|
19
19
|
interface StatisticsPageProps { sessionId: string; rpc: { call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<{ ok: boolean; value?: unknown; error?: { message: string } }> } }
|
|
20
20
|
|
|
21
|
-
const shell: React.CSSProperties = { display: 'flex', flexDirection: 'column', gap:
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
21
|
+
const shell: React.CSSProperties = { width: '100%', maxWidth: 720, display: 'flex', flexDirection: 'column', gap: 12, padding: '0 0 32px', color: 'var(--dsw-alias-label-primary)' }
|
|
22
|
+
const settingsHeading: React.CSSProperties = { margin: 0, fontSize: 16, fontWeight: 500, lineHeight: '24px', color: 'var(--dsw-alias-label-primary)' }
|
|
23
|
+
const settingsIntro: React.CSSProperties = { margin: 0, fontSize: 14, lineHeight: '22px', color: 'var(--dsw-alias-label-tertiary)' }
|
|
24
|
+
const group: React.CSSProperties = { width: '100%', display: 'flex', flexDirection: 'column', borderTop: '1px solid var(--dsw-alias-border-l2)' }
|
|
25
|
+
const groupTitle: React.CSSProperties = { margin: 0, padding: '18px 0 8px', fontSize: 14, fontWeight: 500, lineHeight: '22px', color: 'var(--dsw-alias-label-primary)' }
|
|
26
|
+
const row: React.CSSProperties = { minHeight: 64, display: 'grid', gridTemplateColumns: 'minmax(180px, 1fr) minmax(230px, 288px)', gap: 24, alignItems: 'center', padding: '12px 0', borderBottom: '1px solid var(--dsw-alias-border-l2)' }
|
|
27
|
+
const selectStyle: React.CSSProperties = { boxSizing: 'border-box', width: '100%', height: 36, padding: '0 34px 0 12px', borderRadius: 8, color: 'var(--dsw-alias-label-primary)', background: 'var(--dsw-alias-bg-input)', border: '1px solid var(--dsw-alias-border-l2)', font: 'inherit', fontSize: 14, lineHeight: '22px', outline: 'none' }
|
|
28
|
+
const toggleStyle = (enabled: boolean): React.CSSProperties => ({ position: 'relative', justifySelf: 'end', width: 40, height: 22, padding: 0, border: 0, borderRadius: 999, cursor: 'pointer', transition: 'background .15s ease', background: enabled ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-bg-input)' })
|
|
29
|
+
const toggleThumbStyle = (enabled: boolean): React.CSSProperties => ({ position: 'absolute', top: 3, left: enabled ? 21 : 3, width: 16, height: 16, borderRadius: '50%', background: 'var(--dsw-static-neutral-00, #fff)', boxShadow: '0 1px 3px rgba(0,0,0,.28)', transition: 'left .15s ease' })
|
|
26
30
|
const dashboardCard: React.CSSProperties = { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.13))', background: 'color-mix(in srgb, var(--dsw-alias-bg-module, #171925) 88%, transparent)', borderRadius: 16, boxShadow: '0 12px 36px rgba(0,0,0,.12)' }
|
|
27
31
|
const muted: React.CSSProperties = { color: 'var(--dsw-text-secondary)', fontSize: 12 }
|
|
28
32
|
const toolLabels: Record<string, string> = { verifier_compare: '两项对比', verifier_select: '多项优选', verifier_track: '进度跟踪', verifier_current_session: '会话验收' }
|
|
@@ -31,7 +35,8 @@ const toolColors: Record<string, string> = { verifier_compare: '#4f8cff', verifi
|
|
|
31
35
|
function record(value: unknown): Record<string, unknown> { return typeof value === 'object' && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : {} }
|
|
32
36
|
function values(view: SettingsNamespaceView): Values { const v=record(view.value); return { enabled:v.enabled!==false,provider:String(v.provider??''),model:String(v.model??''),...(typeof v.reasoningEffort==='string'?{reasoningEffort:v.reasoningEffort}:{}),maxTokens:Number(v.maxTokens??32768),maxConcurrency:Number(v.maxConcurrency??8),maxRetries:Number(v.maxRetries??3),timeoutMs:Number(v.timeoutMs??300000),cacheMaxEntries:Number(v.cacheMaxEntries??10000),estimatedInputUsdPerMillion:Number(v.estimatedInputUsdPerMillion??0),estimatedOutputUsdPerMillion:Number(v.estimatedOutputUsdPerMillion??0) } }
|
|
33
37
|
function message(error: unknown): string { return error instanceof Error ? error.message : String(error) }
|
|
34
|
-
function Label({title,help}:{title:string;help:string}) { return <div><div style={{fontWeight:
|
|
38
|
+
function Label({title,help}:{title:string;help:string}) { return <div style={{minWidth:0}}><div style={{fontSize:14,fontWeight:400,lineHeight:'22px',color:'var(--dsw-alias-label-primary)'}}>{title}</div><div style={{fontSize:12,lineHeight:'18px',color:'var(--dsw-alias-label-tertiary)',marginTop:2}}>{help}</div></div> }
|
|
39
|
+
function GroupTitle({children}:{children:React.ReactNode}) { return <h3 style={groupTitle}>{children}</h3> }
|
|
35
40
|
function compact(value: number): string { return new Intl.NumberFormat('zh-CN', { notation: value >= 10_000 ? 'compact' : 'standard', maximumFractionDigits: value >= 1_000 ? 1 : 0 }).format(value) }
|
|
36
41
|
function money(value: number): string { return '$' + value.toLocaleString('en-US', { minimumFractionDigits: value < 0.01 ? 4 : 2, maximumFractionDigits: value < 0.01 ? 4 : 2 }) }
|
|
37
42
|
function duration(value: number): string { if (value < 1000) return Math.round(value) + ' ms'; if (value < 60_000) return (value / 1000).toFixed(1) + ' s'; return (value / 60_000).toFixed(1) + ' min' }
|
|
@@ -47,25 +52,39 @@ function VerifierSettings({ api }:{api:any}) {
|
|
|
47
52
|
const selected=models.find(m=>m.id===draft?.model); const efforts=selected?.reasoning?.efforts??[]
|
|
48
53
|
const patch=<K extends keyof Values>(key:K,value:Values[K])=>setDraft(v=>v?{...v,[key]:value}:v)
|
|
49
54
|
const save=async()=>{if(!loaded||!draft)return;setBusy(true);setSaved(false);setError(null);try{const section={...record(loaded.settings.user),...draft};if(!draft.reasoningEffort)delete section.reasoningEffort;const res=await api.settings.update({ns:NS,patch:section,expectedRevision:loaded.settings.revision});if(!res.result.ok)throw new Error(res.result.error.message);setLoaded(v=>v?{...v,settings:res.result.value}:v);setDraft(values(res.result.value));setSaved(true)}catch(e){setError(message(e))}finally{setBusy(false)}}
|
|
50
|
-
if(!loaded||!draft)return <div style={shell}><h2>LLM Verifier</h2><p>{error??'正在读取 DSH 模型和设置…'}</p>{error&&<Button onClick={()=>void load()}>重试</Button>}</div>
|
|
51
|
-
const numeric=(key:keyof Values,min=0)=><Input type="number" min={min} value={String(draft[key])} onChange={e=>patch(key,Number(e.target.value) as never)} />
|
|
55
|
+
if(!loaded||!draft)return <div style={shell}><h2 style={settingsHeading}>LLM Verifier</h2><p style={settingsIntro}>{error??'正在读取 DSH 模型和设置…'}</p>{error&&<div><Button variant="outline" onClick={()=>void load()}>重试</Button></div>}</div>
|
|
56
|
+
const numeric=(key:keyof Values,min=0)=><Input style={{width:'100%',height:36,borderRadius:8}} type="number" min={min} value={String(draft[key])} onChange={e=>patch(key,Number(e.target.value) as never)} />
|
|
52
57
|
return <div style={shell}>
|
|
53
|
-
<
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<div style={row}><Label title="
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<
|
|
58
|
+
<h2 style={settingsHeading}>LLM Verifier</h2>
|
|
59
|
+
<p style={settingsIntro}>选择已在 DSH「模型」中配置的模型作为独立裁判。修改后点击页面底部的保存按钮生效。</p>
|
|
60
|
+
|
|
61
|
+
<section style={group}><GroupTitle>工具</GroupTitle>
|
|
62
|
+
<div style={row}><Label title="启用 Verifier 工具" help={draft.enabled?'允许 Agent 调用四个 verifier 工具并向裁判模型发起请求。':'停用后,所有 verifier 工具都会立即返回错误。'}/><button type="button" role="switch" aria-checked={draft.enabled} aria-label="启用 Verifier 工具" onClick={()=>patch('enabled',!draft.enabled)} style={toggleStyle(draft.enabled)}><span style={toggleThumbStyle(draft.enabled)}/></button></div>
|
|
63
|
+
{!draft.enabled&&<p style={{margin:'8px 0 0',fontSize:12,lineHeight:'18px',color:'var(--dsw-alias-state-warn-label)'}}>verifier_compare、verifier_select、verifier_track 和 verifier_current_session 当前不可用。</p>}
|
|
64
|
+
</section>
|
|
65
|
+
|
|
66
|
+
<section style={group}><GroupTitle>裁判模型</GroupTitle>
|
|
67
|
+
<div style={row}><Label title="供应商" help="当前 DSH 中可路由的模型供应商。"/><select style={selectStyle} value={draft.provider} onChange={e=>{const provider=e.target.value;const first=loaded.groups.find(g=>g.id===provider)?.models[0];setDraft({...draft,provider,...(first?{model:first.id,reasoningEffort:first.reasoning?.defaultEffort}:{})})}}>{loaded.groups.map(g=><option key={g.id} value={g.id}>{g.name} · {g.id}</option>)}</select></div>
|
|
68
|
+
<div style={row}><Label title="模型" help="用作裁判的具体模型。"/><select style={selectStyle} value={draft.model} onChange={e=>{const model=e.target.value;const found=models.find(m=>m.id===model);setDraft({...draft,model,...(found?.reasoning?.defaultEffort?{reasoningEffort:found.reasoning.defaultEffort}:{reasoningEffort:undefined})})}}>{models.map(m=><option key={m.id} value={m.id}>{m.name} · {m.id}</option>)}</select></div>
|
|
69
|
+
<div style={row}><Label title="推理强度" help="留空时使用所选模型的默认值。"/><select style={selectStyle} value={draft.reasoningEffort??''} onChange={e=>patch('reasoningEffort',e.target.value||undefined)}><option value="">模型默认</option>{efforts.map(e=><option key={e.id} value={e.id}>{e.name}</option>)}</select></div>
|
|
70
|
+
<div style={row}><Label title="最大输出 Token" help="单次裁判请求允许生成的最大 Token 数。"/>{numeric('maxTokens',1)}</div>
|
|
71
|
+
</section>
|
|
72
|
+
|
|
73
|
+
<section style={group}><GroupTitle>执行</GroupTitle>
|
|
74
|
+
<div style={row}><Label title="最大并发" help="所有 verifier 工具共享的请求并发上限。"/>{numeric('maxConcurrency',1)}</div>
|
|
75
|
+
<div style={row}><Label title="最多重试" help="限流、超时和短暂网络错误的重试次数。"/>{numeric('maxRetries',0)}</div>
|
|
76
|
+
<div style={row}><Label title="请求超时" help="单次模型请求的超时时间,单位为毫秒。"/>{numeric('timeoutMs',1)}</div>
|
|
77
|
+
<div style={row}><Label title="缓存条目上限" help="本地持久评分缓存保留的最大条目数。"/>{numeric('cacheMaxEntries',1)}</div>
|
|
78
|
+
</section>
|
|
79
|
+
|
|
80
|
+
<section style={group}><GroupTitle>费用估算</GroupTitle>
|
|
81
|
+
<div style={row}><Label title="输入价格" help="每百万输入 Token 的美元价格,仅用于统计估算。"/>{numeric('estimatedInputUsdPerMillion',0)}</div>
|
|
82
|
+
<div style={row}><Label title="输出价格" help="每百万输出 Token 的美元价格,仅用于统计估算。"/>{numeric('estimatedOutputUsdPerMillion',0)}</div>
|
|
83
|
+
</section>
|
|
84
|
+
|
|
85
|
+
{loaded.failures.length>0&&<div style={{padding:'10px 12px',borderRadius:8,background:'var(--dsw-alias-state-warn-bg)',color:'var(--dsw-alias-state-warn-label)',fontSize:12,lineHeight:'18px'}}><div style={{fontWeight:500,marginBottom:3}}>部分模型目录读取失败</div>{loaded.failures.map(x=><div key={x}>{x}</div>)}</div>}
|
|
86
|
+
{error&&<p style={{margin:0,fontSize:12,lineHeight:'18px',color:'var(--dsw-alias-state-error-primary)'}}>{error}</p>}{saved&&<p style={{margin:0,fontSize:12,lineHeight:'18px',color:'var(--dsw-alias-state-success-primary)'}}>设置已保存。</p>}
|
|
87
|
+
<div style={{display:'flex',justifyContent:'flex-end',gap:8,paddingTop:4}}><Button variant="outline" disabled={busy} onClick={()=>void load()}>重新载入</Button><Button variant="primary" disabled={busy||!loaded.writable} onClick={()=>void save()}>{busy?'保存中…':'保存设置'}</Button></div>
|
|
69
88
|
</div>
|
|
70
89
|
}
|
|
71
90
|
|