diff --git a/README.md b/README.md
index 961b9aad76..e14f644409 100644
--- a/README.md
+++ b/README.md
@@ -1696,6 +1696,26 @@ Use it as-is. Or tear it apart and make it yours.
## Core Features
+### Token usage dashboard
+
+Open **Token usage** in the workspace sidebar (`/workspace/usage`) to review
+your recorded tokens over the last 7 or 30 days, daily input/output totals,
+cache-hit input tokens by model, and paginated run history with failure filters.
+Run history covers all dates independently of the selected chart period.
+Conversation links use each run's recorded assistant to open the default or
+matching custom-agent chat.
+Periods with no recorded runs show an empty message without a date axis or
+zero-filled daily details; runs with zero reported tokens still show details.
+
+Reporting requires `runs:read` permission and a SQLite or PostgreSQL database;
+it is unavailable in the static demo. Counts reflect persisted provider usage,
+may be incomplete during active runs or when providers omit usage, and are not
+a provider bill. Cache hits are included in input tokens. Daily buckets use the
+browser's current UTC offset and attribute a run to its creation date.
+The page reuses the existing `/api/console` APIs; their optional cost and currency
+fields and server-side pricing configuration remain supported.
+See [dashboard behavior and design](frontend/docs/token-usage-dashboard.md).
+
### Workspace
The workspace keeps a collapsed icon sidebar visible on narrow screens. Its
diff --git a/README_zh.md b/README_zh.md
index fb49a20979..18fda15983 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -712,6 +712,18 @@ DeerFlow 2.0 不再是一个需要你自己拼装的 framework。它是一个开
## 核心特性
+### Token 用量统计
+
+点击侧边栏的 **Token 用量**(`/workspace/usage`),查看近 7/30 天的用量、
+每日输入/输出 Token、各模型的缓存命中输入 Token,以及支持失败筛选和分页的
+运行记录。运行记录包含所有日期,不受图表所选周期限制。
+
+此功能需要 `runs:read` 权限和 SQLite 或 PostgreSQL 数据库,静态演示不提供统计。
+数据来自已持久化的服务商用量;运行过程中或服务商未返回用量时可能不完整,不能
+作为服务商账单。缓存命中 Token 已包含在输入 Token 中。每日分桶使用浏览器当前
+UTC 偏移,并按运行的创建日期归属。页面复用现有 `/api/console` 接口,保留服务端
+价格配置及可选的费用、币种字段。
+
### Skills 与 Tools
Skills 是 DeerFlow 能做“几乎任何事”的关键。
diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md
index 3db665c1d8..d29d582224 100644
--- a/frontend/AGENTS.md
+++ b/frontend/AGENTS.md
@@ -1,16 +1,16 @@
# AGENTS.md
-DeerFlow frontend guidance source of truth; `CLAUDE.md` imports `@AGENTS.md`.
+Frontend guidance; `CLAUDE.md` imports `@AGENTS.md`.
## Project Overview
-DeerFlow's Next.js 16 frontend provides thread-based AI conversations with streaming responses, artifacts, skills, and tools through a LangGraph backend.
+Next.js 16 frontend for LangGraph conversations, streaming, artifacts, skills and tools.
**Stack**: Next.js 16, React 19, TypeScript 5.8, Tailwind CSS 4, pnpm 10.26.2. Requires Node.js 22+ and pnpm 10.26.2+.
-Core dependencies: `@langchain/langgraph-sdk` ^1.5.3 for orchestration/streaming,
-`@langchain/core` ^1.1.15, and `@tanstack/react-query` ^5.90.17 for server state.
-Registry UI: Shadcn, MagicUI, React Bits, Vercel AI SDK (see Code Style).
+Dependencies: `@langchain/langgraph-sdk` ^1.5.3, `@langchain/core` ^1.1.15,
+`@tanstack/react-query` ^5.90.17. Registry UI: Shadcn, MagicUI, React Bits,
+Vercel AI SDK (see Code Style).
`pnpm-workspace.yaml` pins vulnerable `@xmldom/xmldom` 0.9.x to patched
0.9.12 (GHSA-965w-775f-mr7g) and Nextra 4.6.1's Zod dependencies to 4.3.6
@@ -22,28 +22,32 @@ docs builds after changes.
Run from `frontend/`; host pnpm calls use `../scripts/pnpm.py`.
-- `pnpm dev`: Webpack development server; `pnpm build` / `pnpm start`: production build/server.
-- `pnpm check`: ESLint + TypeScript (required before committing); `pnpm lint` / `pnpm typecheck`: individual checks; `pnpm lint:fix`: ESLint fixes.
+- `pnpm dev`: development; `pnpm build` / `pnpm start`: production build/server.
+- Before committing: `pnpm check` (ESLint + TypeScript). Separately: `pnpm lint` / `pnpm typecheck`; ESLint fixes: `pnpm lint:fix`.
- `pnpm format` / `pnpm format:write`: Prettier check/write.
- `pnpm test`: Rstest unit tests; `pnpm test:e2e`: Playwright Chromium E2E tests.
Unit tests under `tests/unit/` mirror `src/`; import source via `@/`.
-Webpack is the default development bundler. Use `DEER_FLOW_DEV_BUNDLER=turbo` with `pnpm dev` to opt in to Turbopack when diagnosing a local Next.js bundler issue.
+Webpack is the default; use `DEER_FLOW_DEV_BUNDLER=turbo pnpm dev` to diagnose with Turbopack.
-On Windows `pnpm dev` binds `127.0.0.1` by default because Hyper-V/winnat excluded port ranges can reject Next's default `0.0.0.0` bind with `EACCES` (#2870). Pass `pnpm dev -- --hostname 0.0.0.0` to listen on a LAN interface instead.
+Windows dev binds `127.0.0.1` to avoid Hyper-V/winnat `EACCES` (#2870).
+For LAN access: `pnpm dev -- --hostname 0.0.0.0`.
-`rstest.config.ts`: **node** runs `*.test.*` pure logic; **happy-dom** runs
-`*.dom.test.*` components/hooks via `@testing-library/react` render/renderHook.
-DOM costs ~3x: keep the split. Effect ordering, unmount cleanup and store
-re-renders need DOM tests with real React.
+`rstest.config.ts`: **node** for `*.test.*` logic; **happy-dom** for `*.dom.test.*`
+components/hooks via `@testing-library/react` render/renderHook. Keep the split
+(DOM costs ~3x). Test effect ordering, unmount cleanup and store re-renders with real React/DOM.
-Content/state suites may mock decorative `FlipDisplay` with
-`tests/unit/helpers/flip-display.tsx`, preserving children, classes and keyed
-remounts. Happy DOM 21's animation cancellation rejects `finished`; keep rejection
-reporting enabled. Real Motion behavior belongs in Playwright.
+Content/state suites may use `tests/unit/helpers/flip-display.tsx` to mock
+decorative `FlipDisplay`; preserve children, classes and keyed remounts.
+Happy DOM 21 animation cancellation rejects `finished`; keep rejection reporting
+enabled. Test real Motion in Playwright.
-E2E tests live under `tests/e2e/` and use Playwright with Chromium. They mock all backend APIs via `page.route()` network interception and test real page interactions (navigation, chat input, streaming responses). Config: `playwright.config.ts`. The real-backend auth contract in `tests/e2e-real-backend/auth-disabled-contract.spec.ts` and `backend/tests/test_auth_me_permissions.py` pin the complete route-permission list; update both when adding registered permissions (including `projects:read/write/delete`).
+Playwright Chromium E2E: `tests/e2e/`, configured by `playwright.config.ts`.
+Mock backend APIs with `page.route()`; exercise real navigation, chat input and streaming.
+When registering permissions (including `projects:read/write/delete`), update both
+`tests/e2e-real-backend/auth-disabled-contract.spec.ts` and
+`backend/tests/test_auth_me_permissions.py`, which pin the complete route-permission list.
CI runs four E2E shards; only shard 1 runs auth recovery. Suite reports stay separate.
@@ -77,6 +81,15 @@ Keep IM notification preferences viewer-fenced and separate from browser alerts;
## Architecture
+Token usage: `app/workspace/usage` composes `components/workspace/usage` and
+`core/usage` over the existing owner-scoped console APIs. Keep owner, period,
+timezone, status and page in query keys; consume AbortSignals and never show
+another owner's or period's placeholder totals. Gate on `runs:read` and static
+mode. Display tokens without changing optional backend pricing fields.
+See [design and reporting semantics](docs/token-usage-dashboard.md).
+Run links reuse `pathOfThread`; `lead_agent` and absent assistant IDs select
+normal chats, while custom assistant aliases follow Gateway normalization.
+
Model controls: `core/models/use-model-control` + HumanInputCard.
Knowledge evidence is parsed in `core/citations/sources.ts` from version-1
diff --git a/frontend/docs/token-usage-dashboard.md b/frontend/docs/token-usage-dashboard.md
new file mode 100644
index 0000000000..e5b3a10e11
--- /dev/null
+++ b/frontend/docs/token-usage-dashboard.md
@@ -0,0 +1,73 @@
+# Token usage dashboard
+
+The workspace page at `/workspace/usage` presents the existing current-user
+reporting APIs introduced in upstream PR #3920. It adds no database tables,
+permissions, provider calls, billing logic, dependencies, or backend API changes.
+
+## Extension-first evaluation
+
+A packaged extension can register a page and sidebar navigation through
+`PluginContribution` and `BrowserAssets`. That is a viable alternative when
+operators want an optional, independently distributed reporting product.
+
+This contribution proposes a built-in view of DeerFlow's existing console APIs.
+It is presentation of an existing core capability, with shared React components,
+locale types, authenticated fetch and account-scoped query caching. The page
+does not introduce a second reporting service or token collector. A packaged
+implementation would additionally need its installation/lifecycle and a browser
+module or namespaced backend action adapter; the page mount context currently
+exposes `callBackend` for plugin actions rather than a typed console reader.
+
+Both approaches can express the feature. The built-in proposal keeps the existing
+API and its authorization boundary unchanged and makes its reports discoverable
+without an extra deployment installation. Maintainer agreement on this product
+placement is still needed before upstream submission; this rationale does not
+claim that extension hooks are incapable of supporting it.
+
+The author's fork associated with #3920 already contains a console UI. This
+contribution complements the merged API; it does not claim to introduce token
+accounting or the first dashboard implementation.
+
+## Reporting contract
+
+- `GET /api/console/usage` supplies 7/30-day totals, daily buckets and per-model
+ counts. Browser UTC offset is sent as `tz_offset_minutes`. Existing fixed-offset
+ semantics apply across the whole window, including daylight-saving transitions.
+- The API attributes all recorded tokens in a run to its creation date, rather
+ than the wall-clock date of each individual model call. Active runs may still
+ have partial persisted counters; providers that omit usage can leave gaps.
+- Cache-hit input tokens are a subset of input tokens, not an additional amount
+ to add to total tokens. Model run counts are non-exclusive for multi-model runs.
+- `GET /api/console/runs` supplies 20 rows per page and a `has_more` sentinel.
+ All/error/timeout filters reset pagination. This history is independent of the
+ chart's period. Offset pagination is live, not a snapshot.
+- Run links reuse `pathOfThread` and the recorded `assistant_id`. The built-in
+ `lead_agent` and absent/empty legacy IDs open normal chats. Custom assistant
+ aliases are trimmed, lowercased and have underscores changed to hyphens,
+ matching the Gateway identity convention; they open that agent's chat route.
+ Thread IDs are encoded as opaque path segments by the shared route helper.
+- Counts are provider-reported usage recorded by DeerFlow, not provider invoices.
+ The view displays no estimated prices. Existing optional `cost`, `total_cost`
+ and `currency` response fields, configuration and tests remain unchanged.
+
+## Access and failure behavior
+
+The sidebar entry and queries require a current user with `runs:read`. Static
+demos issue no usage requests. The Gateway enforces authorization and owner scope;
+the frontend does not grant access. Memory-only storage reports 503 and the page
+explains the SQLite/PostgreSQL requirement. Forbidden, unavailable, loading and
+empty reports remain distinct; failed requests never become fabricated zeroes.
+
+Query keys include owner and report filters. The authenticated workspace owns
+cache lifetime; consumed AbortSignals cancel obsolete reads. Switching period
+does not display the previous period as placeholder data. Only the first run
+page refreshes on focus/reconnect. Refresh explicitly reloads both panels.
+
+## Verification
+
+Run `pnpm check`, `pnpm rstest run tests/unit/core/usage` and
+`pnpm exec playwright test tests/e2e/usage-dashboard.spec.ts` from `frontend/`.
+The browser suite uses mocked APIs and exercises navigation, periods, timezone,
+failure recovery, filtering, pagination, English and Chinese mobile layout.
+The dashboard tests deliberately include the upstream monetary response fields
+to prove that token-only presentation does not require removing those fields.
diff --git a/frontend/src/app/workspace/usage/page.tsx b/frontend/src/app/workspace/usage/page.tsx
new file mode 100644
index 0000000000..a7802b8f5c
--- /dev/null
+++ b/frontend/src/app/workspace/usage/page.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { useEffect } from "react";
+
+import { UsageDashboard } from "@/components/workspace/usage/usage-dashboard";
+import {
+ WorkspaceContainer,
+ WorkspaceHeader,
+} from "@/components/workspace/workspace-container";
+import { useI18n } from "@/core/i18n/hooks";
+
+export default function UsagePage() {
+ const { t } = useI18n();
+ useEffect(() => {
+ document.title = `${t.usage.title} - ${t.pages.appName}`;
+ }, [t.usage.title, t.pages.appName]);
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/workspace/usage/query-error.tsx b/frontend/src/components/workspace/usage/query-error.tsx
new file mode 100644
index 0000000000..1b8b812e10
--- /dev/null
+++ b/frontend/src/components/workspace/usage/query-error.tsx
@@ -0,0 +1,36 @@
+import { Button } from "@/components/ui/button";
+import { GatewayApiError } from "@/core/api/errors";
+import type { Translations } from "@/core/i18n/locales/types";
+
+export function UsageQueryError({
+ error,
+ retry,
+ text,
+}: {
+ error: Error;
+ retry: () => void;
+ text: Translations["usage"];
+}) {
+ const status = error instanceof GatewayApiError ? error.status : null;
+ const message =
+ status === 403
+ ? text.forbidden
+ : status === 404
+ ? text.unavailable
+ : status === 503
+ ? text.databaseRequired
+ : text.loadFailed;
+ return (
+