fix(dashboard): avoid double-counting cached input tokens - #424
Conversation
Use provider-reported token totals when available and rebuild stale dashboard summaries under the corrected semantics. Preserve Anthropic cache buckets as additive fallback fields when providers omit a total. Co-authored-by: Talon <talon@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d232af66d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Document the real Codex regression comparison and Claude Code provider fallback evidence in the pull request. Co-authored-by: Talon <talon@users.noreply.github.com>
Co-authored-by: Talon <talon@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 17236cb2b5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| offset = _session_offset_from_request(request) | ||
| limit = _session_limit_from_request(request) | ||
| query = _session_query_from_request(request) | ||
| repair_stale_session_summaries(query) |
There was a problem hiding this comment.
Make stale-summary repair best-effort
When an upgraded dashboard has any matching stale summaries, this new call performs synchronous repair writes before /api/sessions can return; if the trace DB is opened read-only or another claude-tap process holds the .write.lock long enough for store_summary to raise sqlite3.OperationalError, the exception is not caught here and the whole sessions API returns 500 even though the aggregate/list reads could otherwise still be served from cached data. Consider catching repair failures or moving this to a best-effort/background path so stale-cache repair cannot break the dashboard page.
Useful? React with 👍 / 👎.
| reported = usage.get("total_tokens") | ||
| if isinstance(reported, int) and not isinstance(reported, bool) and reported >= 0: | ||
| return reported |
There was a problem hiding this comment.
Keep Bedrock cache buckets in token totals
For AWS Bedrock Converse usage that includes totalTokens together with cacheReadInputTokens or cacheWriteInputTokens, returning the reported total here drops the cache buckets from dashboard summaries and aggregates. AWS defines totalTokens as input plus output, with cache read/write as separate fields, so a response like inputTokens=9, outputTokens=4, totalTokens=13, cacheReadInputTokens=3, cacheWriteInputTokens=2 now shows 13 instead of the previous 18; keep using the provider total only for providers whose cache is embedded, or add native cache buckets for Bedrock-style usage.
Useful? React with 👍 / 👎.
Summary
usage.total_tokensso OpenAI Responses cached input is not counted twiceFixes #423.
Validation
uv run ruff check .uv run ruff format --check .uv run pytest tests/ -x --timeout=60(1072 passed, 26 skipped)uv lock --checkuv run python scripts/check_screenshots.py .agents/evidence/pr/issue-423-token-totalsReal E2E
gpt-5.6-sol. The real 3-call trace reported 49,546 input, 236 output, 36,096 cached input, and 49,782 provider total.openrouter/claude-haiku-4-5. It made three real/v1/messagescalls, used the shell tool, returnedANTHROPIC_ISSUE423_OK 3, and the dashboard fallback totaled 4,261 input + 268 output = 4,529. New API logs confirmed token/model/channel attribution.liaohaochun/claude-tap/issue-423is retained for the owner as token chore: update changelog for v0.1.61 #165 with a non-unlimited 50,000,000 quota (the configured $100 limit) and all models enabled. The key is not included in this PR.Before / After Evidence
The first image uses the same real Codex SQLite trace rendered by the base commit (
v0.1.142): the old dashboard shows85,878, which equals49,782 + 36,096and demonstrates the cache double-counting bug. The second image renders that same trace with this fix and shows the correct provider total49,782. The third image is a separate real Claude Code/New API trace and shows the provider-compatible Anthropic fallback total4,529.Trace Detail Evidence