dsh-deepseek-web-login 0.4.2 → 0.5.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/CHANGELOG.md CHANGED
@@ -2,6 +2,52 @@
2
2
 
3
3
  本项目遵循大致语义化版本;日期为本地时间。
4
4
 
5
+ ## 0.5.1 — 2026-09-27
6
+
7
+ > 面板能看见「上次自动换号」了;另修两处与现状矛盾的说明。
8
+
9
+ ### 新增
10
+
11
+ - **「上次自动换号」显示**:自动换号之后,「防风控」页的自动换号说明里会多出一句
12
+ `上次自动换号:09:12(工作号 → xxx@gmail.com)`。
13
+ 换号那一轮会全量重发(体感是任务突然变慢),有了这行就能对上原因。
14
+ - 只记**自动**换号;手动切号不记(那是你自己的操作,不需要提示)。
15
+ - 只记录在内存里:重启后从"还没有记录"开始 —— 换号是运行时行为,留一份过期时间反而误导。
16
+ - 账号两端按账号库里的展示名显示(备注名优先,其次掩码账号,不泄露完整凭证信息)。
17
+
18
+ ### 修复
19
+
20
+ - 纠正两处**与现状矛盾**的说明:关于页那张卡片的标题原为「为什么没有「自动换号」」,
21
+ `src/accounts.ts` 的模块注释也写着"刻意不做自动轮换" —— 而「自动换号」从 0.4.0 起就有了。
22
+ 两处都改成"默认关闭"的表述,原有论据(机器行为特征 / 多号关联风险)全部保留。
23
+
24
+ ## 0.5.0 — 2026-09-27
25
+
26
+ > 新增「允许并行调用工具」开关,并把默认改成**一次只发一个工具调用**。
27
+
28
+ ### 新增
29
+
30
+ - **「允许并行调用工具」开关**(「防风控」页 → 请求节流):关掉后模型一轮只发一个工具调用、
31
+ 等结果回来再决定下一步;打开则允许一轮最多 3 个,由 DSH 并行执行。
32
+ - 它改变的是**模型看到的协议指令** —— 属于「引导」而不是「强制」,不拦截也不改写模型发出的调用。
33
+ - ⚠️ 切换后**第一轮会全量重发一次**(协议文本变了,投喂链要重建),之后恢复正常。
34
+
35
+ ### 变更(**破坏性语义变化**)
36
+
37
+ - 🔴 **默认改为「一次只发一个工具调用」**(即开关默认不勾)。0.4.2 及以前默认允许批量。
38
+ - 升级后**第一个任务的协议文本即变化** ⇒ 投喂链断一次(下一轮全量重发 + 新建网页端会话)。
39
+ - 之后每个任务**总耗时变长**:每个工具各占一轮请求(3 个工具约从 2 轮变 4 轮)。
40
+ - 想保留旧行为:设置页把「允许并行调用工具」勾上即可(= 显式 `serialToolCalls: false`)。
41
+
42
+ ### 说明
43
+
44
+ - 工具在 DSH 侧执行(读文件、跑命令),**不产生任何 DeepSeek 请求** ⇒ 对网页端不可见。
45
+ 别和「允许并发生成」混淆:后者是**同时对 DeepSeek 发两条请求**(实测会触发账号级限制),
46
+ 前者只影响模型一轮里发几个工具调用。
47
+ - **请求密度本身基本不变**:闸门间隔按「上一次结束」时刻计算,而工具执行发生在其后
48
+ ⇒ 工具耗时本就盖住了那段间隔。实测 827 个相邻请求间隔里 **99% 都 > 4s**(中位 18.3s)。
49
+ 真正变化的是**总请求数**与**总耗时**。
50
+
5
51
  ## 0.4.2 — 2026-09-26
6
52
 
7
53
  > 新增「Token 统计」页:本地的用量趋势与分布。以前 token 数只在上报途中被算一次就丢了。
package/lib/client.js CHANGED
@@ -1632,16 +1632,40 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
1632
1632
  const swHint = el("p", "dsw-hint", "");
1633
1633
  gateCard.append(swHint);
1634
1634
  const currentSwitchMinutes = () => Math.max(0, Math.round(Number(swRange.value) || 0));
1635
+ /** 最近一次自动换号(后端只在**自动**切号时写;手动切不记)。null = 还没有过。 */
1636
+ let lastAutoSwitchInfo = null;
1635
1637
  const paintAutoSwitch = () => {
1636
1638
  const minutes = currentSwitchMinutes();
1637
1639
  swValue.textContent = minutes === 0 ? "关闭" : `${minutes} 分钟`;
1638
- swHint.textContent = minutes === 0 ? "关闭时不会自动换号 —— 当前账号一直用到你手动切换为止。" : `每 ${minutes} 分钟换到账号库里的下一个可用账号(失效或正在受限的会跳过;可用的不足两个就不换)。换号会让投喂链断掉:下一轮要全量重发,历史图也要重新上传 —— 间隔越短,这个代价出现得越频繁。`;
1640
+ const base = minutes === 0 ? "关闭时不会自动换号 —— 当前账号一直用到你手动切换为止。" : `每 ${minutes} 分钟换到账号库里的下一个可用账号(失效或正在受限的会跳过;可用的不足两个就不换)。换号会让投喂链断掉:下一轮要全量重发,历史图也要重新上传 —— 间隔越短,这个代价出现得越频繁。`;
1641
+ const last = lastAutoSwitchInfo;
1642
+ swHint.textContent = last ? `${base}上次自动换号:${shortTime(last.at)}(${last.from} → ${last.to})。` : base;
1639
1643
  };
