Skip to content

fix(bedrock): count cacheWriteInputTokens in turn tokens and cost - #478

Open
pcbeingused333 wants to merge 3 commits into
posit-dev:mainfrom
pcbeingused333:fix/bedrock-cache-write-tokens
Open

pcbeingused333 wants to merge 3 commits into
posit-dev:mainfrom
pcbeingused333:fix/bedrock-cache-write-tokens

Conversation

@pcbeingused333

Copy link
Copy Markdown
Contributor

ChatBedrock() appends a Converse cache point by default for anthropic.* and amazon.nova* models, but converse_tokens() read only inputTokens, outputTokens and cacheReadInputTokens. The cacheWriteInputTokens field of the Converse usage was dropped, so turns that wrote to the cache reported fewer input tokens, and a lower cost, than they used. ChatAnthropic() already folds cache creation into the input count (1.25x for the 5 minute cache, 2x for cache="1h").

This change does the same for the Converse provider:

  • Claude models (anthropic.*, with or without a cross-region prefix): inputTokens + cacheWriteInputTokens * 1.25, or * 2 when cache="1h".
  • Other models: cache writes are counted at the regular input rate (multiplier 1).
  • A missing cacheWriteInputTokens field counts as 0, as before.

Tests (tests/test_provider_bedrock_converse.py, TestResponseParsing) build Converse responses with cacheReadInputTokens and cacheWriteInputTokens and check the resulting (input, output, cached) tuple for a 5m Claude model, a 1h Claude model, a Nova model and a response without the field. Three of them fail on main (the write tokens are ignored) and pass with the change. The bedrock and token test files pass locally; nothing was run against the real Bedrock API. A CHANGELOG entry is included.

Open question: if you would rather only count the tokens and leave the per-model weighting out, the multiplier branch is a few lines and easy to drop.

This change was made with Claude Code.

🤖 Generated with Claude Code

pcbeingused333 and others added 2 commits October 21, 2026 08:18
ChatBedrock() sends cache points by default for anthropic.* and amazon.nova*
models, but converse_tokens() ignored the cacheWriteInputTokens field of
the Converse usage, so cache writes were never counted. Fold them into the
input count like ChatAnthropic() does: 1.25x (2x with cache="1h") on Claude
models, the regular input rate otherwise.

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
cache_write = usage.get("cacheWriteInputTokens", 0)
return (
usage["inputTokens"],
usage["inputTokens"] + int(cache_write * cache_write_mult),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do other providers need to incorporate cache write tokens?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Anthropic already folds cache writes in. Checking the rest: OpenAI does need it, since GPT-5.6 and later bill Responses cache writes at 1.25x (2.5x for the 12h lifetime) and report them as input_tokens_details.cache_write_tokens, which is included in input_tokens. That is in a separate PR, #480, so this one stays Bedrock-only. Google reports no write count, Ollama is local, and the OpenAI-compatible Chat Completions providers (OpenRouter etc.) expose the field but the write rate depends on the upstream model, so I left those out.

# Conflicts:
#	CHANGELOG.md

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants