fix: enforce Anthropic cache_control budget - #27170
Conversation
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
The existing test only verified the request-wide count was clamped to 4. A regression that reversed the stripping order (e.g. dropping the system marker first) would still pass. Tighten the assertions to lock in the intended priority: tools then older messages then system, with the most recent message's marker preserved. Also note in _strip_first_cache_control's docstring that it mutates its argument in place. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Thanks for the focused fix. I verified the premise against current main and did not find correctness or design blockers in the PR diff. Current main still has the over-budget path: The PR’s approach fits the existing narrow adapter boundary: it removes tool-schema marker forwarding and adds a final Anthropic kwargs sanitizer in Automated hermes-sweeper review. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused cache-budget fix. The current-main premise is real: agent/prompt_caching.py:89-97 creates up to four markers, while agent/anthropic_adapter.py:1690-1695 can forward a tool-schema marker.
Problems
agent/anthropic_adapter.py:1314removes tool-schemacache_controlunconditionally. Current main explicitly supports that marker to cache the schema cross-session atagent/anthropic_adapter.py:1690-1695; this changes supported caching behavior even when the request is within budget._count_cache_control()atagent/anthropic_adapter.py:1891recursively treats every dict-valuedcache_controlkey as a request marker. A validinput_schema.properties.cache_controlobject would be counted and can be deleted by_strip_first_cache_control()at line 1876.
Suggested changes
- Retain legitimate schema caching and constrain budget accounting/removal to valid Anthropic marker positions.
- Add a regression case for an input-schema property named
cache_control, alongside the request-wide cap test.
Automated hermes-sweeper review.
| cache_control = t.get("cache_control") | ||
| if isinstance(cache_control, dict): | ||
| anthropic_tool["cache_control"] = dict(cache_control) | ||
| # Do not forward cache_control from OpenAI-format tool dicts here. |
There was a problem hiding this comment.
This unconditionally removes a supported schema-cache marker. Current main deliberately forwards it at agent/anthropic_adapter.py:1690-1695 to cache the tool schema cross-session. Please enforce the four-marker budget without disabling schema caching for requests that do not exceed it.
| def _count_cache_control(value: Any) -> int: | ||
| """Count cache_control markers recursively in an Anthropic request object.""" | ||
| if isinstance(value, dict): | ||
| return (1 if isinstance(value.get("cache_control"), dict) else 0) + sum( |
There was a problem hiding this comment.
This counts any dict-valued key named cache_control, including a valid JSON Schema field such as input_schema.properties.cache_control. If the budget is exceeded, _strip_first_cache_control() removes that schema property. Restrict detection to valid Anthropic cache-marker locations and add a schema-property regression test.
|
Closing as superseded by #76032 (merged), which lands tool-schema caching via a request-local breakpoint planner ( This PR and that planner take opposite positions on the same budget problem: this PR strips tool-level The sweeper's earlier notes on this PR also stand: the unconditional strip removed supported cross-session schema caching, and the recursive The underlying concern (never exceed the 4-block budget) is real and now guarded where the markers are planned rather than sanitized after the fact. Thanks for the report and the fix — the budget framing helped shape the review of the merged design. |
Summary
cache_controlmarkers into native Anthropic tool definitionsWhy
Anthropic enforces a hard request-wide limit of 4
cache_controlblocks across system, messages, and tools. Hermes' prompt caching strategy already uses the full budget for system + recent messages. If a tool/schema marker is forwarded as well, native Anthropic rejects the request with:The sanitizer strips extras before the SDK call, preferring tools first because tool-schema caching is not currently part of Hermes' budgeted placement strategy.
Test plan
python3 -m pytest tests/agent/test_prompt_caching.py -qResult:
16 passed