mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-12 18:22:48 +03:00
Hoisting a mid-conversation `system`/`developer` message into the top-level `system` field carried its `cache_control` marker along. Anthropic assembles the cache prefix as tools -> system -> messages, so the marker ended the cached prefix at the system block and left the accumulated conversation without a breakpoint: that turn was billed as fresh input and the next one rebuilt the cache. `relocateHoistedCacheBoundary` moves the marker to the nearest preceding block that can carry a breakpoint, skipping thinking blocks, empty text and anything the upstream normalisation discards or empties out. If that block already carries the client's own marker, both are kept - unless the hoisted one, now ahead of the target in `system[]`, would put a 5m breakpoint before a 1h one, which Anthropic rejects; it is dropped in that case. Either way the breakpoint count never grows. normalizeClaudeUpstreamMessages rewrites tool_result and inlined file/document blocks into plain text after the hoist, which silently discarded any marker on them - including a relocated one. The replacement block now inherits it. Both hoisting implementations share the helper; a fix touching only claudeSystemRole.ts would leave extractSystemMessagesToBody broken, and the native Claude path reaches the former through normalizeClaudeUpstreamMessages. Capability-gated hoisting for strict providers (#7293) is unaffected. Fixes #9436 Co-authored-by: LeonG606 <leongudat01@gmail.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>