Repository navigation
fix(responses): preserve prompt cache reuse in chat bridge - #42281
ryan-crabbe-berri merged 5 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
|
@greptileai Please review the updated cache-mode fix and confirm multimodal breakpoint preservation remains complete across the Chat-to-Responses bridge. |
20520b3 to
f9764fa
Compare
6d84883 to
b1084f0
Compare
|
@greptileai review latest head |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit b1084f0. Configure here.
There was a problem hiding this comment.
LGTM. Verified live against OpenAI that implicit mode keeps the explicit marks and reads back the previous turn's prefix. Docs follow-up incoming for making the implicitl default change and then also documenting what we do by default in the other scenarios here
…ady routes the hook #42281 landed the text, image_url and file branch carry and the implicit default on main, and the Responses routing lookup this branch changed has no observable effect there, so the PR shrinks to the unknown-block fallback branch and its regression test
…es (#40032) * fix(responses): keep cache breakpoints on requests that reach the Responses API The chat-completions bridge rebuilt every content block without the prompt_cache_breakpoint marker the cache-control hook had just placed on it, so the request went out with prompt_cache_options set to explicit mode and nothing actually marked. Explicit mode caches only what is marked, so those deployments lost the implicit caching they were getting before the injection point was added The native surface had a second miss. The bridging check looked the provider config up with the still-prefixed model while the config keys on the bare one, so every bedrock_mantle model read as having no native Responses support, and role-targeted injection points were deferred to a chat-completions pass that never runs for them * fix(responses): keep prompt cache breakpoint on stringified content blocks * test: cover the responses/ routing prefix in the native cache point case * fix(responses): keep only the fallback-branch marker carry, main already routes the hook #42281 landed the text, image_url and file branch carry and the implicit default on main, and the Responses routing lookup this branch changed has no observable effect there, so the PR shrinks to the unknown-block fallback branch and its regression test * fix(responses): drop a malformed prompt_cache_breakpoint under drop_params in the chat-to-Responses bridge * fix(responses): accept the 30m prompt_cache_breakpoint ttl under drop_params OpenAI's Responses API takes a ttl of 30m on an explicit breakpoint marker, so the drop_params validation keeps it instead of stripping it as an unknown key. Trims the bridge test docstrings to the dated vendor citation. * test(integration): audit cells for prompt_cache_breakpoint through the chat-to-Responses bridge Adds the /audit cells for the bridge's prompt_cache_breakpoint carry: valid and malformed markers on every carrying block kind and on tool and assistant content, the drop_params on and off contract, the hook-injected system marker, the Anthropic SDK path through the Responses adapter, upstream errors, idempotent spend rows, and the chaos cells (mixed burst, upstream outage, slow streams, worker SIGKILL and a proxy restart mid burst), all against a scripted Responses endpoint with the request it received read back by response id * test(integration): give every scripted responses reply its own id The prompt-cache-breakpoint audit's scripted upstream minted the response id from the request's marker, so three identical marked requests shared one id. The spend-log writer skips rows whose request_id already landed, and the idempotent-logging cell saw one row for three calls on every leg. The upstream now mints a unique id per reply like a real provider, and the cells match a response to its request by the marker inside that id.
…breakpoint an input item Since this branch was cut, main carries prompt_cache_breakpoint markers through the bridge on input items' content blocks (BerriAI#42281, BerriAI#44119, BerriAI#45500), and its tests expect a leading system message whose block carries one to stay an input item so the marker survives. Folding that message into `instructions` dropped the marker and broke eight of those tests. The fold now skips a leading system message any of whose blocks carries a prompt_cache_breakpoint, alongside the non-text case it already skipped. A block with only cache_control, the shape BerriAI#42171 reports, still folds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TLDR
Problem this solves:
How it solves it:
User Flow
Before: an agent with growing tool history keeps rewriting previously cached input
POST https://litellm-domain/v1/chat/completionswith tools, medium reasoning, and automatic cache injectionAfter: each turn reuses the previous eligible tool boundary and writes only its new suffix
Pre-Submission checklist
Screenshots / Proof of Fix
The same three growing tool turns were captured from the exact production image and replayed through the real upstream provider. The six bounded calls cost $0.1265075 total
Before (cdcbf2f)
prompt_cache_options.mode: explicit0,1725, and17252280,1110, and1665After (b1084f0, patch-equivalent live run at 6d84883)
prompt_cache_options.mode: implicitwhile retaining explicit breakpoints0,2280, and28352280,555, and555Test Plan
20 passed, 735 deselectedacross the focused cache and Responses tests on the rebased tipType
Bug Fix
Test
Final Attestation
Note
Medium Risk
Changes upstream prompt-cache semantics (implicit vs explicit) and request payload shape for cached agent/tool conversations; incorrect behavior would affect cache hit rates and cost but is limited to OpenAI prompt-cache breakpoint flows with tests covering overrides.
Overview
Fixes prompt-cache reuse when chat completions are bridged to the Responses API and when LiteLLM auto-injects cache breakpoints for OpenAI GPT ≥5.6.
The chat→Responses converter now copies
prompt_cache_breakpointonto converted text, image_url, and file content blocks viawith_prompt_cache_breakpoint, so injected marks are not dropped mid-bridge. On the OpenAI-dialect chat path, when the cache hook newly places breakpoints it defaultsprompt_cache_options.modetoimplicitinstead ofexplicit, while per-block breakpoints stay explicit and caller-suppliedprompt_cache_options(including TTL) are unchanged.Tests assert breakpoint survival through
transform_requestand update expectations for the implicit default on chat/completions and Responses request bodies.Reviewed by Cursor Bugbot for commit b1084f0. Bugbot is set up for automated code reviews on this repo. Configure here.