1640
1644
  swRange.addEventListener("input", paintAutoSwitch);
1641
1645
  swRange.addEventListener("change", () => {
1642
1646
  paintAutoSwitch();
1643
1647
  saveGate({ autoSwitchMinutes: currentSwitchMinutes() });
1644
1648
  });
1649
+ const serialRow = el("div", "dsw-gate-row");
1650
+ const serialLabel = el("label", "dsw-switch");
1651
+ const serialInput = el("input");
1652
+ serialInput.type = "checkbox";
1653
+ const serialTrack = el("span", "dsw-switch-track");
1654
+ serialLabel.append(serialInput, serialTrack, el("span", void 0, "允许并行调用工具"));
1655
+ serialRow.append(serialLabel);
1656
+ gateCard.append(serialRow);
1657
+ const serialHint = el("p", "dsw-hint", "");
1658
+ gateCard.append(serialHint);
1659
+ const paintSerialTools = () => {
1660
+ const batched = serialInput.checked;
1661
+ serialHint.textContent = batched ? "允许并行:模型可以一次发多个工具调用(同一批最多 3 个),DSH 会并行跑它们 —— 一轮请求推进多步,任务更快。工具在 DSH 侧执行、不发 DeepSeek 请求,所以对网页端不可见。切换后的第一轮会全量重发一次。" : "默认:一次只发一个工具调用,等结果回来再决定下一步 —— 后一步能用上前一步的真实结果,逐步反应更稳。代价是每个工具各占一轮请求,任务总耗时明显变长。切换后的第一轮会全量重发一次。";
1662
+ };
1663
+ serialInput.checked = false;
1664
+ paintSerialTools();
1665
+ serialInput.addEventListener("change", () => {
1666
+ paintSerialTools();
1667
+ saveGate({ serialToolCalls: !serialInput.checked });
1668
+ });
1645
1669
  const cleanupRow = el("div", "dsw-gate-row");
1646
1670
  cleanupRow.append(el("span", "dsw-gate-label", "会话清理"));
1647
1671
  const cleanupBtns = {};
@@ -2179,9 +2203,9 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
2179
2203
  for (const [key, value] of rows) pathsKv.append(el("div", "k", key), el("div", "dsw-path", value));
2180
2204
  };
2181
2205
  const riskCard = el("div", "dsw-card");
2182
- riskCard.append(el("div", "dsw-cardhead", "为什么没有「自动换号」"));
2183
- riskCard.append(el("p", "dsw-hint", "💡 账号库支持一键手动切换,但刻意不做自动轮换(检测到限流就自动换一个号继续发)。原因不是保守:"));
2184
- riskCard.append(el("p", "dsw-hint", "参考项目切的是「CLI 下次启动用哪个账号」——服务端看不到;而我们每次对话都实时发请求。真人不会在几分钟内换一个账号接着发消息,自动换号是极强的机器行为特征,与本插件在传输层指纹、随机间隔、会话清理上「降低机器可识别性」的努力直接冲突。"));
2206
+ riskCard.append(el("div", "dsw-cardhead", "关于「自动换号」(默认关闭)"));
2207
+ riskCard.append(el("p", "dsw-hint", "💡 账号库支持一键手动切换;「防风控」页的「自动换号」滑块可以让它按时间轮换 —— 但默认是关闭的,因为下面这些理由仍然成立:开它是在拿「降低机器特征」换「摊薄单账号密度」。"));
2208
+ riskCard.append(el("p", "dsw-hint", "参考项目切的是「CLI 下次启动用哪个账号」——服务端看不到;而我们每次对话都实时发请求。真人不会在几分钟内换一个账号接着发消息,自动换号是极强的机器行为特征,与本插件在传输层指纹、随机间隔、会话清理上「降低机器可识别性」的努力直接冲突。⇒ 所以它默认关闭,而且判据只看时间、不看限流状态(\"一被限流就换\"更糟:同一出口 IP 上多号交替活跃,更像有组织的规避)。"));
2185
2209
  riskCard.append(el("p", "dsw-hint", "另外:同一服务商会把多账号关联起来(同设备 / 同 IP / 同指纹 / 相近的行为模式)。一旦被判定为同一人的多开小号,处置通常比单账号超频更重,而且可能波及全部关联账号。所以账号库的目标是「在自己的多个正常账号之间切换更省事」,不是「靠轮换把限流绕过去」。"));
2186
2210
  aboutPane.append(riskCard);
2187
2211
  const applyTransportCard = (info) => {
@@ -2326,7 +2350,10 @@ background:var(--bg2);white-space:pre-wrap;font-size:12px}
2326
2350
  swRange.min = String(swBounds.min);
2327
2351
  swRange.max = String(swBounds.max);
2328
2352
  swRange.value = String(g.autoSwitchMinutes ?? g.autoSwitchDefault ?? 0);
2353
+ lastAutoSwitchInfo = g.lastAutoSwitch ?? null;
2329
2354
  paintAutoSwitch();
2355
+ serialInput.checked = g.serialToolCalls === false;
2356
+ paintSerialTools();
2330
2357
  const mode = g.cleanup?.mode ?? "deferred";
2331
2358
  for (const key of Object.keys(cleanupBtns)) cleanupBtns[key].classList.toggle("active", key === mode);
2332
2359
  const showRanges = mode === "deferred";