dsh-advisor-group 0.0.1 → 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/README.md +128 -98
- package/README.zh.md +131 -103
- package/lib/client.js +307 -23
- package/lib/index.d.mts +21 -1
- package/lib/index.mjs +565 -87
- package/package.json +43 -30
package/lib/client.js
CHANGED
|
@@ -518,6 +518,10 @@ const waitingStyle = {
|
|
|
518
518
|
color: "#fbbf24",
|
|
519
519
|
marginTop: 6
|
|
520
520
|
};
|
|
521
|
+
const noticeStyle = {
|
|
522
|
+
color: "#fda4af",
|
|
523
|
+
marginTop: 6
|
|
524
|
+
};
|
|
521
525
|
/** Internal announcements that must never reach the user (the tool list). */
|
|
522
526
|
const INTERNAL_TOOL_STEP_NAMES = /* @__PURE__ */ new Set(["⚙️ tools", "⚙ tools"]);
|
|
523
527
|
/** True when the tool result represents a failure — the wrapper prefix, or a
|
|
@@ -784,6 +788,8 @@ function AdvisorSteps({ message }) {
|
|
|
784
788
|
}, (0, react.createElement)("div", { style: thinkingTagStyle }, `${group} 📋 行动·${toolViews.length + 1}`), (0, react.createElement)("div", { style: descriptionBodyStyle }, liveAction)));
|
|
785
789
|
return (0, react.createElement)("div", null, children);
|
|
786
790
|
}
|
|
791
|
+
/** Auto-hide delay for transient card notices (request failures, resync). */
|
|
792
|
+
const NOTICE_TTL_MS = 6e3;
|
|
787
793
|
function AdvisorGroupNodeView(props) {
|
|
788
794
|
const data = props.node.data;
|
|
789
795
|
const sessionId = data.sessionId;
|
|
@@ -791,10 +797,36 @@ function AdvisorGroupNodeView(props) {
|
|
|
791
797
|
const [contextCollapsed, setContextCollapsed] = (0, react.useState)(true);
|
|
792
798
|
const lastEventIdRef = (0, react.useRef)(0);
|
|
793
799
|
const lastBootIdRef = (0, react.useRef)("");
|
|
800
|
+
const [transientNotice, setTransientNotice] = (0, react.useState)(null);
|
|
801
|
+
const noticeTimerRef = (0, react.useRef)(null);
|
|
802
|
+
const showTransientNotice = (text, kind, ttlMs) => {
|
|
803
|
+
if (noticeTimerRef.current !== null) {
|
|
804
|
+
clearTimeout(noticeTimerRef.current);
|
|
805
|
+
noticeTimerRef.current = null;
|
|
806
|
+
}
|
|
807
|
+
setTransientNotice({
|
|
808
|
+
text,
|
|
809
|
+
kind
|
|
810
|
+
});
|
|
811
|
+
if (ttlMs !== void 0) noticeTimerRef.current = setTimeout(() => {
|
|
812
|
+
noticeTimerRef.current = null;
|
|
813
|
+
setTransientNotice(null);
|
|
814
|
+
}, ttlMs);
|
|
815
|
+
};
|
|
816
|
+
const clearStreamNotice = () => {
|
|
817
|
+
setTransientNotice((prev) => prev && prev.kind === "stream" ? null : prev);
|
|
818
|
+
};
|
|
794
819
|
(0, react.useEffect)(() => {
|
|
795
820
|
if (!sessionId) return;
|
|
796
821
|
const es = new EventSource(`/advisor-group/stream?sessionId=${encodeURIComponent(sessionId)}&lastEventId=${lastEventIdRef.current}&bootId=${encodeURIComponent(lastBootIdRef.current)}&token=${encodeURIComponent(advisorGroupToken())}`);
|
|
822
|
+
es.onopen = () => {
|
|
823
|
+
clearStreamNotice();
|
|
824
|
+
};
|
|
825
|
+
es.onerror = () => {
|
|
826
|
+
showTransientNotice("连接中断,正在重连…", "stream");
|
|
827
|
+
};
|
|
797
828
|
es.onmessage = (event) => {
|
|
829
|
+
clearStreamNotice();
|
|
798
830
|
try {
|
|
799
831
|
const delta = JSON.parse(event.data);
|
|
800
832
|
const bootId = delta.bootId ?? "";
|
|
@@ -848,11 +880,22 @@ function AdvisorGroupNodeView(props) {
|
|
|
848
880
|
});
|
|
849
881
|
} catch {}
|
|
850
882
|
};
|
|
851
|
-
es.addEventListener("resync", () => {
|
|
883
|
+
es.addEventListener("resync", (event) => {
|
|
852
884
|
lastEventIdRef.current = 0;
|
|
853
885
|
setLive({});
|
|
886
|
+
let reason = "";
|
|
887
|
+
try {
|
|
888
|
+
reason = JSON.parse(event.data).reason ?? "";
|
|
889
|
+
} catch {}
|
|
890
|
+
showTransientNotice(reason === "restart" ? "服务端已重启,正在补齐对话内容…" : reason === "gap" ? "正在补齐断开期间的内容…" : "正在补齐对话内容…", "stream", NOTICE_TTL_MS);
|
|
854
891
|
});
|
|
855
|
-
return () =>
|
|
892
|
+
return () => {
|
|
893
|
+
es.close();
|
|
894
|
+
if (noticeTimerRef.current !== null) {
|
|
895
|
+
clearTimeout(noticeTimerRef.current);
|
|
896
|
+
noticeTimerRef.current = null;
|
|
897
|
+
}
|
|
898
|
+
};
|
|
856
899
|
}, [sessionId]);
|
|
857
900
|
const mergedMessages = data.messages.map((message) => {
|
|
858
901
|
if (message.role !== "advisor") return message;
|
|
@@ -899,14 +942,21 @@ function AdvisorGroupNodeView(props) {
|
|
|
899
942
|
}, data.status === "running" ? (0, react.createElement)("button", {
|
|
900
943
|
type: "button",
|
|
901
944
|
onClick: () => {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
945
|
+
(async () => {
|
|
946
|
+
try {
|
|
947
|
+
const body = await (await fetch("/advisor-group/stop", {
|
|
948
|
+
method: "POST",
|
|
949
|
+
headers: {
|
|
950
|
+
"content-type": "application/json",
|
|
951
|
+
...authHeaders()
|
|
952
|
+
},
|
|
953
|
+
body: JSON.stringify({ sessionId })
|
|
954
|
+
})).json();
|
|
955
|
+
if (body.ok === false) showTransientNotice(body.error ?? "请求未被服务端接受,请稍后重试。", "action", NOTICE_TTL_MS);
|
|
956
|
+
} catch {
|
|
957
|
+
showTransientNotice("网络异常,请稍后重试。", "action", NOTICE_TTL_MS);
|
|
958
|
+
}
|
|
959
|
+
})();
|
|
910
960
|
},
|
|
911
961
|
style: {
|
|
912
962
|
cursor: "pointer",
|
|
@@ -920,14 +970,21 @@ function AdvisorGroupNodeView(props) {
|
|
|
920
970
|
}, "⏹ 停止") : data.status === "cancelled" ? (0, react.createElement)("button", {
|
|
921
971
|
type: "button",
|
|
922
972
|
onClick: () => {
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
973
|
+
(async () => {
|
|
974
|
+
try {
|
|
975
|
+
const body = await (await fetch("/advisor-group/resume", {
|
|
976
|
+
method: "POST",
|
|
977
|
+
headers: {
|
|
978
|
+
"content-type": "application/json",
|
|
979
|
+
...authHeaders()
|
|
980
|
+
},
|
|
981
|
+
body: JSON.stringify({ sessionId })
|
|
982
|
+
})).json();
|
|
983
|
+
if (body.ok === false) showTransientNotice(body.error ?? "请求未被服务端接受,请稍后重试。", "action", NOTICE_TTL_MS);
|
|
984
|
+
} catch {
|
|
985
|
+
showTransientNotice("网络异常,请稍后重试。", "action", NOTICE_TTL_MS);
|
|
986
|
+
}
|
|
987
|
+
})();
|
|
931
988
|
},
|
|
932
989
|
style: {
|
|
933
990
|
cursor: "pointer",
|
|
@@ -953,7 +1010,32 @@ function AdvisorGroupNodeView(props) {
|
|
|
953
1010
|
color: "#86efac",
|
|
954
1011
|
fontWeight: 700,
|
|
955
1012
|
marginBottom: 4
|
|
956
|
-
} }, "📌 综合结论"), (0, react.createElement)("div", null, renderMarkdown(data.summary.conclusion))) : null, data.status === "
|
|
1013
|
+
} }, "📌 综合结论"), (0, react.createElement)("div", null, renderMarkdown(data.summary.conclusion))) : null, data.status === "completed" && (data.summary?.riskNotes ?? []).length > 0 ? (0, react.createElement)("div", { style: {
|
|
1014
|
+
borderTop: "1px dashed #2f9e44",
|
|
1015
|
+
marginTop: 8,
|
|
1016
|
+
paddingTop: 8
|
|
1017
|
+
} }, (data.summary?.riskNotes ?? []).map((note, index) => (0, react.createElement)("div", {
|
|
1018
|
+
key: index,
|
|
1019
|
+
style: {
|
|
1020
|
+
color: "#fbbf24",
|
|
1021
|
+
fontSize: 12,
|
|
1022
|
+
marginTop: 2
|
|
1023
|
+
}
|
|
1024
|
+
}, note))) : null, data.status === "cancelled" ? (0, react.createElement)("div", { style: {
|
|
1025
|
+
borderTop: "1px dashed #2f9e44",
|
|
1026
|
+
marginTop: 8,
|
|
1027
|
+
paddingTop: 8
|
|
1028
|
+
} }, (0, react.createElement)("div", { style: {
|
|
1029
|
+
color: "#fde68a",
|
|
1030
|
+
marginBottom: 4
|
|
1031
|
+
} }, "本次讨论已停止;点 ▶ 继续聊天 可从断点续跑。"), (data.summary?.riskNotes ?? []).map((note, index) => (0, react.createElement)("div", {
|
|
1032
|
+
key: index,
|
|
1033
|
+
style: {
|
|
1034
|
+
color: "#fbbf24",
|
|
1035
|
+
fontSize: 12,
|
|
1036
|
+
marginTop: 2
|
|
1037
|
+
}
|
|
1038
|
+
}, note))) : null, data.status === "running" ? (0, react.createElement)("div", { style: waitingStyle }, "▊ AWAITING RESPONSES…") : null, transientNotice ? (0, react.createElement)("div", { style: noticeStyle }, transientNotice.text) : null);
|
|
957
1039
|
}
|
|
958
1040
|
const settingsRootStyle = {
|
|
959
1041
|
fontFamily: "'Inter', 'Segoe UI', system-ui, sans-serif",
|
|
@@ -1120,6 +1202,21 @@ const AVATAR_OPTIONS = [
|
|
|
1120
1202
|
"🚀",
|
|
1121
1203
|
"🛡️"
|
|
1122
1204
|
];
|
|
1205
|
+
function defaultJevConfig() {
|
|
1206
|
+
return {
|
|
1207
|
+
enabled: false,
|
|
1208
|
+
provider: "typesafe",
|
|
1209
|
+
model: "jev-latest",
|
|
1210
|
+
baseURL: "",
|
|
1211
|
+
timeoutMs: 1e4,
|
|
1212
|
+
confidenceThreshold: .6,
|
|
1213
|
+
useEnglishState: false
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
const JEV_DEFAULT_ENDPOINTS = {
|
|
1217
|
+
typesafe: "https://api.typesafe.ai/v1/systemone",
|
|
1218
|
+
openrouter: "https://openrouter.ai/api/alpha/decisions"
|
|
1219
|
+
};
|
|
1123
1220
|
function AdvisorGroupSettingsTab() {
|
|
1124
1221
|
const [config, setConfig] = (0, react.useState)(null);
|
|
1125
1222
|
const [providers, setProviders] = (0, react.useState)([]);
|
|
@@ -1268,6 +1365,10 @@ function AdvisorGroupSettingsTab() {
|
|
|
1268
1365
|
try {
|
|
1269
1366
|
const configPayload = {
|
|
1270
1367
|
...config,
|
|
1368
|
+
trigger: {
|
|
1369
|
+
...config.trigger,
|
|
1370
|
+
jev: config.trigger.jev ? (({ apiKeyMeta: _meta, ...rest }) => rest)(config.trigger.jev) : defaultJevConfig()
|
|
1371
|
+
},
|
|
1271
1372
|
advisors: config.advisors.map(({ apiKeyMetaByProvider: _meta, ...rest }) => rest)
|
|
1272
1373
|
};
|
|
1273
1374
|
const data = await (await fetch("/advisor-group/config", {
|
|
@@ -1414,7 +1515,188 @@ function AdvisorGroupSettingsTab() {
|
|
|
1414
1515
|
}
|
|
1415
1516
|
}),
|
|
1416
1517
|
style: settingsInputStyle
|
|
1417
|
-
}))), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("div", { style: {
|
|
1518
|
+
}))), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("strong", null, "Jev 前置分类"), (0, react.createElement)("div", { style: {
|
|
1519
|
+
fontSize: 12,
|
|
1520
|
+
color: "var(--dsh-color-muted, #8b90a0)",
|
|
1521
|
+
margin: "4px 0 8px"
|
|
1522
|
+
} }, "启用后由 Jev 判断是否需要顾问群;未配置或调用失败时自动使用本地分类器。"), (0, react.createElement)("div", { style: {
|
|
1523
|
+
display: "flex",
|
|
1524
|
+
alignItems: "center",
|
|
1525
|
+
gap: 8,
|
|
1526
|
+
marginBottom: 8
|
|
1527
|
+
} }, (0, react.createElement)("input", {
|
|
1528
|
+
type: "checkbox",
|
|
1529
|
+
checked: config.trigger.jev?.enabled ?? false,
|
|
1530
|
+
onChange: (e) => setConfig({
|
|
1531
|
+
...config,
|
|
1532
|
+
trigger: {
|
|
1533
|
+
...config.trigger,
|
|
1534
|
+
jev: {
|
|
1535
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1536
|
+
enabled: e.target.checked
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
})
|
|
1540
|
+
}), label("启用 Jev")), (0, react.createElement)("div", { style: {
|
|
1541
|
+
display: "grid",
|
|
1542
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
|
|
1543
|
+
gap: 8
|
|
1544
|
+
} }, (0, react.createElement)("div", null, label("Jev 渠道"), (0, react.createElement)("select", {
|
|
1545
|
+
value: config.trigger.jev?.provider ?? "typesafe",
|
|
1546
|
+
onChange: (e) => {
|
|
1547
|
+
const current = config.trigger.jev ?? defaultJevConfig();
|
|
1548
|
+
const previousProvider = current.provider ?? "typesafe";
|
|
1549
|
+
const currentURL = current.baseURL ?? "";
|
|
1550
|
+
const usesDefault = !currentURL || currentURL === JEV_DEFAULT_ENDPOINTS[previousProvider];
|
|
1551
|
+
setConfig({
|
|
1552
|
+
...config,
|
|
1553
|
+
trigger: {
|
|
1554
|
+
...config.trigger,
|
|
1555
|
+
jev: {
|
|
1556
|
+
...current,
|
|
1557
|
+
provider: e.target.value,
|
|
1558
|
+
...usesDefault ? { baseURL: JEV_DEFAULT_ENDPOINTS[e.target.value] } : {}
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
},
|
|
1563
|
+
style: settingsInputStyle
|
|
1564
|
+
}, (0, react.createElement)("option", { value: "typesafe" }, "TypeSafe 官方 API"), (0, react.createElement)("option", { value: "openrouter" }, "OpenRouter Decisions API"))), (0, react.createElement)("div", null, label("Jev 模型"), (0, react.createElement)("input", {
|
|
1565
|
+
value: config.trigger.jev?.model ?? "jev-latest",
|
|
1566
|
+
onChange: (e) => setConfig({
|
|
1567
|
+
...config,
|
|
1568
|
+
trigger: {
|
|
1569
|
+
...config.trigger,
|
|
1570
|
+
jev: {
|
|
1571
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1572
|
+
model: e.target.value
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}),
|
|
1576
|
+
style: settingsInputStyle
|
|
1577
|
+
})), (0, react.createElement)("div", null, label("判断阈值(0-1)"), (0, react.createElement)("input", {
|
|
1578
|
+
type: "number",
|
|
1579
|
+
min: 0,
|
|
1580
|
+
max: 1,
|
|
1581
|
+
step: .05,
|
|
1582
|
+
value: String(config.trigger.jev?.confidenceThreshold ?? .6),
|
|
1583
|
+
onChange: (e) => setConfig({
|
|
1584
|
+
...config,
|
|
1585
|
+
trigger: {
|
|
1586
|
+
...config.trigger,
|
|
1587
|
+
jev: {
|
|
1588
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1589
|
+
confidenceThreshold: Number(e.target.value)
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
}),
|
|
1593
|
+
style: settingsInputStyle
|
|
1594
|
+
})), (0, react.createElement)("div", null, label("高风险阈值(0-1,空=跟随判断阈值)"), (0, react.createElement)("input", {
|
|
1595
|
+
type: "number",
|
|
1596
|
+
min: 0,
|
|
1597
|
+
max: 1,
|
|
1598
|
+
step: .05,
|
|
1599
|
+
placeholder: String(config.trigger.jev?.confidenceThreshold ?? .6),
|
|
1600
|
+
value: config.trigger.jev?.highRiskThreshold !== void 0 ? String(config.trigger.jev.highRiskThreshold) : "",
|
|
1601
|
+
onChange: (e) => setConfig({
|
|
1602
|
+
...config,
|
|
1603
|
+
trigger: {
|
|
1604
|
+
...config.trigger,
|
|
1605
|
+
jev: {
|
|
1606
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1607
|
+
highRiskThreshold: e.target.value === "" ? void 0 : Number(e.target.value)
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
}),
|
|
1611
|
+
style: settingsInputStyle
|
|
1612
|
+
})), (0, react.createElement)("div", null, label("请求超时(毫秒)"), (0, react.createElement)("input", {
|
|
1613
|
+
type: "number",
|
|
1614
|
+
min: 1e3,
|
|
1615
|
+
max: 6e4,
|
|
1616
|
+
step: 1e3,
|
|
1617
|
+
value: String(config.trigger.jev?.timeoutMs ?? 1e4),
|
|
1618
|
+
onChange: (e) => setConfig({
|
|
1619
|
+
...config,
|
|
1620
|
+
trigger: {
|
|
1621
|
+
...config.trigger,
|
|
1622
|
+
jev: {
|
|
1623
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1624
|
+
timeoutMs: Math.max(1e3, Number(e.target.value))
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}),
|
|
1628
|
+
style: settingsInputStyle
|
|
1629
|
+
}))), (0, react.createElement)("div", { style: { marginTop: 8 } }, label("API 地址(留空使用渠道默认地址)"), (0, react.createElement)("input", {
|
|
1630
|
+
value: config.trigger.jev?.baseURL || JEV_DEFAULT_ENDPOINTS[config.trigger.jev?.provider ?? "typesafe"],
|
|
1631
|
+
placeholder: JEV_DEFAULT_ENDPOINTS[config.trigger.jev?.provider ?? "typesafe"],
|
|
1632
|
+
onChange: (e) => setConfig({
|
|
1633
|
+
...config,
|
|
1634
|
+
trigger: {
|
|
1635
|
+
...config.trigger,
|
|
1636
|
+
jev: {
|
|
1637
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1638
|
+
baseURL: e.target.value
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
}),
|
|
1642
|
+
style: settingsInputStyle
|
|
1643
|
+
})), (0, react.createElement)("div", { style: {
|
|
1644
|
+
display: "grid",
|
|
1645
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
|
|
1646
|
+
gap: 8,
|
|
1647
|
+
marginTop: 8
|
|
1648
|
+
} }, (0, react.createElement)("div", null, label("Jev API Key"), (0, react.createElement)("input", {
|
|
1649
|
+
type: "password",
|
|
1650
|
+
placeholder: config.trigger.jev?.apiKeyMeta?.configured ? `已配置 ••••${config.trigger.jev.apiKeyMeta.last4 ?? ""}` : "输入 API Key",
|
|
1651
|
+
value: config.trigger.jev?.apiKey ?? "",
|
|
1652
|
+
onChange: (e) => setConfig({
|
|
1653
|
+
...config,
|
|
1654
|
+
trigger: {
|
|
1655
|
+
...config.trigger,
|
|
1656
|
+
jev: {
|
|
1657
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1658
|
+
apiKey: e.target.value
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}),
|
|
1662
|
+
style: settingsInputStyle
|
|
1663
|
+
})), (0, react.createElement)("div", null, label("API Key 环境变量名(可选)"), (0, react.createElement)("input", {
|
|
1664
|
+
placeholder: "TYPESAFE_API_KEY 或 OPENROUTER_API_KEY",
|
|
1665
|
+
value: config.trigger.jev?.apiKeyEnv ?? "",
|
|
1666
|
+
onChange: (e) => setConfig({
|
|
1667
|
+
...config,
|
|
1668
|
+
trigger: {
|
|
1669
|
+
...config.trigger,
|
|
1670
|
+
jev: {
|
|
1671
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1672
|
+
apiKeyEnv: e.target.value
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}),
|
|
1676
|
+
style: settingsInputStyle
|
|
1677
|
+
}))), (0, react.createElement)("div", { style: {
|
|
1678
|
+
display: "flex",
|
|
1679
|
+
alignItems: "center",
|
|
1680
|
+
gap: 8,
|
|
1681
|
+
marginTop: 8
|
|
1682
|
+
} }, (0, react.createElement)("input", {
|
|
1683
|
+
type: "checkbox",
|
|
1684
|
+
checked: config.trigger.jev?.useEnglishState ?? false,
|
|
1685
|
+
onChange: (e) => setConfig({
|
|
1686
|
+
...config,
|
|
1687
|
+
trigger: {
|
|
1688
|
+
...config.trigger,
|
|
1689
|
+
jev: {
|
|
1690
|
+
...config.trigger.jev ?? defaultJevConfig(),
|
|
1691
|
+
useEnglishState: e.target.checked
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
})
|
|
1695
|
+
}), label("Jev 英文判定(questionEn 概要)")), (0, react.createElement)("div", { style: {
|
|
1696
|
+
fontSize: 12,
|
|
1697
|
+
color: "var(--dsh-color-muted, #8b90a0)",
|
|
1698
|
+
margin: "4px 0 0"
|
|
1699
|
+
} }, "开启后,主模型提供的英文概要(questionEn)会作为 Jev 的判定输入;展示问句、会话记录与重复检测仍用中文。默认关闭。")), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("div", { style: {
|
|
1418
1700
|
display: "flex",
|
|
1419
1701
|
alignItems: "center",
|
|
1420
1702
|
gap: 8
|
|
@@ -1829,9 +2111,11 @@ function apply(ctx) {
|
|
|
1829
2111
|
key: "advisor-group",
|
|
1830
2112
|
locale: "chat"
|
|
1831
2113
|
}, AdvisorGroupNodeView));
|
|
1832
|
-
ctx.slots.inject("settings.
|
|
1833
|
-
name: "settings.
|
|
1834
|
-
|
|
2114
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2115
|
+
name: "settings.section",
|
|
2116
|
+
id: "dsh-advisor-group",
|
|
2117
|
+
order: 0,
|
|
2118
|
+
label: "顾问群"
|
|
1835
2119
|
}, AdvisorGroupSettingsTab));
|
|
1836
2120
|
}
|
|
1837
2121
|
|
package/lib/index.d.mts
CHANGED
|
@@ -99,7 +99,7 @@ interface DiscussionConfig {
|
|
|
99
99
|
* a read-only whitelist of the session's tools (read/grep/glob/web_search…);
|
|
100
100
|
* 'all' exposes every session-visible tool (incl. writable ones); 'off'
|
|
101
101
|
* disables tool calling. Only the direct-http OpenAI/Anthropic channel
|
|
102
|
-
* supports tool calling (ctx.llm / dsh-llm
|
|
102
|
+
* supports tool calling (ctx.llm / dsh-llm does not expose tool calling).
|
|
103
103
|
*/
|
|
104
104
|
advisorTools?: 'readonly' | 'all' | 'off';
|
|
105
105
|
/**
|
|
@@ -112,6 +112,26 @@ interface TriggerConfig {
|
|
|
112
112
|
requireClassifier: boolean;
|
|
113
113
|
allowWebFallback: boolean;
|
|
114
114
|
confidenceThreshold: number;
|
|
115
|
+
jev?: JevConfig;
|
|
116
|
+
}
|
|
117
|
+
type JevProvider = 'typesafe' | 'openrouter';
|
|
118
|
+
interface JevConfig {
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
provider: JevProvider;
|
|
121
|
+
model: string;
|
|
122
|
+
baseURL?: string;
|
|
123
|
+
apiKey?: string;
|
|
124
|
+
apiKeyEnv?: string;
|
|
125
|
+
timeoutMs: number;
|
|
126
|
+
confidenceThreshold: number;
|
|
127
|
+
/** Judge with the caller-provided English gist (questionEn) as the Jev state; default keeps the Chinese question. */
|
|
128
|
+
useEnglishState?: boolean;
|
|
129
|
+
/** Threshold for the high_risk question; unset means follow confidenceThreshold. */
|
|
130
|
+
highRiskThreshold?: number;
|
|
131
|
+
apiKeyMeta?: {
|
|
132
|
+
configured: boolean;
|
|
133
|
+
last4?: string;
|
|
134
|
+
};
|
|
115
135
|
}
|
|
116
136
|
interface UiConfig {
|
|
117
137
|
theme: 'retro-green' | 'retro-amber' | 'retro-blue';
|