openclaw - ✅(Solved) Fix Control UI status bar shows '0% ctx' when actual session context is 44% — contextPercent ignores cacheRead [2 pull requests, 3 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#70491Fetched 2026-04-24 05:57:23
View on GitHub
Comments
3
Participants
2
Timeline
8
Reactions
0
Author
Timeline (top)
commented ×3cross-referenced ×2referenced ×2closed ×1

The Control UI message-status bar shows 0% ctx even when the actual session context window is at 44% utilization (442k of 1.0m tokens for claude-opus-4-7). This is misleading — users think they have plenty of context headroom and don't compact in time, then hit unexpected limits.

The /status slash command correctly reports Context: 442k/1.0m (44%) · 🧹 Compactions: 0. So the server-side accounting is right; the bug is purely in the UI's local computation of contextPercent.


Root Cause

In dist/control-ui/assets/index-Bsj0vinf.js, the per-message metadata aggregator computes contextPercent from inputTokens only, ignoring cacheRead:

let { message: t } of e.messages) {
  let e = t;
  if (e.role !== `assistant`) continue;
  let l = e.usage;
  l && (
    c = !0,
    n += l.input ?? l.inputTokens ?? 0,            // ← n = sum of inputs (per-turn delta after cache hit)
    r += l.output ?? l.outputTokens ?? 0,
    i += l.cacheRead ?? l.cache_read_input_tokens ?? 0,    // ← cacheRead computed but ignored
    a += l.cacheWrite ?? l.cache_creation_input_tokens ?? 0
  );
  // ...
}
// ↓ BUG: n is delta input tokens, not total context consumed
let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
return { input: n, output: r, cacheRead: i, cacheWrite: a, cost: o, model: s, contextPercent: l };

When using prompt-cache aggressively (every modern Claude session does), inputTokens per turn is just the small delta after cache hit (e.g. 6 tokens), while cacheRead accumulates the actual tokens consuming context budget (e.g. 440k).

So:

  • UI computes: 6 / 1_000_000 * 100 ≈ 0.0006% → rounded to 0%
  • Reality: (6 + 440_000) / 1_000_000 = 44%

Fix Action

Workaround

Run /status periodically — it shows the true Context: % and Compactions: count.


PR fix notes

PR #70532: fix(ui): include cached tokens in context usage

Description (problem / solution / changelog)

Summary

Fixes #70491.

The Control UI assistant message footer already collects input, output, cacheRead, and cacheWrite, but the % ctx calculation only used input. For cached providers, input is often just the per-turn delta after a cache hit, so long Claude/OpenAI sessions could show 0% ctx while /status reported substantial context use.

This PR keeps the change scoped to the footer metadata calculation:

  • Compute contextPercent from prompt/context tokens: input + cacheRead + cacheWrite.
  • Keep completion/output tokens visible in the footer, but exclude them from % ctx so long completions do not inflate prompt occupancy.
  • Add jsdom regression coverage for both cached prompt tokens and completion-heavy responses.
  • Add a changelog entry for the user-visible fix.

AI-assisted: yes, Codex.

Screenshots

No screenshot attached. This is a computed footer value change; the regression test renders the footer and asserts the visible 44% ctx text for the cached-token case.

Test plan

  • pnpm exec vitest run ui/src/ui/chat/grouped-render.test.ts --config test/vitest/vitest.unit.config.ts
  • pnpm exec oxfmt --check CHANGELOG.md ui/src/ui/chat/grouped-render.ts ui/src/ui/chat/grouped-render.test.ts
  • pnpm exec oxlint ui/src/ui/chat/grouped-render.ts ui/src/ui/chat/grouped-render.test.ts
  • pnpm check:changed
  • git diff --check

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • ui/src/ui/chat/grouped-render.test.ts (modified, +47/-0)
  • ui/src/ui/chat/grouped-render.ts (modified, +4/-1)

PR #70592: fix(ui): include cacheRead in contextPercent calculation

Description (problem / solution / changelog)

Closes #70491

Summary

The % ctx status pill under assistant messages showed 0% in sessions that rely on prompt caching — even when the actual context window consumption was 44%+.

Root cause: contextPercent was computed from inputTokens alone. With prompt caching, inputTokens is just the small per-turn delta (e.g. 6 tokens), while cacheRead holds the bulk of the tokens consuming the context budget (e.g. 440k tokens). The existing code accumulated cacheRead correctly but then ignored it when computing the percentage.

Fix: Sum input + cacheRead as totalContextTokens before computing the percentage, matching the same accounting used by the /status slash command.

Files changed

ui/src/ui/chat/grouped-render.ts

  • extractGroupMeta: derive contextPercent from input + cacheRead instead of input alone

Test plan

  • Open a cache-heavy session (long session with a large model like claude-opus-4-7)
  • Confirm the % ctx status pill now shows a non-zero percentage matching /status output
  • Confirm fresh sessions (no cache) still show correct percentage
  • Confirm % ctx stays capped at 100% even if tokens exceed window

Changed files

  • ui/src/ui/chat/grouped-render.ts (modified, +4/-1)

Code Example

let { message: t } of e.messages) {
  let e = t;
  if (e.role !== `assistant`) continue;
  let l = e.usage;
  l && (
    c = !0,
    n += l.input ?? l.inputTokens ?? 0,            // ← n = sum of inputs (per-turn delta after cache hit)
    r += l.output ?? l.outputTokens ?? 0,
    i += l.cacheRead ?? l.cache_read_input_tokens ?? 0,    // ← cacheRead computed but ignored
    a += l.cacheWrite ?? l.cache_creation_input_tokens ?? 0
  );
  // ...
}
// ↓ BUG: n is delta input tokens, not total context consumed
let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
return { input: n, output: r, cacheRead: i, cacheWrite: a, cost: o, model: s, contextPercent: l };

---

let totalTokens = entry?.totalTokens ??
                  (entry?.inputTokens ?? 0) + (entry?.outputTokens ?? 0);

---

- let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
+ const totalTokens = n + i + a + r;   // input + cacheRead + cacheWrite + output
+ let l = t && totalTokens > 0 ? Math.min(Math.round(totalTokens / t * 100), 100) : null;
RAW_BUFFERClick to expand / collapse

Bug: Control UI status bar % ctx shows 0% even when server-side context is 44%

Reporter: Giang Tran Date: 2026-04-23 OpenClaw version: 2026.4.21 (build f788c88) Channel: Webchat (Control UI)


Summary

The Control UI message-status bar shows 0% ctx even when the actual session context window is at 44% utilization (442k of 1.0m tokens for claude-opus-4-7). This is misleading — users think they have plenty of context headroom and don't compact in time, then hit unexpected limits.

The /status slash command correctly reports Context: 442k/1.0m (44%) · 🧹 Compactions: 0. So the server-side accounting is right; the bug is purely in the UI's local computation of contextPercent.


Reproduction

  1. Open Control UI webchat session.
  2. Have a long-running session with significant cache reads (e.g. cacheRead = 440k, inputTokens = 6 for the latest turn).
  3. Look at the status pill under the assistant bubble — it shows 0% ctx.
  4. Run /status in the same session — it correctly shows Context: 442k/1.0m (44%).

Root cause

In dist/control-ui/assets/index-Bsj0vinf.js, the per-message metadata aggregator computes contextPercent from inputTokens only, ignoring cacheRead:

let { message: t } of e.messages) {
  let e = t;
  if (e.role !== `assistant`) continue;
  let l = e.usage;
  l && (
    c = !0,
    n += l.input ?? l.inputTokens ?? 0,            // ← n = sum of inputs (per-turn delta after cache hit)
    r += l.output ?? l.outputTokens ?? 0,
    i += l.cacheRead ?? l.cache_read_input_tokens ?? 0,    // ← cacheRead computed but ignored
    a += l.cacheWrite ?? l.cache_creation_input_tokens ?? 0
  );
  // ...
}
// ↓ BUG: n is delta input tokens, not total context consumed
let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
return { input: n, output: r, cacheRead: i, cacheWrite: a, cost: o, model: s, contextPercent: l };

When using prompt-cache aggressively (every modern Claude session does), inputTokens per turn is just the small delta after cache hit (e.g. 6 tokens), while cacheRead accumulates the actual tokens consuming context budget (e.g. 440k).

So:

  • UI computes: 6 / 1_000_000 * 100 ≈ 0.0006% → rounded to 0%
  • Reality: (6 + 440_000) / 1_000_000 = 44%

Comparison with /status command (which is correct)

dist/status-message-NCClW_Lx.js correctly defines:

let totalTokens = entry?.totalTokens ??
                  (entry?.inputTokens ?? 0) + (entry?.outputTokens ?? 0);

Where entry.totalTokens already includes the full prompt cost (input + cacheRead + cacheWrite + output) accumulated over the session. This is what gets formatted into the Context: 442k/1.0m (44%) line.


Suggested fix

In the UI aggregator, compute contextPercent from total tokens consumed, not just inputTokens:

- let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
+ const totalTokens = n + i + a + r;   // input + cacheRead + cacheWrite + output
+ let l = t && totalTokens > 0 ? Math.min(Math.round(totalTokens / t * 100), 100) : null;

…or, even simpler, surface the server-side totalTokens field directly in the per-message usage payload and let the UI use that without recomputing.


Impact

  • Low severity functionally (no data loss, no crash)
  • High UX severity — silently misleads users about session health
  • Most affected: users running long agentic sessions with heavy prompt cache (typical Claude Opus or GPT-5.4 workflows)

A user who relies on this indicator may not run /compact or /new in time, causing the next turn to hit the model's hard context limit and fail.


Workaround

Run /status periodically — it shows the true Context: % and Compactions: count.


Environment

  • OpenClaw 2026.4.21 build f788c88
  • Node v24.14.1
  • Linux WSL2 6.6.87.2 on Windows 11
  • Browser: any (bug is in bundled UI JavaScript, browser-agnostic)
  • Model: anthropic/claude-opus-4-7 (1M context), but reproduces with any cached model

extent analysis

TL;DR

The bug can be fixed by modifying the UI aggregator to compute contextPercent from total tokens consumed, including inputTokens, cacheRead, cacheWrite, and outputTokens.

Guidance

  • The issue arises from the UI's local computation of contextPercent using only inputTokens, ignoring cacheRead.
  • To fix this, update the UI aggregator to calculate contextPercent from the total tokens consumed, which includes inputTokens, cacheRead, cacheWrite, and outputTokens.
  • Verify the fix by checking the status pill under the assistant bubble in the Control UI webchat session, which should now accurately display the context utilization percentage.
  • As a temporary workaround, users can run the /status command periodically to view the correct context utilization percentage.

Example

The suggested fix involves modifying the UI aggregator code to compute contextPercent as follows:

- let l = t && n > 0 ? Math.min(Math.round(n / t * 100), 100) : null;
+ const totalTokens = n + i + a + r;   // input + cacheRead + cacheWrite + output
+ let l = t && totalTokens > 0 ? Math.min(Math.round(totalTokens / t * 100), 100) : null;

Notes

The provided fix assumes that the totalTokens field is not already available in the per-message usage payload. If it is, the UI can simply use that field to compute contextPercent.

Recommendation

Apply the suggested fix to the UI aggregator code to accurately compute contextPercent from total tokens consumed, ensuring that users receive accurate information about session context utilization.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING