jbc-dssi 1.1.1 → 1.1.3
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
|
@@ -99,6 +99,24 @@ function sumUsage(acc, u) {
|
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/**
|
|
103
|
+
* 把落库的「逐步用量」数组合成一行用量 —— **读侧唯一口径**(2026-11-01 存储结构修复)。
|
|
104
|
+
*
|
|
105
|
+
* 只在记录带 `stepUsages`(新格式)时使用。旧记录没这个数组,调用方必须原样使用
|
|
106
|
+
* 历史 `usage`,**不允许**拿它去"猜"或"补" —— 按负责人决定历史不救、不做回填。
|
|
107
|
+
*
|
|
108
|
+
* 返回 null:整轮一条有效用量都没有(老 DSH / 这轮没统计到)→ 手机侧不显示用量项。
|
|
109
|
+
*/
|
|
110
|
+
function aggregateStepUsages(stepUsages) {
|
|
111
|
+
if (!Array.isArray(stepUsages)) return null;
|
|
112
|
+
let acc = null;
|
|
113
|
+
for (const one of stepUsages) {
|
|
114
|
+
const u = normalizeUsage(one);
|
|
115
|
+
if (u) acc = sumUsage(acc, u);
|
|
116
|
+
}
|
|
117
|
+
return acc;
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
/**
|
|
103
121
|
* @param {object} opts
|
|
104
122
|
* @param {object} opts.ctx DSH 上下文(sessionController 公开方法)
|
|
@@ -158,7 +176,11 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
158
176
|
|
|
159
177
|
/**
|
|
160
178
|
* 投递一轮给一个成员,等回复完成后 settle。
|
|
161
|
-
*
|
|
179
|
+
*
|
|
180
|
+
* @returns {Promise<{text?:string, failed?:string, missed?:boolean,
|
|
181
|
+
* usage?:object|null, steps?:number, stepUsages?:Array<object>}>}
|
|
182
|
+
* `stepUsages` = 本轮每一步的用量(每一步一条,按到达顺序);它和 `usage`
|
|
183
|
+
* (各步求和)一起进房间日志,供读侧还原与兼容老客户端。
|
|
162
184
|
*/
|
|
163
185
|
function deliver(group, member, prompt, attachments = {}) {
|
|
164
186
|
return new Promise((resolve) => {
|
|
@@ -191,6 +213,14 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
191
213
|
* 于是「共 N 步」配的是"最后一步"的 token,步数越多的轮次少算越多。
|
|
192
214
|
*/
|
|
193
215
|
let turnUsage = null;
|
|
216
|
+
/*
|
|
217
|
+
* 本轮**逐步**用量(2026-11-01 新增):每一步一条,与 turnUsage 同源。
|
|
218
|
+
*
|
|
219
|
+
* 为什么存这个:旧存储只留聚合值,刷新/重进后无法还原「每一步花了多少」,
|
|
220
|
+
* 历史记录也就永远只能信当时写下的那个数。逐步入库后,读侧可以用它求和还原 ——
|
|
221
|
+
* 面板在实时、刷新、重进、换端任何时刻都是同一份数据的计算结果。
|
|
222
|
+
*/
|
|
223
|
+
const stepUsages = [];
|
|
194
224
|
/*
|
|
195
225
|
* 「共 N 步」的账:turn → 这一轮出现过的 step 号集合。
|
|
196
226
|
*
|
|
@@ -261,13 +291,21 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
261
291
|
// 工具调用那几步没有 text,不能拿它们当回答;有正文才覆盖。
|
|
262
292
|
const text = assistantText(event);
|
|
263
293
|
if (text) lastText = text;
|
|
264
|
-
const usage = normalizeUsage(data.usage);
|
|
265
|
-
if (usage) turnUsage = sumUsage(turnUsage, usage);
|
|
266
294
|
/*
|
|
267
295
|
* 步数:**所有** assistant/message 都要记,包括只调工具、不画块的那几步
|
|
268
296
|
* (与单聊一致 —— token 大头正是这些步骤花掉的)。
|
|
269
297
|
*/
|
|
270
298
|
const step = typeof data.step === 'number' ? data.step : -1;
|
|
299
|
+
const usage = normalizeUsage(data.usage);
|
|
300
|
+
if (usage) {
|
|
301
|
+
/*
|
|
302
|
+
* 逐步入库:步号 + 这一步的五个 token 字段。
|
|
303
|
+
* 同一步重试会各存一条(用量按 attempt 累加,与单聊/Web 一致),
|
|
304
|
+
* 步数仍由 turnStepNums 按 step 号去重,两者互不影响。
|
|
305
|
+
*/
|
|
306
|
+
stepUsages.push({ step, ...usage });
|
|
307
|
+
turnUsage = sumUsage(turnUsage, usage);
|
|
308
|
+
}
|
|
271
309
|
if (step >= 0 && typeof data.turn === 'number') {
|
|
272
310
|
if (!turnStepNums.has(data.turn)) turnStepNums.set(data.turn, new Set());
|
|
273
311
|
turnStepNums.get(data.turn).add(step);
|
|
@@ -283,7 +321,7 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
283
321
|
*/
|
|
284
322
|
const endTurn = typeof data.turn === 'number' ? data.turn : lastTurn;
|
|
285
323
|
const steps = turnStepNums.get(endTurn)?.size ?? 0;
|
|
286
|
-
settle({ text: lastText, usage: turnUsage, steps });
|
|
324
|
+
settle({ text: lastText, usage: turnUsage, steps, stepUsages });
|
|
287
325
|
}
|
|
288
326
|
ac.abort();
|
|
289
327
|
} else if (event?.type === 'turn/error' || event?.type === 'turn/failed') {
|
|
@@ -342,7 +380,21 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
342
380
|
});
|
|
343
381
|
}
|
|
344
382
|
|
|
345
|
-
/**
|
|
383
|
+
/**
|
|
384
|
+
* 把一次投递的结果落成房间行(成员/主管同一套:手机侧按 memberId 显示名字与主管标)。
|
|
385
|
+
*
|
|
386
|
+
* 房间行里的「本轮用量」有两种格式,**读侧必须都认**:
|
|
387
|
+
*
|
|
388
|
+
* 旧格式(2026-10-31 及以前落盘的行,只保留聚合值、无法重算):
|
|
389
|
+
* { usage: {inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, totalTokens}, steps: 10 }
|
|
390
|
+
* 新格式(2026-11-01 起,多一个逐步数组):
|
|
391
|
+
* { usage: {...恒等于逐步求和...}, steps: 10,
|
|
392
|
+
* stepUsages: [{ step: 1, inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, totalTokens }, ...] }
|
|
393
|
+
*
|
|
394
|
+
* `usage` 新格式里照写:给还没升级的老手机读(它们只认这个字段)。
|
|
395
|
+
* 新手机的 GroupStore 优先用 `stepUsages` 求和 —— 刷新/重进后与实时同源。
|
|
396
|
+
* 旧行没有 `stepUsages`:读侧原样显示历史值,不补 0、不重算、不报错(历史不救)。
|
|
397
|
+
*/
|
|
346
398
|
function emitReplyLine(group, round, member, result) {
|
|
347
399
|
const text = String(result.text ?? '').trim() || '[未回应]';
|
|
348
400
|
emitLine(group.id, {
|
|
@@ -353,6 +405,10 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
353
405
|
text,
|
|
354
406
|
usage: result.usage ?? null,
|
|
355
407
|
steps: result.steps ?? 0,
|
|
408
|
+
// 只有真的收到过 usage 才写这个字段;否则 JSON 里不出现(= 老格式,读侧回落)
|
|
409
|
+
stepUsages: Array.isArray(result.stepUsages) && result.stepUsages.length > 0
|
|
410
|
+
? result.stepUsages
|
|
411
|
+
: undefined,
|
|
356
412
|
round: round?.rounds ?? 0,
|
|
357
413
|
});
|
|
358
414
|
round.totalTurns += 1;
|
|
@@ -594,9 +650,21 @@ export function createRoundEngine({ ctx, state, dssAgent, log, save, broadcast }
|
|
|
594
650
|
}
|
|
595
651
|
}
|
|
596
652
|
|
|
597
|
-
/**
|
|
653
|
+
/**
|
|
654
|
+
* 打开群聊页时拉房间历史。
|
|
655
|
+
*
|
|
656
|
+
* 【读侧口径(2026-11-01)】
|
|
657
|
+
* 带 `stepUsages` 的新记录:用量由逐步数据**当场求和**再下发 —— 刷新/重进拿到的
|
|
658
|
+
* 值和实时那一刻完全同源(这份和也是 `usage` 字段的来源,二者恒等)。
|
|
659
|
+
* 没有 `stepUsages` 的旧记录:**原样返回**,显示当时写下的历史值。按负责人决定
|
|
660
|
+
* 历史不救 —— 这里不猜、不补 0、不拿别的字段假装重算。
|
|
661
|
+
*/
|
|
598
662
|
function roomSnapshot(group) {
|
|
599
|
-
return (state.rooms[group.id] ?? []).slice(-ROOM_LOG_MAX)
|
|
663
|
+
return (state.rooms[group.id] ?? []).slice(-ROOM_LOG_MAX).map((line) => {
|
|
664
|
+
if (!Array.isArray(line?.stepUsages) || line.stepUsages.length === 0) return line;
|
|
665
|
+
const usage = aggregateStepUsages(line.stepUsages);
|
|
666
|
+
return usage ? { ...line, usage } : line;
|
|
667
|
+
});
|
|
600
668
|
}
|
|
601
669
|
|
|
602
670
|
return { handleUserMessage, roomSnapshot, ensureGroupSession };
|