jbc-dssi 1.1.0 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jbc-dssi",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "鲸编程 - 不只是手机遥控操作电脑,而是将电脑级的Agent能力装进手机",
6
6
  "keywords": [
@@ -71,6 +71,34 @@ function normalizeUsage(usage) {
71
71
  return any ? out : null;
72
72
  }
73
73
 
74
+ /**
75
+ * 把一次模型调用的 usage 累加进本轮 —— **2026-10-31 修的就是这里**。
76
+ *
77
+ * 【为什么必须累加】
78
+ * 一个 turn 会被拆成多个 step,**每一步都发一条 assistant/message、各带这一步的
79
+ * usage**。旧实现 `lastUsage = usage` 只留最后一条,于是面板出现自相矛盾的数字:
80
+ * 「共 10 步」却只有 60,686 tok —— 而第 10 步单独就 60,686(59,008+240+1,438),
81
+ * 前 9 步全丢。真机那一轮(2026-10-31 21:26:57~21:27:45,群会话 session-66663e11)
82
+ * 逐步核对:10 步合计 539,775 tok(缓存命中 521,728 / 未命中 9,159 / 输出 8,888),
83
+ * 谷价 ≈¥0.0551;旧口径只显示 60,686 tok / ≈¥0.0072,少算约 9 步。
84
+ *
85
+ * 【口径】与单聊(`android/.../data/Transcript.kt` 的 `addUsage`)和 Web UI 的
86
+ * `deriveTurnTokenUsage` 完全一致:每条 assistant/message 的 usage 各自相加;
87
+ * totalTokens 也逐条相加,**不**用 input+output 重算(会与 Web 差出数字)。
88
+ * 同一 step 的重试会产生多条 assistant/message:用量按 attempt 累加(与单聊一致),
89
+ * 步数则由调用方按 step 号去重。
90
+ */
91
+ function sumUsage(acc, u) {
92
+ if (!acc) return u;
93
+ return {
94
+ inputTokens: acc.inputTokens + u.inputTokens,
95
+ outputTokens: acc.outputTokens + u.outputTokens,
96
+ cacheReadTokens: acc.cacheReadTokens + u.cacheReadTokens,
97
+ cacheWriteTokens: acc.cacheWriteTokens + u.cacheWriteTokens,
98
+ totalTokens: acc.totalTokens + u.totalTokens,
99
+ };
100
+ }
101
+
74
102
  /**
75
103
  * @param {object} opts
76
104
  * @param {object} opts.ctx DSH 上下文(sessionController 公开方法)
@@ -156,7 +184,13 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
156
184
  let prompted = false;
157
185
  let minTurn = null;
158
186
  let lastText = '';
159
- let lastUsage = null;
187
+ /*
188
+ * 本轮用量 = 各 step 的 usage **累加**(见 [sumUsage])。
189
+ *
190
+ * 2026-10-31 之前这里是 `lastUsage`(只留最后一条 assistant/message),
191
+ * 于是「共 N 步」配的是"最后一步"的 token,步数越多的轮次少算越多。
192
+ */
193
+ let turnUsage = null;
160
194
  /*
161
195
  * 「共 N 步」的账:turn → 这一轮出现过的 step 号集合。
162
196
  *
@@ -228,7 +262,7 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
228
262
  const text = assistantText(event);
229
263
  if (text) lastText = text;
230
264
  const usage = normalizeUsage(data.usage);
231
- if (usage) lastUsage = usage;
265
+ if (usage) turnUsage = sumUsage(turnUsage, usage);
232
266
  /*
233
267
  * 步数:**所有** assistant/message 都要记,包括只调工具、不画块的那几步
234
268
  * (与单聊一致 —— token 大头正是这些步骤花掉的)。
@@ -249,7 +283,7 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
249
283
  */
250
284
  const endTurn = typeof data.turn === 'number' ? data.turn : lastTurn;
251
285
  const steps = turnStepNums.get(endTurn)?.size ?? 0;
252
- settle({ text: lastText, usage: lastUsage, steps });
286
+ settle({ text: lastText, usage: turnUsage, steps });
253
287
  }
254
288
  ac.abort();
255
289
  } else if (event?.type === 'turn/error' || event?.type === 'turn/failed') {