dsh-deepseek-web-login 0.6.9 → 0.6.10
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 +31 -0
- package/lib/index.js +35 -7
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循大致语义化版本;日期为本地时间。
|
|
4
4
|
|
|
5
|
+
## 0.6.10 — 2026-09-30
|
|
6
|
+
|
|
7
|
+
**修「换个窗口聊天就把上下文清一次」:重开链时不再往复用来的会话里塞根消息。**
|
|
8
|
+
|
|
9
|
+
现场(用户截图 + 网页端界面):DeepSeek 网页端里,同一个用户消息气泡(内容就是我们那份
|
|
10
|
+
`# Tool Calling Protocol` 提示词)下面出现 **`5 / 5` 的版本翻页 + 「修改 / 重新生成」入口** ——
|
|
11
|
+
也就是插件在那条消息下反复造了兄弟分支;用户那边的观感是"换个窗口它就把上下文清了一遍,
|
|
12
|
+
还老是去调网页端的『修改』"。
|
|
13
|
+
|
|
14
|
+
根因(代码 + 实机状态双证):
|
|
15
|
+
|
|
16
|
+
1. 网页端会话槽与投喂链都是**账号级单槽**(`reuseSlot` / `contextChain`),不区分 DSH 会话 ——
|
|
17
|
+
这是既有设计,不是本次引入的。所以"换窗口"时,新窗口的请求会**落进上一个窗口的网页端会话**。
|
|
18
|
+
2. 落进去之后,链判据必然不满足(历史不是严格追加 / head 变了 / 会话轮换 / 同一步重试),
|
|
19
|
+
于是走 `decideFeed` 的 `restart` 分支:**发全量 prompt + `parent_message_id: null`**。
|
|
20
|
+
`null` 是「根消息」语义,而那个会话**已经有内容** ⇒ 网页端把这条根渲染成同一位置的
|
|
21
|
+
又一个兄弟版本(`n / n`),分叉的对象恰好是我们那份巨大的提示词。实机当时是
|
|
22
|
+
`entries=46`(该会话里已经挂着一段 46 条的链)而 `parentId=6` 的错位状态。
|
|
23
|
+
|
|
24
|
+
改法:**要发根消息 + 当前会话是复用来的 ⇒ 换一个干净会话**(旧会话交回给它自己的清理)。
|
|
25
|
+
判据抽成纯函数 `needsFreshSession(feed, reused, mode)`,有用例守,并守住"宿主真的调用了它"。
|
|
26
|
+
|
|
27
|
+
⚠️ 刻意**只在链式模式下生效**:全量模式里"每轮都是根消息"本来就是常态,若也一律换会话,
|
|
28
|
+
就变成**每轮多建 + 多删一个会话**(+2 个请求/轮)—— 请求密度本身就是风控关注点,
|
|
29
|
+
不能为只有链式模式才有的问题付这个代价(这一条也被用例钉住了)。
|
|
30
|
+
|
|
31
|
+
⚠️ 已知边界(本版**没**解决,需要先确认能力):真正做到"每个 DSH 会话各用一个网页端会话"
|
|
32
|
+
需要 DSH 把会话身份交给适配器;目前查到的请求头里只有 `config / adapterDefaults / tools`,
|
|
33
|
+
没有会话 id。本版的效果是"不再污染别人的会话、不再造兄弟分支",代价是切换窗口时该窗口会
|
|
34
|
+
新开一个网页端会话(旧的会被回收)。
|
|
35
|
+
|
|
5
36
|
## 0.6.9 — 2026-09-30
|
|
6
37
|
|
|
7
38
|
**补丁版:修好诊断工具(`tools/inspect-session.mjs`)在官方桌面端上的静默失效。**
|
package/lib/index.js
CHANGED
|
@@ -1337,6 +1337,25 @@ function normalizeContextMode(value) {
|
|
|
1337
1337
|
}
|
|
1338
1338
|
/** 设置页展示用(纯文本,别写 markdown 星号)。 */
|
|
1339
1339
|
const CONTEXT_MODE_HINT = "链式投喂:之后每轮只发新增内容,并把上一条回答挂到父消息上,让服务端自己维护上下文 —— 请求体小得多、也更像真人连续对话。代价是工具协议只存在于链首那条消息里,一旦服务端把早期上下文丢掉,模型可能不按约定格式发工具调用;本插件遇到任何不确定会自动退回全量重发。每轮全量:最稳,行为和以前完全一致(网页端会看到每条消息都带着完整提示词)。";
|
|
1340
|
+
/**
|
|
1341
|
+
* 这一轮要不要**换一个干净会话**。
|
|
1342
|
+
*
|
|
1343
|
+
* 🔴 2026-09-30 实测的坑(用户报"换个窗口聊天就把上下文清理一次"):
|
|
1344
|
+
* 重开链时发的是 `parent_message_id: null`(根消息);如果那时用的还是**复用来的**会话,
|
|
1345
|
+
* 就等于往一个**已经有内容**的网页端会话里又塞了一个根 —— 网页端把它渲染成同一条消息的
|
|
1346
|
+
* 多个兄弟版本(带「修改 / 重新生成」入口和 `n / n` 翻页),而那条消息恰好是我们那份巨大的
|
|
1347
|
+
* 提示词 ⇒ 界面上看起来就是"同一段提示词被改了好几遍、上下文被清了一次"。
|
|
1348
|
+
* 触发重开链的原因很多(`FeedReason` 那几种:换窗口导致历史不是严格追加、head 变了、
|
|
1349
|
+
* 会话轮换、同一步重试……),日常使用里**经常**走到。
|
|
1350
|
+
*
|
|
1351
|
+
* 判据:**要发根消息 + 当前会话是复用来的 ⇒ 换新会话**。重开链的语义本来就是"从干净上下文
|
|
1352
|
+
* 重新开始",那就该配一个干净会话(旧会话交回给它自己的清理)。
|
|
1353
|
+
* 本来就是新会话(`reused === false`)时**不重复换**,否则每轮都白建一个。
|
|
1354
|
+
*/
|
|
1355
|
+
function needsFreshSession(feed, reused, mode) {
|
|
1356
|
+
if (mode !== "chained") return false;
|
|
1357
|
+
return feed.parentMessageId === null && reused;
|
|
1358
|
+
}
|
|
1340
1359
|
/** 严格前缀:prev 是 next 的前缀(含相等时不算"追加")。 */
|
|
1341
1360
|
function isStrictPrefix(prev, next) {
|
|
1342
1361
|
if (next.length <= prev.length) return false;
|
|
@@ -2933,7 +2952,7 @@ function accountKey(auth) {
|
|
|
2933
2952
|
}
|
|
2934
2953
|
return (hash >>> 0).toString(36);
|
|
2935
2954
|
}
|
|
2936
|
-
async function leaseSession(auth, signal, transport, maxTurns, cleanup) {
|
|
2955
|
+
async function leaseSession(auth, signal, transport, maxTurns, cleanup, forceNew = false) {
|
|
2937
2956
|
signal.throwIfAborted();
|
|
2938
2957
|
const key = accountKey(auth);
|
|
2939
2958
|
const limit = Number.isFinite(maxTurns) ? Math.max(0, Math.floor(maxTurns)) : 20;
|
|
@@ -2941,7 +2960,7 @@ async function leaseSession(auth, signal, transport, maxTurns, cleanup) {
|
|
|
2941
2960
|
sessionId: await transport.createSession(auth, signal),
|
|
2942
2961
|
reused: false
|
|
2943
2962
|
};
|
|
2944
|
-
if (reuseSlot && reuseSlot.key === key && reuseSlot.turns < limit) {
|
|
2963
|
+
if (!forceNew && reuseSlot && reuseSlot.key === key && reuseSlot.turns < limit) {
|
|
2945
2964
|
reuseSlot.turns += 1;
|
|
2946
2965
|
return {
|
|
2947
2966
|
sessionId: reuseSlot.sessionId,
|
|
@@ -3037,9 +3056,8 @@ async function openCompletion(auth, params, signal, transport) {
|
|
|
3037
3056
|
let lastFailure;
|
|
3038
3057
|
const canFailover = makeCanFailover(params);
|
|
3039
3058
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
3040
|
-
|
|
3041
|
-
const
|
|
3042
|
-
const feed = decideFeed({
|
|
3059
|
+
let lease = await leaseSession(auth, signal, transport, params.sessionReuseTurns ?? 20, params.onDeleteSession);
|
|
3060
|
+
const planFeed = (sessionId, reused) => decideFeed({
|
|
3043
3061
|
mode: currentContextMode(),
|
|
3044
3062
|
...params.promptParts ? {
|
|
3045
3063
|
head: params.promptParts.head,
|
|
@@ -3049,9 +3067,19 @@ async function openCompletion(auth, params, signal, transport) {
|
|
|
3049
3067
|
full: params.prompt,
|
|
3050
3068
|
sessionId,
|
|
3051
3069
|
accountKey: accountKey(auth),
|
|
3052
|
-
reused
|
|
3070
|
+
reused,
|
|
3053
3071
|
...contextChain ? { chain: contextChain } : {}
|
|
3054
3072
|
});
|
|
3073
|
+
let feed = planFeed(lease.sessionId, lease.reused);
|
|
3074
|
+
if (needsFreshSession(feed, lease.reused, currentContextMode())) {
|
|
3075
|
+
const reason = feed.reason;
|
|
3076
|
+
lease = await leaseSession(auth, signal, transport, params.sessionReuseTurns ?? 20, params.onDeleteSession, true);
|
|
3077
|
+
feed = {
|
|
3078
|
+
...planFeed(lease.sessionId, lease.reused),
|
|
3079
|
+
reason
|
|
3080
|
+
};
|
|
3081
|
+
}
|
|
3082
|
+
const sessionId = lease.sessionId;
|
|
3055
3083
|
if (feed.reason !== lastFeedReason) {
|
|
3056
3084
|
lastFeedReason = feed.reason;
|
|
3057
3085
|
params.onContextFeed?.({
|
|
@@ -9171,7 +9199,7 @@ async function checkForUpdate(current, fetchImpl) {
|
|
|
9171
9199
|
* 兜底常量与 package.json 的一致性由 `tests/check-smoke.mjs` 守着,不会漂。
|
|
9172
9200
|
*/
|
|
9173
9201
|
/** 与 package.json 保持一致的兜底版本(由测试保证不会漂)。 */
|
|
9174
|
-
const FALLBACK_VERSION = "0.6.
|
|
9202
|
+
const FALLBACK_VERSION = "0.6.10";
|
|
9175
9203
|
let cached;
|
|
9176
9204
|
/** 本插件版本(如 `0.1.26`)。 */
|
|
9177
9205
|
function pluginVersion() {
|