Repository navigation
fix(responses): propagate message cache_control through Responses->Chat transform (LIT-2594) - #29166
Conversation
|
|
Greptile SummaryThis PR fixes a silent bug where
Confidence Score: 5/5Safe to merge — the change is a minimal, well-scoped propagation of an existing field with no side-effects on unrelated code paths. The fix touches only the else-branch of the input-item transform (tool-call and function-call paths are untouched), adds a type-safe field to GenericChatCompletionMessage, and is protected by 10 focused tests including a no-injection-points regression baseline. No existing behaviour is altered when cache_control is absent. No files require special attention.
|
| Filename | Overview |
|---|---|
| litellm/responses/litellm_completion_transformation/transformation.py | Propagates cache_control from Responses-API input items onto GenericChatCompletionMessage; logic is correct and the isinstance(input_item, dict) guard is safe since TypedDicts are dict instances in Python. |
| litellm/types/llms/openai.py | Adds cache_control: ChatCompletionCachedContent to GenericChatCompletionMessage, making it consistent with all other concrete message TypedDicts and removing the need for a type-ignore comment. |
| tests/test_litellm/responses/litellm_completion_transformation/test_cache_control_propagation_lit_2594.py | 10 new pure-unit tests (no real network calls) covering the transform in isolation and the full Anthropic pipeline; good regression coverage including the no-injection-points baseline. |
Reviews (2): Last reviewed commit: "style: drop type:ignore now that Generic..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…he_control (LIT-2594)
|
@greptileai please re-review — addressed P2 from the prior review by adding |
edelauna
left a comment
There was a problem hiding this comment.
Would like this fix please 🙏
| cache_control = ( | ||
| input_item.get("cache_control") | ||
| if isinstance(input_item, dict) | ||
| else None |
There was a problem hiding this comment.
Checking isinstance(input_item, dict) will silently drop cache_control if messages are passed in as pre-parsed objects or Pydantic models (such as ChatCompletionSystemMessageParam or ResponseInputTextParam) rather than standard Python dictionaries.
Let's add a fallback check to extract the property from object attributes using hasattr/getattr to make this completely bulletproof:
| else None | |
| else getattr(input_item, "cache_control", None) |
Summary
cache_control_injection_pointsconfigured on a Responses API request was silently dropped before the messages reached the provider transform, so prompt caching on the Responses path was a no-op for both Anthropic and Bedrock Converse Anthropic models.Root cause
AnthropicCacheControlHook.get_chat_completion_promptcorrectly attachescache_controlto each input message in chat-completion form (when the input items have arolefield). But the next step in the Responses pipeline --LiteLLMCompletionResponsesConfig._transform_responses_api_input_item_to_chat_completion_message-- constructed:without forwarding any other fields, so the message-level
cache_controlwas dropped on the floor.anthropic_messages_ptandAnthropicConfig.translate_system_messageboth read top-levelcache_controlon string-content messages, but they never saw it.Fix
In the else-branch of
_transform_responses_api_input_item_to_chat_completion_message, after building theGenericChatCompletionMessage, propagatecache_controlfrom the input item onto the resulting message dict when present. Existing behaviour for tool-call / function-call input items (which have their own transforms and do not carry message-levelcache_control) is unchanged.Diff is 23 lines on the source file (one-line propagation + comment) plus 195 lines of regression tests.
Tests
10 new tests in
tests/test_litellm/responses/litellm_completion_transformation/test_cache_control_propagation_lit_2594.py:AnthropicCacheControlHook -> Responses-Chat transform -> AnthropicConfig.translate_system_message + anthropic_messages_ptto assert that:cache_controlcache_controlcache_control(no leak)cache_controlanywhere (regression safety net)All 10 tests pass. Full surrounding suite (
tests/test_litellm/responses/litellm_completion_transformation/+tests/test_litellm/integrations/test_anthropic_cache_control_hook.py) is 130 passed, 0 failed.Evidence
Drove the exact bug-report flow (Responses API input with
cache_control_injection_pointson system + last user, large system prompt) throughAnthropicCacheControlHook -> Responses-Chat transform -> AnthropicConfig.translate_system_message + anthropic_messages_pt.BEFORE (clean
litellm_oss_agent_shin_daily_branchHEAD1fe911d8):AFTER (this branch):
Repro script: a 60-line Python harness that builds the bug-report input, drives the hook, runs the transform, then calls
AnthropicConfig.translate_system_message+anthropic_messages_ptand prints the cache_control state at every stage. Same script run on both branches with only the source file swapped.Notes
GITHUB_TOKENlacksrepo+workflowscope for directgit push. Merge-base diff is therefore noisier than the actual change -- the real diff is the two files in this PR.litellm_oss_agent_shin_daily_branchper the Shin fork-PR policy.Session: https://litellm-agent-platform.onrender.com/sessions/75246fbc-562e-44c4-8fb8-032ac0cb2bda
Verification (ship-pr)
litellm_oss_agent_shin_daily_branch(Shin fork-PR policy)### Evidencewith BEFORE/AFTER captured from the realAnthropicCacheControlHook -> Responses->Chat transform -> AnthropicConfig.translate_system_message + anthropic_messages_ptchain1a2bd369(unit-test, lint, semgrep, secret-scan, code-quality, build-ui, validate-model-prices-json, test-server-root-path x2, Codecov, every proxy-* and provider test suite). Only outstanding check isVeria AI - PR Reviewwhich has beenin_progressfor >25 min with no annotations or output -- known intermittent flake (see prior LIT-3320 / LIT-2553 session notes). No security-relevant code paths were touched (the change copies an already-validated dict field onto another dict).test_string_user_message_with_cache_control_is_preservedand 5 sibling unit tests (Codecov upload races on multi-shard runs and frequently underreports patch coverage on this repo).