dsh-deepseek-web-login 0.6.34 → 0.6.36

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,74 @@
2
2
 
3
3
  本项目大致遵循语义化版本;日期为本地时间。
4
4
 
5
+ ## 0.6.36 — 2026-10-02
6
+
7
+ **把"提示词里到底有什么"变成可查的事实(诊断),并顺带给出这次现场的完整核对结论。**
8
+
9
+ 用户反复问「是不是把答案直接告诉模型了」—— 这个问题**只靠字符数回答不了**:一个 25k 的提示词
10
+ 既可能是"把模型的旧回答又发了一遍"(缺陷),也可能是"工具返回"(**正常且必要**)。
11
+ 两者在网页端看起来一模一样,但一个是 bug、另一个是机制。所以每轮额外落盘**结构计数**:
12
+
13
+ ```
14
+ "stats": { "assistant": 0, "user": 1, "toolResult": 1, "systemBlocks": 0 }
15
+ ```
16
+
17
+ `assistant > 0` 才是"把模型自己说过的话又发了一遍"。以后不用读分享页**估**,直接查这个文件。
18
+
19
+ **本次现场的核对结论**(`dev/replay-turn-prompts.mjs` 新增,用会话日志重放**真实发出去的**提示词):
20
+
21
+ | 轮次 | 实发字符 | 里面有什么 |
22
+ |---|---|---|
23
+ | "现在几点了" | **11** | 只有 `User: 现在几点了` |
24
+ | 下一轮 | **12** | 只有新增那一条 |
25
+ | 天气那轮的搜索返回 | 25491 | `[Tool Result for call_…]`(工具返回,必须回灌) |
26
+
27
+ **真实发送里 `Assistant:` 是 0 条** —— 模型的旧回答没有被发回去。
28
+ 分享页里能看到的 `[Tool Result for call_055551695bfc4f82b3e9] 2026-10-02 19:34:10 星期五`
29
+ **正是 0.6.35 生效的证据**(改之前这里会是 `User: 2026-10-02 19:34:10 星期五`);
30
+ `Assistant: ` 前缀 0 次、`Tool Calling Protocol` 只出现 1 次(没有重复的固定头)。
31
+
32
+ > ⚠️ 说明一件事,免得再被误读:**"网页端的提示词里出现了时间/天气"本身不是 bug** ——
33
+ > 那是 agent 自己调了 `Get-Date` / `web_fetch`,工具输出必须回灌,否则模型无从得知。
34
+ > 判断标准只有一条:**它是 `[Tool Result for …]`(正常)还是 `User: …`(缺陷)**。
35
+
36
+ **新增** `dev/replay-turn-prompts.mjs`:把某会话每一轮真实发出去的提示词重放出来并给出结构统计。
37
+ 以后再遇到"提示词里有什么"的疑问,一条命令即可,不必依赖分享页的二手转述。
38
+
39
+ ## 0.6.35 — 2026-10-02
40
+
41
+ **纠正 0.6.34:真正的原因是 DSH 的工具返回是 `role: "tool"`,而我们没有这个分支。**
42
+
43
+ 0.6.34 我按"工具返回被折进一条普通 user 文本"去修的(判据是"assistant 发过工具调用 ⇒ 紧随的
44
+ user 文本就是返回")。**那个推断是猜的,而且我的证据本身是错的** —— 我用的
45
+ `dev/dump-turn-input.mjs` 只打了 `user/message` / `assistant/message` / `request/header` / `step/end`
46
+ **四种事件**,而工具返回记在第五种里:
47
+
48
+ ```
49
+ type=tool/result {"message":{"role":"tool",
50
+ "toolCallId":"call_c2cf288c12734112b11e",
51
+ "content":[{"type":"text","text":"2026-10-02 18:54:28 星期五\r\n"}],"isError":false}}
52
+ ```
53
+
54
+ **`role: "tool"`** —— 不是 `role:'user'`,也不是 `tool-result` 块(测试夹具里长的是后者,真机不是)。
55
+ 我们原来**没有 `tool` 这个分支**,于是它掉进 user 分支 ⇒ 渲染成
56
+ `User: 2026-10-02 18:54:28 星期五` ⇒ 模型以为"用户告诉了我时间"(它的思考原话:
57
+ 「**我没拿到工具结果,用户直接给了时间**。那就接受。」)⇒ 回答变成「收到,…」。
58
+
59
+ **改法(这次是有证据的)**:`serializePromptParts` 增加 `role === 'tool'` 分支,
60
+ 用消息**自带的** `toolCallId` 与 `isError` 标成 `[Tool Result for <id>]`,
61
+ 并清掉 0.6.34 那条"预期下一个 user 文本是工具返回"的待办。
62
+ 0.6.34 的推断**保留为次要防线**(注释已改写,明确它不是主要依据),因为两种形状的期望输出一致、
63
+ 留着能覆盖我没能证伪的那种形状;且主分支会先清掉待办,它不会再误触发。
64
+
65
+ **顺带修掉那个把我带偏的工具**:`dev/dump-turn-input.mjs` 增加 `tool/call` / `tool/result` 分支 ——
66
+ **看不见工具返回的诊断,比没有诊断更危险**(它让我在错误前提上写了一版修复)。
67
+
68
+ **用例 69 项**(新增 4 条,直接用手机会话日志里的确切形状)。
69
+ ⚠️ 写这 4 条时踩了一次**虚守卫**:第一版把 assistant 侧的调用 id 与 `toolCallId` 写成**同一个值**,
70
+ 于是关掉主分支时次要防线给出同样结果、用例**照样全绿**(变异只红 2 条而不是 4 条)。
71
+ 把两边的 id 改成不同值后,变异才真正红 4 条 —— 又一次"两个来源同一个值就测不出真伪"。
72
+
5
73
  ## 0.6.34 — 2026-10-02
6
74
 
7
75
  **修复:工具返回被当成「用户说的话」发给模型 —— 所以它回「收到,…」而不是回答问题。**
package/lib/index.js CHANGED
@@ -1893,16 +1893,15 @@ function serializePromptParts(options) {
1893
1893
  const protocol = toolSection ? `\n\n${protocolText}${toolSection}` : "";
1894
1894
  const lines = [];
1895
1895
  /**
1896
- * 上一条 assistant 消息里的工具调用 id —— 用来把**紧随其后的那条 user 文本**认成工具返回。
1896
+ * ⚠️ **次要防线**(主路径是下面 `role === 'tool'` 那一段 —— 那才是有证据的权威形状)。
1897
1897
  *
1898
- * 🔴 2026-10-02 现场(用户报「提示词把答案直接告诉模型了,所以它回『收到,…』」):
1899
- * DSH 执行 `pwsh` 之后,把工具输出当成一条**普通的 user 文本消息**交给我们,于是我们照实
1900
- * 渲染成 `User: 2026-10-02 18:54:28 星期五` —— 模型读到的是"用户告诉了我时间",
1901
- * 它自己的思考原话就是:「**我没拿到工具结果,用户直接给了时间**。那就接受。」
1902
- * 回答于是从"回答几点"变成"收到,…" —— 看着就像在复述一个已知答案。
1898
+ * 这里兜的是另一种可能存在的形状:**工具返回被折进一条普通 `user` 文本消息**。
1899
+ * 判据:在 agent 循环里 assistant 发出工具调用后**必须先有工具返回**才轮得到下一条用户输入,
1900
+ * 所以紧跟其后的那条 user 文本只可能是工具返回。
1903
1901
  *
1904
- * 判据为什么成立:在 agent 循环里,assistant 发出工具调用之后**必须先有工具返回**,
1905
- * 才轮得到下一条用户输入。所以紧跟其后的那条 user 文本,按构造只能是工具返回。
1902
+ * ⚠️ 不要把它当成主要依据 —— 2026-10-02 我先用这个推断去修,后来读会话日志才发现
1903
+ * 真机用的是 `role:'tool'`。推断能修好只是**碰巧**(两种形状的期望输出一致)。
1904
+ * 主路径落地后 `pendingToolCallIds` 会被清空,这里不会再误触发。
1906
1905
  */
1907
1906
  let pendingToolCallIds = [];
1908
1907
  for (const message of options.messages ?? []) {
@@ -1921,6 +1920,13 @@ function serializePromptParts(options) {
1921
1920
  else if (text.trim()) lines.push(`Assistant: ${text}`);
1922
1921
  continue;
1923
1922
  }
1923
+ if (message.role === "tool") {
1924
+ const body = flattenText(blocks).join("") || "(no output)";
1925
+ const errorMark = message.isError === true ? " [ERROR]" : "";
1926
+ lines.push(`[Tool Result${errorMark} for ${String(message.toolCallId ?? "")}]\n${body}`);
1927
+ pendingToolCallIds = [];
1928
+ continue;
1929
+ }
1924
1930
  const toolResults = blocks.filter((block) => block?.type === "tool-result");
1925
1931
  const text = flattenText(blocks.filter((block) => block?.type !== "tool-result")).join("");
1926
1932
  const imageMarks = blockImageMarks(blocks, options.keptImageKeys);
@@ -5572,6 +5578,12 @@ async function openCompletion(auth, params, signal, transport, keepIds) {
5572
5578
  promptChars: feed.prompt.length,
5573
5579
  headChars: params.promptParts ? String(params.promptParts.head ?? "").length : null,
5574
5580
  firstDiff: !chainEntries || !currentEntries ? null : firstDifference(chainEntries, currentEntries),
5581
+ stats: {
5582
+ assistant: (feed.prompt.match(/^Assistant: /gm) ?? []).length,
5583
+ user: (feed.prompt.match(/^User: /gm) ?? []).length,
5584
+ toolResult: (feed.prompt.match(/^\[Tool Result/gm) ?? []).length,
5585
+ systemBlocks: (feed.prompt.match(/^\[System\]/gm) ?? []).length
5586
+ },
5575
5587
  tailSame: !chainEntries || !currentEntries ? null : currentEntries.length <= chainEntries.length ? false : currentEntries[chainEntries.length - 1] === chainEntries[chainEntries.length - 1]
5576
5588
  });
5577
5589
  }
@@ -10442,7 +10454,7 @@ async function checkForUpdate(current, fetchImpl) {
10442
10454
  * 兜底常量与 package.json 的一致性由 `tests/check-smoke.mjs` 守着,不会漂。
10443
10455
  */
10444
10456
  /** 与 package.json 保持一致的兜底版本(由测试保证不会漂)。 */
10445
- const FALLBACK_VERSION = "0.6.34";
10457
+ const FALLBACK_VERSION = "0.6.36";
10446
10458
  let cached;
10447
10459
  /** 本插件版本(如 `0.1.26`)。 */
10448
10460
  function pluginVersion() {