dsh-deepseek-web-login 0.6.15 → 0.6.17
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 +74 -0
- package/lib/index.js +3927 -3875
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,80 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循大致语义化版本;日期为本地时间。
|
|
4
4
|
|
|
5
|
+
## 0.6.17 — 2026-10-01
|
|
6
|
+
|
|
7
|
+
**增量投喂不再重发「模型上一句回答」(用户反馈:完全没必要)。**
|
|
8
|
+
|
|
9
|
+
用户原话:「为啥网页版的聊天我看到了,还总是把模型上一句回答的结果,加到下一句当提示词!
|
|
10
|
+
完全没必要啊!!!!」(附截图:增量气泡里赫然是 `Assistant: <上一句整段回答>` + `User: 嘟嘟嘟!`)
|
|
11
|
+
|
|
12
|
+
原因:主机的消息列表里既有用户消息、也有**助手消息**(=我们上一轮从服务端流下来的那段回复);
|
|
13
|
+
`serializePromptParts` 把它们统一转写成 `Assistant: …` / `User: …` 条目,而增量投喂原样把
|
|
14
|
+
"新追加的条目"整段发出去 ⇒ 那条回答被当成下一句的输入重发。**它本来就是服务端的上一轮输出
|
|
15
|
+
(就在我们要挂的父消息位置),重发纯属白烧 token,还让模型看到自己在"自言自语"。**
|
|
16
|
+
|
|
17
|
+
改动:
|
|
18
|
+
|
|
19
|
+
1. `context-feed.ts` 新增 `isAssistantTranscriptEntry()`:增量里 `Assistant: …` 条目一律剔除。
|
|
20
|
+
⚠️ **只剔增量**:全量 prompt 是"从零重述",必须保留完整对话(有用例钉着)。
|
|
21
|
+
2. 🔴 **续写/纠正轮必须跳过剔除** —— 那两轮(`adapter.ts` 在回答被截断 / 模型把工具程序写进正文时
|
|
22
|
+
自动发起)是**故意**把半截回答再发一遍的(`Assistant: 半截` + `User: <续写指令>`),
|
|
23
|
+
剔了模型就只能从零重写。判据用**插件自己的指令常量**(`isContinuationCue`),不猜文案 ——
|
|
24
|
+
为此把 `CONTINUE_INSTRUCTION` / `TOOL_CALL_RETRY_INSTRUCTION` 从 `adapter.ts` 挪到
|
|
25
|
+
`protocol.ts`(单一来源,适配器与判据共用)。
|
|
26
|
+
⚠️ 这条是**既有用例逼出来的**:一刀切的实现让「链式 + 续写轮」那条用例立刻变红,
|
|
27
|
+
说明它守的是真语义差异,不是过时的断言。
|
|
28
|
+
3. 边界:尾巴上**只有**回声(没有新用户/工具内容)时不做剔除 —— 宁可多发一段,
|
|
29
|
+
也不要发空增量让这一轮退化成重开链(那会连带换掉会话)。
|
|
30
|
+
4. 可见性:剔了几条进日志(`另略过 N 条模型回声`)并进决策回执(`echoDropped`)。
|
|
31
|
+
|
|
32
|
+
用例:`check-context-feed` +4(剔回声 / 工具调用回声也剔 / 尾巴只有回声时不剔 / 全量不受影响),
|
|
33
|
+
并把「续写轮」那条改成用**真实常量**构造(原来用自造文案)+断言"续写轮不剔"。
|
|
34
|
+
反向验证:退回一刀切的实现 ⇒ 新用例立刻变红。59/59 用例文件通过。
|
|
35
|
+
|
|
36
|
+
## 0.6.16 — 2026-10-01
|
|
37
|
+
|
|
38
|
+
**修严重的现场 bug:链式模式下"一个窗口聊三句 ⇒ 网页端多出三个新会话,旧会话还被删掉"。**
|
|
39
|
+
|
|
40
|
+
### 根因(全程靠插桩定位,没有猜)
|
|
41
|
+
|
|
42
|
+
收尾"放过这个会话"的条件是:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
if (id === sessionId && complete && !poisoned && limit > 0) continue // 放过
|
|
46
|
+
retireSession(id); cleanup(id) // 否则退役 + 删除
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
链式模式只保证了 `limit > 0`(不轮换),但**还有 `complete && !poisoned` 这道门** ——
|
|
50
|
+
而 `complete` 只在一个地方置真:底层流的迭代器自然结束(`item.done`)。
|
|
51
|
+
**消费方(DSH)读到终止事件就停止取值**,我们拿不到 `item.done`,`complete` 永远是 `false`,
|
|
52
|
+
于是每一轮结束时这个会话都被 `retireSession + cleanup`(**弃用并删除**)、链也记不上
|
|
53
|
+
⇒ 下一轮只能再新建一个会话。用户看到的就是"每轮一个新会话 + 旧会话在网页端消失"。
|
|
54
|
+
|
|
55
|
+
插桩记录(`~/.dsh/web-login/diag-feed.jsonl`)是决定性证据:同一个归属键下
|
|
56
|
+
`命中旧槽=false → NEW session=…` 连着三轮,而中间那一轮 `命中旧槽=true → feed chained chars=133`
|
|
57
|
+
—— 同一份代码里两种结果都有,说明不是"永远连不上",而是成功的那一轮也被判成没跑完。
|
|
58
|
+
|
|
59
|
+
### 修法
|
|
60
|
+
|
|
61
|
+
1. **认服务端的显式终态**:`kind:'finish'`(`[DONE]` 时解析器补发的收尾事件)或
|
|
62
|
+
`response/status: FINISHED` 一到,`sawTerminal = true`;收尾判据改成
|
|
63
|
+
`roundOk = complete || sawTerminal`(会话保留 + 链记账都用它)。
|
|
64
|
+
这与项目既有纪律一致("SSE 判卡住要用显式终态,不看有没有字节")。
|
|
65
|
+
2. **N04 的意图不变**:真的提前中断(没等到终态)仍要退役会话 —— 那个会话可能停在半路。
|
|
66
|
+
用例一正一反把这个边界钉住了。
|
|
67
|
+
3. **加持久可见性**:收尾退役时记下原因(`extra-session` / `poisoned` / `not-finished` / `rotated`),
|
|
68
|
+
挂在 `GET /context-mode` 的 `chain.lastRetire` 上 —— 这类"每轮新建会话"下次不用再插桩。
|
|
69
|
+
|
|
70
|
+
用例:`check-context-chain` 新增两条(消费方读完终态就停 ⇒ 会话保留+链记上;终止前就停 ⇒ 仍退役),
|
|
71
|
+
**并做了反向验证**:把修复退回去(`roundOk = complete`)第一条立刻变红,改回来即绿。
|
|
72
|
+
|
|
73
|
+
### 排查过程留下的工具
|
|
74
|
+
|
|
75
|
+
`dev/patch-diag.mjs`:往**已安装产物**里插 6 处只读诊断(不用发版/不占装机周期就能拿到
|
|
76
|
+
"每轮决策原因、租用键、是否新建会话、head 从第几个字符开始不同")。两个坑已写在脚本注释里:
|
|
77
|
+
对象最后一个属性没有尾逗号(逗号要放开头)、备份源不能拿目标文件自己。
|
|
78
|
+
|
|
5
79
|
## 0.6.15 — 2026-10-01
|
|
6
80
|
|
|
7
81
|
**界面两处修正(用户反馈):「一键重登」搬到账号库;删掉一堆误导性的"注释"。**
|