Skip to content

fix(ai): place prompt cache breakpoints on OpenRouter Anthropic and Qwen requests - #52110

Merged
rekram1-node merged 8 commits into
v2from
openrouter-cache
Sep 29, 2026
Merged

rekram1-node merged 8 commits into
v2from
openrouter-cache

Conversation

@rekram1-node

@rekram1-node rekram1-node commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Issue for this PR

No linked issue.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

applyCachePolicy skipped OpenRouter whenever the request used the default cache policy, so OpenRouter requests only got cache_control markers when a caller set an explicit policy. Core never does, so no OpenRouter session sent breakpoints.

This enables explicit caching for Anthropic and Alibaba Qwen through OpenRouter (prompt caching docs), instead of leaving Claude uncached and relying on Qwen's less predictable implicit caching.

The default policy on OpenRouter is now chosen by model:

  • anthropic/* and OpenRouter's ~anthropic/* latest-model aliases: the usual breakpoints (last tool, first and last system parts, conversation tail).
  • qwen/* (including leading-~ aliases): system boundaries and conversation tail, without a model allowlist. Alibaba ignores breakpoints on tool definitions and caches tools as part of the system prompt (context cache docs).
  • Everything else: no default breakpoints. In particular, Gemini's moving-tail explicit caching was more expensive than leaving its implicit caching alone in live testing.

Explicit cache policies and manually placed cache hints still apply to every OpenRouter model, as before.

Shared Chat lowering now puts assistant and tool-result breakpoints on text content parts (content: [{ type: "text", text, cache_control }]), rather than on the message itself. Alibaba ignores message-level markers. Unmarked assistant text remains a string, and reasoning-only assistants do not acquire fabricated text markers. A wrapped system update consumes its breakpoint budget once rather than twice.

Only OpenRouter currently enables cache controls in the shared Chat lowering, so other providers' requests and native Anthropic Messages are unchanged. The existing four-breakpoint limit and per-part TTLs remain supported.

How did you verify your code works?

  • Basic tests for the default Anthropic/Qwen policies, latest-model aliases, unchanged OpenAI/Gemini requests, assistant/tool-result serialization, and wrapped system-update budgeting. Existing reasoning replay assertions now expect marked assistant text parts; signatures remain unchanged.
  • Full packages/ai test suite, focused Core request/transport/provider tests, and root bun run check pass.
  • Real CLI tool loops and follow-up prompts across a broad OpenRouter matrix verified breakpoint placement, cache reads/writes, aliases, reasoning variants, and billed usage.cost. Claude Sonnet 4.6 billed about $0.0045 per subsequent step versus $0.037 on v2 in the tested session.
  • Nine-request Qwen loops: coder-plus billed $0.0198 on v2 versus $0.0158 with the fix; qwen3.7-plus billed $0.0097 versus $0.0081.
  • Assistant content-part markers: 15 direct requests using compiled bodies across Claude Sonnet 4.6, Haiku 4.5, Qwen Coder Plus, Qwen3 Max, and Qwen3.7 Plus all returned HTTP 200 and demonstrated cache writes and reads. Coder Plus had one partial hit when the marker advanced, followed by a full prefix hit on repetition; markers do not guarantee every request fully hits the cache.

Screenshots / recordings

Not applicable.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@rekram1-node rekram1-node changed the title fix(ai): place prompt cache breakpoints on OpenRouter requests by default fix(ai): place prompt cache breakpoints on OpenRouter Anthropic and Qwen requests Sep 29, 2026
@rekram1-node
rekram1-node force-pushed the openrouter-cache branch 2 times, most recently from 006684b to 011f324 Compare September 29, 2026 20:35
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