dsh-deepseek-web-login 0.4.0 → 0.4.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,24 @@
2
2
 
3
3
  本项目遵循大致语义化版本;日期为本地时间。
4
4
 
5
+ ## 0.4.1 — 2026-09-26
6
+
7
+ > 被限流/封禁时能自己接下去。0.4.0 的自动换号,从这个版本起才是真正的兜底。
8
+
9
+ ### 改进
10
+
11
+ - **封禁后不再需要手动点「继续」**:账号被封(`user is muted`)时,此前把**解除时间**(可能几小时)
12
+ 当作重试间隔交给重试策略 ⇒ 它直接放弃重试 ⇒ 整轮停住、等人手动点「继续」。
13
+ 现在只要**还能换号**(自动换号开着、且账号库里还有可用账号),就给 2 秒的短退避 ——
14
+ 重试立刻发生,重发时自动换到可用账号,**整轮任务自己接下去**。
15
+ - 没有别的账号可用时仍保持原行为(长退避 ⇒ 放弃重试),不做无用空转
16
+ - 候选账号换完即止 ⇒ **不会无限换号重试**
17
+ - ⚠️ 只在自动换号**开着**时生效(滑块默认 0 = 关闭 ⇒ 行为与 0.4.0 完全一致)
18
+
19
+ ### 说明
20
+
21
+ - 限流(`操作过于频繁` / HTTP 429 / 业务码 40029)本来就是自动退避重发、不需要手动干预 —— 这次没动它。
22
+
5
23
  ## 0.4.0 — 2026-09-26
6
24
 
7
25
  > 两件事:一个「自动换号」滑块,以及一条会把限流误判成"不可重试"的修复。
package/lib/index.js CHANGED
@@ -1466,6 +1466,14 @@ function muteUntilMs(json) {
1466
1466
  return Math.round(seconds * 1e3);
1467
1467
  }
1468
1468
  /**
1469
+ * 「能换号接着干」时给的重试退避。
1470
+ *
1471
+ * 为什么是 2 秒而不是 0:让 dsh-llm-retry 立刻重发,但仍留一点余量 ——
1472
+ * 重发进入适配器时,"自动换号"的检查点要先跑完(可能含一次探活)。
1473
+ * 它**不是**"等对面恢复"的退避,而是"我马上换个号再试一次"的信号。
1474
+ */
1475
+ const FAILOVER_RETRY_MS = 2e3;
1476
+ /**
1469
1477
  * 被限制时的用户可读文案。
1470
1478
  *
1471
1479
  * 只说结论与解除时间 —— **不解释原因**。原因(免费网页端对高频自动化的静默限流、
@@ -2877,6 +2885,17 @@ const defaultTransport = {
2877
2885
  */
2878
2886
  async function openCompletion(auth, params, signal, transport) {
2879
2887
  let lastFailure;
2888
+ /**
2889
+ * 宿主给的「还能不能换号接着干」。问不出来(没注入 / 抛错)时按**不能**处理 ——
2890
+ * 保守方向:宁可让用户点一次「继续」,也不要给一个它其实接不上的短退避。
2891
+ */
2892
+ const canFailover = () => {
2893
+ try {
2894
+ return params.canFailover?.() === true;
2895
+ } catch {
2896
+ return false;
2897
+ }
2898
+ };
2880
2899
  for (let attempt = 0; attempt < 2; attempt++) {
2881
2900
  const lease = await leaseSession(auth, signal, transport, params.sessionReuseTurns ?? 20, params.onDeleteSession);
2882
2901
  const sessionId = lease.sessionId;
@@ -2979,7 +2998,7 @@ async function openCompletion(auth, params, signal, transport) {
2979
2998
  const untilMs = muteUntilMs(parsed);
2980
2999
  const failure = biz ? new AdapterLlmError(muted ? mutedMessage(untilMs) : busy ? "网页版限流:同一账号同时只能生成一条消息,稍后自动重试" : throttled ? "网页版限流:发得太频繁,稍后自动重试" : bizErrorMessage(biz.code, biz.msg), muted || busy || throttled ? "RATE_LIMIT" : isInvalidSessionError(biz) ? "TRANSPORT" : isInvalidRefFileError(biz) ? "INVALID_REF_FILE" : bizErrorCode(biz.code), {
2981
3000
  status: resp.status,
2982
- ...muted && untilMs !== void 0 ? { providerRetryAfterMs: Math.max(0, untilMs - Date.now()) } : {},
3001
+ ...muted && untilMs !== void 0 ? { providerRetryAfterMs: canFailover() ? FAILOVER_RETRY_MS : Math.max(0, untilMs - Date.now()) } : {},
2983
3002
  ...muted && untilMs !== void 0 ? { mutedUntilMs: untilMs } : {},
2984
3003
  ...busy ? { providerRetryAfterMs: 5e3 } : {},
2985
3004
  ...throttled ? {
@@ -5812,6 +5831,7 @@ function createAdapter(deps) {
5812
5831
  try {
5813
5832
  for await (const event of runStream(auth, {
5814
5833
  prompt: currentPrompt,
5834
+ canFailover: deps.canFailover,
5815
5835
  promptParts: {
5816
5836
  head: promptParts.head,
5817
5837
  entries: promptParts.entries,
@@ -8236,7 +8256,7 @@ async function checkForUpdate(current, fetchImpl) {
8236
8256
  * 兜底常量与 package.json 的一致性由 `tests/check-smoke.mjs` 守着,不会漂。
8237
8257
  */
8238
8258
  /** 与 package.json 保持一致的兜底版本(由测试保证不会漂)。 */
8239
- const FALLBACK_VERSION = "0.4.0";
8259
+ const FALLBACK_VERSION = "0.4.1";
8240
8260
  let cached;
8241
8261
  /** 本插件版本(如 `0.1.26`)。 */
8242
8262
  function pluginVersion() {
@@ -8825,6 +8845,18 @@ function apply(ctx, config = {}) {
8825
8845
  autoSwitching = false;
8826
8846
  }
8827
8847
  }
8848
+ /**
8849
+ * 「当前账号被限时,换个号还能不能接着干」—— 只决定失败该给长退避还是短退避。
8850
+ *
8851
+ * ⚠️ 只在用户**明确开了**自动换号(间隔 > 0)时才为真。默认关闭 ⇒ 保持原行为
8852
+ * (长退避 ⇒ 重试策略放弃),免得把一个没打算换号的用户悄悄换到别的账号上。
8853
+ */
8854
+ const canFailover = () => {
8855
+ const minutes = gate.settings().autoSwitchMinutes ?? 0;
8856
+ if (!Number.isFinite(minutes) || minutes <= 0) return false;
8857
+ if (autoSwitching) return false;
8858
+ return pickNextAccount(listAccounts().filter((account) => !autoSwitchSkip.has(account.id)), activeAccountId(), Date.now()) !== void 0;
8859
+ };
8828
8860
  let contextMode = applyContextMode(readContextModeSetting() ?? (config.contextMode === "chained" ? "chained" : "full"));
8829
8861
  logger.info?.(`deepseek-web: 上下文投喂=${contextMode}` + (contextMode === "chained" ? "(只发增量 + parent 指向上一条回答)" : "(每轮重发全量 prompt)"));
8830
8862
  const adapterConfig = {
@@ -8965,6 +8997,7 @@ function apply(ctx, config = {}) {
8965
8997
  currentAccountId: activeAccountId,
8966
8998
  gate,
8967
8999
  maybeAutoSwitch,
9000
+ canFailover,
8968
9001
  sessionCleaner,
8969
9002
  config: adapterConfig,
8970
9003
  readImage: async (ref, signal) => {