From 68f3f8b12d78e8e7e2ce070fd3ed3142b100ba44 Mon Sep 17 00:00:00 2001 From: Dmatut7 <2966283641@qq.com> Date: Sun, 14 Jun 2026 00:02:38 +0800 Subject: [PATCH] fix(vis): report cumulative session tokens in Context tab token bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `projectContext` partitioned each `usage.record` into either `byScope.session` or `byScope.turn` by its `usageScope` field. But agent-core's main loop records every step with scope 'turn' (only the rare compaction/replay paths use 'session'), so `byScope.session` stayed near-empty — and the Context tab token bar reads `byScope.session`, so it under-reported (often showed nothing) for normal sessions. Make `byScope.session` the cumulative session total (every record, matching agent-core's UsageRecorder.total / byModel) and keep `byScope.turn` as the turn-scoped subset. Extends the existing projector test with a byScope.session assertion (was {0,0,0,0} before, now the cumulative total). Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/vis/server/src/lib/context-projector.ts | 10 ++++++++-- apps/vis/server/test/lib/context-projector.test.ts | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/apps/vis/server/src/lib/context-projector.ts b/apps/vis/server/src/lib/context-projector.ts index 81569f9e3..57372bc96 100644 --- a/apps/vis/server/src/lib/context-projector.ts +++ b/apps/vis/server/src/lib/context-projector.ts @@ -170,8 +170,14 @@ export function projectContext(entries: ReadonlyArray): ContextProjec }]; break; case 'usage.record': { - const scope = (rec.usageScope ?? 'session') as 'session' | 'turn'; - addUsage(usage.byScope[scope], rec.usage); + // `byScope.session` is the cumulative session total — every usage + // record, matching agent-core's UsageRecorder.total / byModel — while + // `byScope.turn` is the turn-scoped subset. The main agent loop records + // every step as 'turn', so partitioning records into one bucket OR the + // other left `byScope.session` near-empty and under-reported the Context + // tab token bar, which reads `byScope.session`. + addUsage(usage.byScope.session, rec.usage); + if ((rec.usageScope ?? 'session') === 'turn') addUsage(usage.byScope.turn, rec.usage); if (!usage.byModel[rec.model]) usage.byModel[rec.model] = { ...ZERO }; addUsage(usage.byModel[rec.model]!, rec.usage); break; diff --git a/apps/vis/server/test/lib/context-projector.test.ts b/apps/vis/server/test/lib/context-projector.test.ts index 1d63f1d85..014dd7d75 100644 --- a/apps/vis/server/test/lib/context-projector.test.ts +++ b/apps/vis/server/test/lib/context-projector.test.ts @@ -25,6 +25,13 @@ describe('context-projector', () => { expect(proj.usage.byScope.turn).toEqual({ inputOther: 10, output: 5, inputCacheRead: 0, inputCacheCreation: 0, }); + // `byScope.session` is the cumulative session total — the sum of every + // usage record (matching `byModel`), not just records explicitly scoped + // 'session'. The main loop records every step as 'turn', so before the fix + // this bucket stayed {0,0,0,0} and the Context tab token bar read empty. + expect(proj.usage.byScope.session).toEqual({ + inputOther: 10, output: 5, inputCacheRead: 0, inputCacheCreation: 0, + }); expect(proj.usage.byModel['kimi-k2']).toEqual({ inputOther: 10, output: 5, inputCacheRead: 0, inputCacheCreation: 0, });