Skip to content

Cache write tokens not accounted for when using OpenRouter, causing cost underestimation #18440

Closed

Description

@rambip

Description

When a cache miss occurs via OpenRouter, opencode displays a near-zero cost even though the actual billing is much higher. This causes the in-app cost tracker to be way off from what OpenRouter bills.

The root cause: cacheWriteInputTokens falls back to 0 for OpenRouter because the code only looks for cache write tokens in anthropic and bedrock metadata. But OpenRouter actually exposes this in the usage response:

"usage_response": {
"prompt_tokens_details": {
  "cached_tokens": 10318,
  "cache_write_tokens": 0
}
}

The fix would be to also read input.usage?.cacheWriteInputTokens (or whatever field name the vercel/ai SDK maps cache_write_tokens to) as a fallback:

const cacheWriteInputTokens = safe(
  input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
  input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
  input.metadata?.["venice"]?.["usage"]?.["cacheCreationInputTokens"] ??
  input.usage?.cacheWriteInputTokens ?? // OpenRouter
  0
)

The exact field name on input.usage needs to be verified against how the vercel/ai SDK maps prompt_tokens_details.cache_write_tokens.

Plugins

N/A

OpenCode version

1.2.27

Steps to reproduce

  1. Use Claude sonnet 4.6 with openrouter
  2. Create a 50k token conversation
  3. wait 10 min (TTL is 5 min)
  4. send a new message
  5. See that price estimation only increases marginally (<0.1$) but the real cost is >0.1$

Screenshot and/or share link

Don't have it there.
But 4$estimated, 20$ real

Operating System

No response

Terminal

No response

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 20, 2026
  2. iandreyshev commented on Mar 24, 2026

    @iandreyshev

    We're hitting the same issue with LiteLLM proxy routing to AWS Bedrock (bedrock/us.anthropic.claude-sonnet-4-6).

    LiteLLM correctly returns cache_creation_input_tokens and cache_read_input_tokens in the usage object:

    "usage": {
        "prompt_tokens": 10801,
        "completion_tokens": 12,
        "cache_creation_input_tokens": 10798,
        "cache_read_input_tokens": 0,
        "prompt_tokens_details": {
            "cached_tokens": 0,
            "cache_creation_tokens": 10798
        }
    }

    But since LiteLLM uses the OpenAI-compatible format, there's no metadata["bedrock"] or metadata["anthropic"] in the response. OpenCode only reads cache write tokens from provider-specific metadata, so cacheWriteInputTokens is always 0.

    In our case, OpenCode shows ~$0.03 while LiteLLM reports ~$0.07 for the same session. The difference comes from 10798 cache_creation tokens priced at $3.00/M (regular input) instead of $3.75/M (cache write).

    The fallback to input.usage.cacheWriteInputTokens proposed above would fix this for all OpenAI-compatible proxies.

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

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions