Skip to content

Commit db96218

Browse files
authored
feat(ui): show context usage details (#100264)
* feat(ui): show context usage details * fix(ui): translate context usage labels * fix(ui): translate context usage labels * test: route e2e tempfile helper dependencies * chore: drop superseded test routing change * chore: drop superseded test routing change * chore: drop superseded test routing change
1 parent c3b479b commit db96218

69 files changed

Lines changed: 699 additions & 242 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Docs: https://docs.openclaw.ai
2828

2929
### Changes
3030

31+
- **Control UI context usage:** show context-window progress, latest-run input/output tokens, and the active model when the chat context ring is opened.
3132
- **Conversational onboarding:** add a real agent-loop Crestodian setup flow across the CLI, Gateway, web install, and macOS app, with typed operations, exact approval binding, masked credential prompts, isolated session transcripts, and safe handoff to the normal agent.
3233
- **Generated session titles:** name new Control UI sessions from their first message, and add default/per-agent `utilityModel` routing for lower-cost session, topic, and thread title generation. Thanks @Juliangsm and @zhangguiping-xydt.
3334
- **ClawRouter routing and quotas:** add the bundled ClawRouter provider plugin with credential-scoped dynamic model discovery, OpenAI-compatible and native Anthropic/Gemini transports, and managed budget reporting across OpenClaw usage surfaces. (#99658)

scripts/control-ui-mock-dev.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
type ControlUiMockGatewayScenario,
1111
} from "../ui/src/test-helpers/control-ui-e2e.ts";
1212
import {
13+
resolveExternalPackageAliasesForVite,
1314
resolveSourcePackageAliasesForVite,
1415
resolveTsconfigPathAliasesForVite,
1516
} from "../ui/vite.config.ts";
@@ -629,7 +630,11 @@ const server = await createServer({
629630
plugins: [createMockGatewayPlugin(scenario)],
630631
publicDir: path.join(uiRoot, "public"),
631632
resolve: {
632-
alias: [...resolveSourcePackageAliasesForVite(), ...resolveTsconfigPathAliasesForVite()],
633+
alias: [
634+
...resolveExternalPackageAliasesForVite(),
635+
...resolveSourcePackageAliasesForVite(),
636+
...resolveTsconfigPathAliasesForVite(),
637+
],
633638
},
634639
root: uiRoot,
635640
server: {

ui/src/e2e/chat-flow.e2e.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,60 @@ describeControlUiE2e("Control UI mocked Gateway E2E", () => {
244244
}
245245
});
246246

247+
it("opens current context and latest-run usage from the composer ring", async () => {
248+
const context = await newBrowserContext({
249+
locale: "en-US",
250+
serviceWorkers: "block",
251+
viewport: { height: 900, width: 1280 },
252+
});
253+
const page = await context.newPage();
254+
await installMockGateway(page, {
255+
methodResponses: {
256+
"sessions.list": {
257+
count: 1,
258+
defaults: {
259+
contextTokens: 200_000,
260+
model: "gpt-5.5",
261+
modelProvider: "openai",
262+
},
263+
path: "",
264+
sessions: [
265+
{
266+
contextTokens: 200_000,
267+
inputTokens: 757_300,
268+
key: "main",
269+
kind: "direct",
270+
model: "gpt-5.5",
271+
outputTokens: 42_300,
272+
totalTokens: 46_000,
273+
updatedAt: Date.now(),
274+
},
275+
],
276+
ts: Date.now(),
277+
},
278+
},
279+
});
280+
281+
try {
282+
await page.goto(`${server.baseUrl}chat`);
283+
const trigger = page.locator("summary.context-ring");
284+
await trigger.waitFor({ timeout: 10_000 });
285+
await trigger.click();
286+
287+
const popover = page.locator(".context-usage__popover");
288+
await expect.poll(() => popover.isVisible()).toBe(true);
289+
await expect.poll(() => popover.textContent()).toContain("46k / 200k · 23%");
290+
await expect.poll(() => popover.textContent()).toContain("757.3k");
291+
await expect.poll(() => popover.textContent()).toContain("42.3k");
292+
await expect.poll(() => popover.textContent()).toContain("gpt-5.5");
293+
294+
await page.keyboard.press("Escape");
295+
await expect.poll(() => popover.isHidden()).toBe(true);
296+
} finally {
297+
await closeBrowserContext(context);
298+
}
299+
});
300+
247301
it("keeps a targetless message-tool source reply beside the automatic final reply", async () => {
248302
const context = await newBrowserContext({
249303
locale: "en-US",

ui/src/i18n/.i18n/ar.meta.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/src/i18n/.i18n/ar.tm.jsonl

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ui/src/i18n/.i18n/de.meta.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)