dsh-advisor-group 0.1.2 → 0.1.4

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
@@ -1497,7 +1497,189 @@ function AdvisorGroupSettingsTab() {
1497
1497
  }))), (0, react.createElement)("div", { style: settingsSectionStyle }, dailyGuard ? (0, react.createElement)("div", { style: {
1498
1498
  fontSize: 12,
1499
1499
  color: !dailyGuard.enabled || dailyGuard.remaining > 0 ? "var(--dsh-color-muted, #8b90a0)" : "#e11d48"
1500
- } }, dailyGuard.enabled ? dailyGuard.remaining > 0 ? `今日剩余咨询次数:${dailyGuard.remaining} / ${dailyGuard.limit}(UTC 日切)` : `今日咨询次数已用尽(${dailyGuard.used} / ${dailyGuard.limit}),将于 UTC 日切后恢复。` : `今日已咨询 ${dailyGuard.used} 次(每日上限已关闭)。`) : null), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("div", { style: {
1500
+ } }, dailyGuard.enabled ? dailyGuard.remaining > 0 ? `今日剩余咨询次数:${dailyGuard.remaining} / ${dailyGuard.limit}(UTC 日切)` : `今日咨询次数已用尽(${dailyGuard.used} / ${dailyGuard.limit}),将于 UTC 日切后恢复。` : `今日已咨询 ${dailyGuard.used} 次(每日上限已关闭)。`) : null), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("strong", null, "全局蜂群"), (0, react.createElement)("div", { style: {
1501
+ fontSize: 12,
1502
+ color: "var(--dsh-color-muted, #8b90a0)",
1503
+ margin: "4px 0 8px"
1504
+ } }, "跨会话提问的开关与默认应答方式。"), (0, react.createElement)("div", { style: {
1505
+ display: "flex",
1506
+ alignItems: "center",
1507
+ gap: 8
1508
+ } }, (0, react.createElement)("input", {
1509
+ type: "checkbox",
1510
+ checked: config.swarm.enabled,
1511
+ onChange: (e) => setConfig({
1512
+ ...config,
1513
+ swarm: {
1514
+ ...config.swarm,
1515
+ enabled: e.target.checked
1516
+ }
1517
+ })
1518
+ }), label("总开关")), (0, react.createElement)("div", { style: {
1519
+ fontSize: 12,
1520
+ color: "var(--dsh-color-muted, #8b90a0)",
1521
+ margin: "2px 0 8px"
1522
+ } }, "关闭后本插件不再跨会话提问,三个工具会明确拒绝"), (0, react.createElement)("div", { style: {
1523
+ display: "grid",
1524
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
1525
+ gap: 8
1526
+ } }, (0, react.createElement)("div", null, label("默认应答方式"), (0, react.createElement)("select", {
1527
+ value: config.swarm.defaultMode,
1528
+ onChange: (e) => setConfig({
1529
+ ...config,
1530
+ swarm: {
1531
+ ...config.swarm,
1532
+ defaultMode: e.target.value === "detach" ? "detach" : "wait"
1533
+ }
1534
+ }),
1535
+ style: settingsInputStyle
1536
+ }, (0, react.createElement)("option", { value: "wait" }, "同步等待"), (0, react.createElement)("option", { value: "detach" }, "异步投递"))), (0, react.createElement)("div", null, label("默认等待上限(分钟)"), (0, react.createElement)("input", {
1537
+ type: "number",
1538
+ min: 1,
1539
+ max: 10,
1540
+ value: String(Math.round(config.swarm.defaultWaitMs / 6e4)),
1541
+ onChange: (e) => setConfig({
1542
+ ...config,
1543
+ swarm: {
1544
+ ...config.swarm,
1545
+ defaultWaitMs: Math.min(10, Math.max(1, Number(e.target.value) || 1)) * 6e4
1546
+ }
1547
+ }),
1548
+ style: settingsInputStyle
1549
+ }), (0, react.createElement)("div", { style: {
1550
+ fontSize: 12,
1551
+ color: "var(--dsh-color-muted, #8b90a0)",
1552
+ marginTop: 4
1553
+ } }, "可填 1–10 分钟")), (0, react.createElement)("div", null, label("异步结果保留(小时)"), (0, react.createElement)("input", {
1554
+ type: "number",
1555
+ min: 1,
1556
+ max: 720,
1557
+ value: String(config.swarm.resultTtlHours),
1558
+ onChange: (e) => setConfig({
1559
+ ...config,
1560
+ swarm: {
1561
+ ...config.swarm,
1562
+ resultTtlHours: Math.min(720, Math.max(1, Number(e.target.value) || 1))
1563
+ }
1564
+ }),
1565
+ style: settingsInputStyle
1566
+ }))), (0, react.createElement)("div", { style: {
1567
+ display: "flex",
1568
+ alignItems: "center",
1569
+ gap: 8,
1570
+ marginTop: 8
1571
+ } }, (0, react.createElement)("input", {
1572
+ type: "checkbox",
1573
+ checked: config.swarm.rosterIncludeSubagents,
1574
+ onChange: (e) => setConfig({
1575
+ ...config,
1576
+ swarm: {
1577
+ ...config.swarm,
1578
+ rosterIncludeSubagents: e.target.checked
1579
+ }
1580
+ })
1581
+ }), label("名录列出子代理会话")), (0, react.createElement)("div", { style: {
1582
+ display: "flex",
1583
+ alignItems: "center",
1584
+ gap: 8,
1585
+ marginTop: 8
1586
+ } }, (0, react.createElement)("input", {
1587
+ type: "checkbox",
1588
+ checked: config.swarm.routingEnabled !== false,
1589
+ onChange: (e) => setConfig({
1590
+ ...config,
1591
+ swarm: {
1592
+ ...config.swarm,
1593
+ routingEnabled: e.target.checked
1594
+ }
1595
+ })
1596
+ }), label("按问题找会话")), (0, react.createElement)("div", { style: {
1597
+ fontSize: 12,
1598
+ color: "var(--dsh-color-muted, #8b90a0)",
1599
+ margin: "2px 0 8px"
1600
+ } }, "没有点名会话时,先按问题关键词列出候选,交给用户挑一个,不自动投递"), (0, react.createElement)("div", { style: {
1601
+ display: "flex",
1602
+ alignItems: "center",
1603
+ gap: 8
1604
+ } }, label("候选数"), (0, react.createElement)("input", {
1605
+ type: "number",
1606
+ min: 1,
1607
+ max: 8,
1608
+ value: String(config.swarm.routingTopN ?? 3),
1609
+ disabled: config.swarm.routingEnabled === false,
1610
+ onChange: (e) => setConfig({
1611
+ ...config,
1612
+ swarm: {
1613
+ ...config.swarm,
1614
+ routingTopN: Math.min(8, Math.max(1, Number(e.target.value) || 3))
1615
+ }
1616
+ }),
1617
+ style: {
1618
+ ...settingsInputStyle,
1619
+ width: 120
1620
+ }
1621
+ })), (0, react.createElement)("div", { style: {
1622
+ display: "flex",
1623
+ alignItems: "center",
1624
+ gap: 8,
1625
+ marginTop: 8
1626
+ } }, label("路由方式"), (0, react.createElement)("select", {
1627
+ value: config.swarm.routingEngine === "jev" ? "jev" : "local",
1628
+ disabled: config.swarm.routingEnabled === false,
1629
+ onChange: (e) => setConfig({
1630
+ ...config,
1631
+ swarm: {
1632
+ ...config.swarm,
1633
+ routingEngine: e.target.value === "jev" ? "jev" : "local"
1634
+ }
1635
+ }),
1636
+ style: settingsInputStyle
1637
+ }, (0, react.createElement)("option", { value: "local" }, "本地计算"), (0, react.createElement)("option", { value: "jev" }, "Jev 判断"))), (0, react.createElement)("div", { style: {
1638
+ fontSize: 12,
1639
+ color: "var(--dsh-color-muted, #8b90a0)",
1640
+ margin: "2px 0 8px"
1641
+ } }, "Jev 判断需要单独配置在「触发判定」里的 Jev 凭据;任何失败都会静默回退到本地排序"), (0, react.createElement)("div", { style: {
1642
+ display: "flex",
1643
+ alignItems: "center",
1644
+ gap: 8,
1645
+ marginTop: 8
1646
+ } }, label("是否该问别的会话"), (0, react.createElement)("select", {
1647
+ value: config.swarm.routingAsk === "off" ? "off" : config.swarm.routingAsk === "always" ? "always" : "gated",
1648
+ onChange: (e) => setConfig({
1649
+ ...config,
1650
+ swarm: {
1651
+ ...config.swarm,
1652
+ routingAsk: e.target.value === "off" ? "off" : e.target.value === "always" ? "always" : "gated"
1653
+ }
1654
+ }),
1655
+ style: settingsInputStyle
1656
+ }, (0, react.createElement)("option", { value: "off" }, "关"), (0, react.createElement)("option", { value: "gated" }, "本地预过滤 + Jev(默认)"), (0, react.createElement)("option", { value: "always" }, "每轮都问"))), (0, react.createElement)("div", { style: {
1657
+ fontSize: 12,
1658
+ color: "var(--dsh-color-muted, #8b90a0)",
1659
+ margin: "2px 0 8px"
1660
+ } }, "中间档只在消息看起来涉及别的会话时才问 Jev,几乎不花钱;最后一档每轮都会多一次 Jev 调用"), (0, react.createElement)("div", { style: { marginTop: 8 } }, label("不参与路由的会话"), (0, react.createElement)("textarea", {
1661
+ "aria-label": "routingExclude",
1662
+ placeholder: "每行一个:会话标题关键词或完整 sessionId",
1663
+ rows: 3,
1664
+ value: (config.swarm.routingExclude ?? []).join("\n"),
1665
+ onChange: (e) => setConfig({
1666
+ ...config,
1667
+ swarm: {
1668
+ ...config.swarm,
1669
+ routingExclude: e.target.value.split("\n").map((line) => line.trim()).filter((line) => line.length > 0)
1670
+ }
1671
+ }),
1672
+ style: {
1673
+ ...settingsInputStyle,
1674
+ marginTop: 4,
1675
+ resize: "vertical",
1676
+ width: "100%"
1677
+ }
1678
+ }), (0, react.createElement)("div", { style: {
1679
+ fontSize: 12,
1680
+ color: "var(--dsh-color-muted, #8b90a0)",
1681
+ marginTop: 4
1682
+ } }, "填会话标题里的关键词或完整 sessionId;这些会话不会出现在路由候选和会话名录里,被点名时也会拒绝投递"))), (0, react.createElement)("div", { style: settingsSectionStyle }, (0, react.createElement)("div", { style: {
1501
1683
  display: "grid",
1502
1684
  gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
1503
1685
  gap: 8
package/lib/index.d.mts CHANGED
@@ -144,12 +144,57 @@ interface QuotaConfig {
144
144
  /** Max new consultations per UTC day when enabled (1–100000), default 50. */
145
145
  maxPerDay: number;
146
146
  }
147
+ interface SwarmConfig {
148
+ /** Master switch for the cross-session tools (ask_session / list_sessions / ask_result). */
149
+ enabled: boolean;
150
+ /** Default response mode when the caller omits both `waitMs` and `detach`. */
151
+ defaultMode: 'wait' | 'detach';
152
+ /** Default wait ceiling in milliseconds when the caller omits `waitMs` (1–10 min). */
153
+ defaultWaitMs: number;
154
+ /** How long detached ask results are kept on disk, in hours (clamped to 1–720). */
155
+ resultTtlHours: number;
156
+ /** Whether the session roster lists subagent sessions. */
157
+ rosterIncludeSubagents: boolean;
158
+ /**
159
+ * Route an unnamed question to candidate sessions instead of guessing or
160
+ * sending it blind (pure keyword layer, no model call). Schema default is on.
161
+ */
162
+ routingEnabled?: boolean;
163
+ /** How many routing candidates to return (1–8, default 3). */
164
+ routingTopN?: number;
165
+ /**
166
+ * Which engine orders the routing candidates (2026-10-19): 'local' (default)
167
+ * uses the keyword scorer alone; 'jev' still recalls with the local scorer —
168
+ * it is the recall step and the safety net — and lets Jev re-rank that closed
169
+ * list. Jev reuses the `trigger.jev` credentials/endpoint config; when it is
170
+ * not configured, or on any failure, the local order is returned unchanged.
171
+ */
172
+ routingEngine?: 'local' | 'jev';
173
+ /**
174
+ * Whether a user turn should ask the cross-session engine for a suggestion
175
+ * (2026-10-19). 'off' never calls Jev; 'gated' (default) asks only when the
176
+ * pure prefilter thinks the turn points at another session/task; 'always'
177
+ * asks on every turn (one batched Jev call per turn). Any answer is a hint
178
+ * only: nothing is delivered and the model decides.
179
+ */
180
+ routingAsk?: 'off' | 'gated' | 'always';
181
+ /**
182
+ * Sessions excluded from the whole swarm (2026-10-19): an entry matches a
183
+ * session when it equals its session id (case-insensitive) or is a
184
+ * case-insensitive substring of its title / fallback display name. Excluded
185
+ * sessions never appear in the roster or routing candidates, routing aliases
186
+ * pointing at them are dropped, and an explicit ask_session target that
187
+ * resolves to one is refused with `swarm-excluded`.
188
+ */
189
+ routingExclude?: string[];
190
+ }
147
191
  interface Config {
148
192
  enabled: boolean;
149
193
  discussion: DiscussionConfig;
150
194
  trigger: TriggerConfig;
151
195
  ui: UiConfig;
152
196
  quota: QuotaConfig;
197
+ swarm: SwarmConfig;
153
198
  advisors: AdvisorConfig[];
154
199
  }
155
200
  declare const Config: Schema<Config>;