Feature/tokens command and calculation - #393
Open
AlanAAG wants to merge 2 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two related changes to how token usage is reported.
1. Fix token display math.
input_tokensfrom every provider is the full prompt size, cache reads included.cachedis a subset of it, never a sibling. The dashboard was rendering both as if they were independent, which read as double-counting.input − cached(genuinely new tokens)input + outputwith cached excluded, derived client-side instead of using the API'stoken.total(which israwInput + output)2. Add
/tokens. Per-session token breakdown, printed into the chat it was typed in. Deterministic: no LLM call, no agent dispatch, same shape as/clear.Session token usage
Input: 79,022
Cached: 312,455
Output: 5,770
Total: 84,792
Why the new Session fields
Session.input_tokens/output_tokens/cache_tokensalready existed but are per-run.reset_run_counters()is called fromsession_manager.start_run()on every fresh run, so tt turn. Theusage_eventstable has asession_idcolumn but it's never populated (collector.py:1236passestask_id=None).So per-chat cumulative totals didn't exist anywhere. This adds
total_input_tokens/total_output_tokens/total_cache_tokens, incremented inattribute_usage_to_current_taskalongdeliberately excluded fromreset_run_counters().No schema migration:
session_storagepersists the wh, andfrom_dictdefaults to 0, so existing sessionsload clean and start counting.Explicitly not changed
The storage layer is provider truth and other consumers depend on current semantics:
interface.py:2588Anthropic'sbase_input + cache_creation + cache_readreassembly, and every other provider's extractionstorage.py:227SUM(input_tokens + output_tokens)token.py:40billable_tokens, already uncached-only and documented as intentionally separate from display (it's the budget limiter)This is presentation-only plus the new cumulative coun
Testing
tests/test_tokens_command.py, 6 checks: totals sur, round-trip throughto_dict/from_dict`,pre-existing sessions load as zero, the subtraction, the clamp when a provider over-reports cache reads, and unsaved sessions reading aszero
tests/test_token_attribution.py, 6 passed, no regressiontsc --noEmitclean,npm run buildgreen/tokensagainst a real session returned79,022 / 312,455 / 5,770 / 84,792, matchingsessions.db(
total_input=391,477,total_cache=312,455)Reviewer notes
usage_eventsnever recordedsession_id. Current chats read0until they run again.sessionId:"new"andsession_manager.get()returnsNone. Handled viagetattr(session, ..., 0).Cached: e cache rather than reading it (interface.py:1406`records a miss). Correct, but looks like a bug if you test with a single message./tokens' Total now agreet both differ from the rawtoken.totalthe API stillreturns.Follow-up (not in this PR)
Populating
session_idinusage_eventswould let per-session totals survive a DB rebuild and feed the dashboard, and would remove theneed for counters on the Session object at all.