Skip to content

Preserve cache_control for Qwen/DeepSeek on OpenRouter + Anthropic adapter - #1

Merged
jwbron merged 1 commit into
mainfrom
cache-control-passthrough-qwen-deepseek
May 28, 2026
Merged

Preserve cache_control for Qwen/DeepSeek on OpenRouter + Anthropic adapter#1
jwbron merged 1 commit into
mainfrom
cache-control-passthrough-qwen-deepseek

Conversation

@jwbron

@jwbron jwbron commented May 28, 2026

Copy link
Copy Markdown
Owner

Why

When Claude Code is pointed at Qwen/DeepSeek through the LiteLLM proxy (Anthropic /v1/messages -> OpenRouter), cache_control was being lost end-to-end, so every turn paid the full input rate (cache_read_input_tokens stayed at 0). These three fixes let the prefix cache actually land (measured ~0% -> ~95% hit rate on Alibaba/DeepSeek routes).

Changes

  1. openrouter/chat/transformation.py — add QWEN and DEEPSEEK to CacheControlSupportedModels. OpenRouter natively supports cache_control content blocks for these upstreams (docs); without them the handler strips the marker before the upstream call.

  2. anthropic/.../adapters/transformation.pyis_anthropic_claude_model — recognize qwen/deepseek so the Anthropic->OpenAI adapter applies cache_control for those models. (This method is also consulted for thinking translation: widening it means a raw Anthropic thinking dict is passed through instead of being translated to reasoning_effort for these models. In practice callers use drop_params: true and/or set reasoning_effort explicitly, so this is benign, but it's the one behavioral tradeoff to be aware of.)

  3. anthropic/.../adapters/transformation.py_add_system_message_to_messages — drop the x-anthropic-billing-header: system block. Claude Code injects this ahead of the cache_control marker with a per-request hash; left in, it invalidates the upstream prefix-cache key every turn. This mirrors _filter_billing_headers_from_system in the sibling messages adapter, which already filters it.

Tests

  • is_anthropic_claude_model recognizes qwen/deepseek (and still rejects gpt/gemini).
  • Billing-header system block is dropped while a real block keeps its cache_control.
  • transform_request preserves cache_control for qwen/deepseek models.

All four touched files pass black.

…apter

Three related fixes so cache_control survives end-to-end when routing
Anthropic /v1/messages traffic to Qwen/DeepSeek upstreams via OpenRouter:

1. Add QWEN and DEEPSEEK to CacheControlSupportedModels so the OpenRouter
   chat handler stops stripping cache_control before the upstream call.

2. Widen is_anthropic_claude_model to recognize qwen/deepseek so the
   Anthropic->OpenAI adapter applies cache_control for those models.

3. Drop the x-anthropic-billing-header system block in the adapter path
   (mirrors _filter_billing_headers_from_system in the messages adapter).
   Its per-request hash otherwise invalidates the prefix cache every turn,
   pinning cache_read_input_tokens at 0.

Adds unit tests for all three paths.
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.

1 participant