← Back to Noel
AgentNoel
Token and cache accounting
Turns differing provider usage reports into comparable records while preserving cache, reasoning and incomplete-stream distinctions.
llm-token-cache-accounting
See how it helpsWhen is it useful?
Use it when costs disagree across providers or cached and streamed requests produce confusing token totals.
What does it help you do?
- Normalizes provider counters into non-overlapping usage buckets.
- Separates cache reads, writes, reasoning and ordinary input.
- Marks incomplete streams and subscription-mode accounting limitations.
Try asking this
Reconcile cached streaming usage without billing the same input tokens twice. Compare the provider's final counters with accumulated chunks. Store cache reads and ordinary input separately, and flag a missing final usage record for reconciliation.
Detailed documentation
Read the skill’s original instructions, examples and checks in their authored language.
Show less
LLM Token & Cache Accounting
LLM providers report token usage with incompatible semantics. Naive summation across providers routinely double-counts cached tokens or misses hidden reasoning and tool-use tokens by 2x–10x.
Workflow
- Normalize provider token semantics into disjoint canonical buckets:
Map every provider response into disjoint quantities so total cost is a clean dot product of
(bucket_quantity * bucket_rate):uncached_input_tokens: Fresh input tokens billed at standard input rate.cache_write_input_tokens: Tokens written into prompt cache (1.25xor2xbase input rate, or TTL-specific write rate).cache_read_input_tokens: Cached input tokens read at discounted rate (0.1xor0.25xbase input rate).standard_output_tokens: Visible completion tokens billed at output rate.reasoning_output_tokens: Internal chain-of-thought / thinking tokens billed at output rate.
- Handle each provider's exact schema:
- Anthropic (
messagesAPI):usage.input_tokens,usage.cache_creation_input_tokens, andusage.cache_read_input_tokensare mutually exclusive (disjoint).- Total prompt context =
input_tokens + cache_creation_input_tokens + cache_read_input_tokens. - If
usage.cache_creationsplitsephemeral_5m_input_tokensvs.ephemeral_1h_input_tokens, rate each at its respective write multiplier.
- OpenAI (
chat.completions&responsesAPI):prompt_tokens(input_tokens) already includesprompt_tokens_details.cached_tokens.- Compute
uncached_input_tokens = prompt_tokens - cached_tokensandcache_read_input_tokens = cached_tokens. Never addcached_tokenson top ofprompt_tokens! completion_tokens(output_tokens) already includescompletion_tokens_details.reasoning_tokens. Computestandard_output_tokens = completion_tokens - reasoning_tokens.
- Google Gemini (
generateContentusageMetadata):promptTokenCountalready includescachedContentTokenCount. Computeuncached_input_tokens = promptTokenCount - cachedContentTokenCount.thoughtsTokenCountis billed at the output rate; storestandard_output_tokens(candidatesTokenCount) andreasoning_output_tokens(thoughtsTokenCount) distinctly.
- Anthropic (
- Streaming responses and aborted connections:
- Enable final usage chunks on streams (
stream_options: { include_usage: true }for OpenAI;message_delta/message_stopfor Anthropic). - If a stream aborts before the final usage frame, record a fallback event with
certainty: 'estimated', counting prompt tokens plus tokenized output chunks emitted before abort.
- Enable final usage chunks on streams (
- Multi-turn agent loops and CLI / subscription modes:
- Record each turn in an agent loop as its own event linked to
runIdandturnIndex, trackingcontextGrowthTokensacross turns to spot quadratic prompt growth or cache-busting prefixes. - For subscription CLI runs with no per-call charge, record tokens, duration, turns, and
imputedListCostMicros(billingMode: 'subscription_cli' | 'api_metered' | 'byok').
- Record each turn in an agent loop as its own event linked to
Included files 1
SKILL.md
