Skip to content

Commit f079119

Browse files
committed
fix: return preserved totalTokens from resolveFreshSessionTotalTokens (fixes #82900)
1 parent 800a0d3 commit f079119

8 files changed

Lines changed: 16 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
2626
- QA-Lab: add the personal-agent approval-denial scenario so the benchmark pack verifies denied local reads stop cleanly without tool progress or fixture leaks. (#83150) Thanks @iFiras-Max1.
2727

2828
### Fixes
29+
- Agents/sessions: return preserved totalTokens from resolveFreshSessionTotalTokens even when stale, so /context and Control UI context meter show correct utilization without affecting compaction or memory flush. Fixes #82900. (#82919) Thanks @njuboy11.
2930

3031
- Feishu: return bound subagent delivery origins from session thread setup so Feishu subagent completions route back to the same DM or topic. (#83190) Thanks @100menotu001.
3132
- CLI/update: tailor post-update Gateway recovery hints by platform, showing systemd, LaunchAgent, Scheduled Task, or generic service-manager guidance instead of macOS-only recovery text. (#83096) Thanks @rubencu.

src/auto-reply/reply/commands-context-report.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ describe("buildContextReply", () => {
154154
}),
155155
);
156156
expect(result.text).toContain("Tracked prompt estimate: 1,020 chars (~255 tok)");
157-
expect(result.text).toContain("Actual context usage (cached): unavailable");
158-
expect(result.text).toContain("Session tokens (cached): unknown / ctx=8,192");
159-
expect(result.text).not.toContain("~645 tok");
157+
expect(result.text).toContain("Actual context usage (cached): 900 tok");
158+
expect(result.text).toContain("Session tokens (cached): 900 total / ctx=8,192");
159+
expect(result.text).toContain("Untracked provider/runtime overhead: ~645 tok");
160160
});
161161

162162
it("prefers the target session entry from sessionStore for cached context stats", async () => {

src/auto-reply/reply/memory-flush.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function resolveMemoryFlushGateState<
5050
}
5151

5252
const totalTokens =
53-
resolvePositiveTokenCount(params.tokenCount) ?? resolveFreshSessionTotalTokens(params.entry);
53+
resolvePositiveTokenCount(params.tokenCount) ?? (params.entry?.totalTokensFresh === false ? undefined : resolveFreshSessionTotalTokens(params.entry));
5454
if (!totalTokens || totalTokens <= 0) {
5555
return null;
5656
}

src/auto-reply/reply/session-fork.runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export async function resolveParentForkTokenCountRuntime(params: {
7070
storePath: string;
7171
}): Promise<number | undefined> {
7272
const freshPersistedTokens = resolveFreshSessionTotalTokens(params.parentEntry);
73-
if (typeof freshPersistedTokens === "number") {
73+
if (typeof freshPersistedTokens === "number" && params.parentEntry.totalTokensFresh !== false) {
7474
return freshPersistedTokens;
7575
}
7676

src/auto-reply/status.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ describe("buildStatusMessage", () => {
128128
});
129129
const normalized = normalizeTestText(text);
130130

131-
expect(normalized).toContain("Context: ?/1.0m");
132-
expect(normalized).not.toContain("Context: 3.8m/1.0m");
131+
expect(normalized).toContain("Context: 3.8m/1.0m");
132+
expect(normalized).not.toContain("Context: ?/1.0m");
133133
});
134134

135135
it("shows sanitized TTS provider details in the voice status line", async () => {
@@ -1585,8 +1585,8 @@ describe("buildStatusMessage", () => {
15851585
});
15861586
const normalized = normalizeTestText(text);
15871587

1588-
expect(normalized).toContain("Context: ?/1.0m");
1589-
expect(normalized).not.toContain("Context: 3.8m/1.0m");
1588+
expect(normalized).toContain("Context: 3.8m/1.0m");
1589+
expect(normalized).not.toContain("Context: ?/1.0m");
15901590
expect(normalized).not.toContain("Context: 3.82m/1.0m");
15911591
},
15921592
{ prefix: "openclaw-status-" },

src/config/sessions/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,16 +550,16 @@ export function resolveFreshSessionTotalTokens(
550550
if (total === undefined) {
551551
return undefined;
552552
}
553-
if (entry?.totalTokensFresh === false) {
554-
return undefined;
555-
}
553+
// PR #82578 ensured totalTokens is preserved across stale usage updates
554+
// instead of being corrupted to undefined. totalTokensFresh=false only
555+
// means "possibly slightly stale", not "unavailable".
556556
return total;
557557
}
558558

559559
export function isSessionTotalTokensFresh(
560560
entry?: Pick<SessionEntry, "totalTokens" | "totalTokensFresh"> | null,
561561
): boolean {
562-
return resolveFreshSessionTotalTokens(entry) !== undefined;
562+
return resolveSessionTotalTokens(entry) !== undefined && entry?.totalTokensFresh !== false;
563563
}
564564

565565
export type GroupKeyResolution = {

src/gateway/session-utils.search.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ describe("listSessionsFromStore search", () => {
282282
const missing = result.sessions.find((row) => row.key === "agent:main:missing");
283283
expect(fresh?.totalTokens).toBe(1200);
284284
expect(fresh?.totalTokensFresh).toBe(true);
285-
expect(stale?.totalTokens).toBeUndefined();
285+
expect(stale?.totalTokens).toBe(2200);
286286
expect(stale?.totalTokensFresh).toBe(false);
287287
expect(missing?.totalTokens).toBeUndefined();
288288
expect(missing?.totalTokensFresh).toBe(false);

src/gateway/session-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ export function buildGatewaySessionRow(params: {
18011801
resolvePositiveNumber(resolveFreshSessionTotalTokens(entry)) ??
18021802
resolvePositiveNumber(transcriptUsage?.totalTokens);
18031803
const totalTokensFresh =
1804-
typeof totalTokens === "number" && Number.isFinite(totalTokens) && totalTokens > 0
1804+
typeof totalTokens === "number" && Number.isFinite(totalTokens) && totalTokens > 0 && entry?.totalTokensFresh !== false
18051805
? true
18061806
: transcriptUsage?.totalTokensFresh === true;
18071807
const childSessions = params.storeChildSessionsByKey

0 commit comments

Comments
 (0)