Stamp the effective cache policy onto outgoing requests so prefix protection reaches the wire - #148
Conversation
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…all.rs Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…cache_layout.rs Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…all.rs,crates/tinyagents-integr Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
…all.rs,crates/tinyagents-integr Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe harness now stamps inherited cache policy onto outgoing model requests when required. Breakpoint injection and provider adapters read the stamped policy. Integration tests cover protected and unprotected run policies. Documentation describes the policy flow. ChangesPrompt cache policy propagation
Vendor reference update
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Bug fix · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant AgentHarness
participant ModelCall
participant BreakpointLogic
participant ProviderAdapter
AgentHarness->>ModelCall: provide run-level CachePolicy
ModelCall->>ModelCall: stamp effective policy on request clone
ModelCall->>BreakpointLogic: process stamped request
BreakpointLogic->>BreakpointLogic: inject prompt_cache_key when protection is enabled
ModelCall->>ProviderAdapter: send stamped request
ProviderAdapter->>ProviderAdapter: evaluate wants_prompt_cache_breakpoints()
Merge Risk: ⚪ Minimal · up to The updated request policy flow preserves protected and unprotected prompt-cache behavior without an identified merge-blocking risk. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 2 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
A rabbit reads each line, Comment |
There was a problem hiding this comment.
tinysweeper found nothing blocking. Approving.
$0.0043 · 32,418 in / 2,997 out · 3,142 cached (10%) · deepseek/deepseek-v4-flash, z-ai/glm-5.2
critique: $0.0011 · 12,259 in / 577 out · 0 cached (0%) · deepseek/deepseek-v4-flash
security: $0.0017 · 7,379 in / 501 out · 3,142 cached (43%) · deepseek/deepseek-v4-flash, z-ai/glm-5.2
tests: $0.0007 · 5,108 in / 1,532 out · 0 cached (0%) · deepseek/deepseek-v4-flash
description: $0.0005 · 5,916 in / 63 out · 0 cached (0%) · deepseek/deepseek-v4-flash
Summary
RunPolicy::cache.protect_prompt_prefixwas inert on the wire. The agent loop resolved the effective cache policy (request-level, else the harnessRunPolicy::cache) and used it to decide whether to callapply_prompt_cache_breakpoints— but that function, and every provider adapter, readrequest.cache_policyalone, which the loop never sets. So a host that protected the prefix the documented way (on the run policy) got:prompt_cache_keyrouting hint inprovider_options, ever;cache_controlmarkers from the Anthropic adapter, ever;PromptCacheGuardMiddlewarethat kept reporting the prefix as protected.wave2_cache_layoutonly covered the request-level path (with_cache_policy), which is why this passed.The loop now stamps the effective policy onto the outgoing request (a clone — the original is what the response-cache key was derived from) before injecting the key and dispatching, so both readers see it. Stamping also runs when the run policy does not protect but a middleware declared cacheable segments: with the companion tinyinference change an adapter treats declared segments as the opt-in, and the run policy must be able to veto. The common path (no protection, no declared prefix) still pays for no clone.
Also pins
vendor/tinyinferenceto tinyhumansai/tinyinference#10, which suppliesModelRequest::wants_prompt_cache_breakpoints, a complete native Anthropic adapter (tools, streaming, three-marker placement), OpenRoutercache_control, and DeepSeek'sprompt_cache_hit_tokens. That PR should merge first; this one's submodule pointer then needs no change (the branch commit is on the upstream repo).API Or Behavior Changes
protect_prompt_prefixon the run policy and a declared cacheable prefix, outgoing requests now carrycache_policy: Some(<effective>)and a derivedprompt_cache_keyinprovider_options; with it off, they carrycache_policy: Some(<effective, protect=false>)when segments are declared, so adapters cannot opt in behind the host's back. The[cache]debug line per model call reportsprotect_prompt_prefix, whether a key was injected, and the cacheable-segment count.PROMPT_CACHE_KEY_OPTIONis unchanged; adapters that have no routing-key concept (Anthropic) consume and drop it.Tests
cargo fmt --checkcargo clippy --all-targets -- -D warningscargo clippy --all-targets --all-features -- -D warningscargo build --all-targetscargo build --all-targets --all-featurescargo test— all greencargo test --all-features— all greenNew:
wave2_cache_layout::run_policy_breakpointsdrives a realAgentHarnesswith a request-recording model and a middleware that declares the system prompt as cacheable (the way a host that assembles its own messages does), and pins both directions — a protecting run policy reaches the provider as a stamped policy plus atap-…prompt_cache_key; an unprotecting one is stamped as the veto and injects nothing.Documentation
docs/modules/harness/cache.mdgains "Whereprotect_prompt_prefixis read", describing the stamp, the two readers, and the regression.Summary by CodeRabbit
Bug Fixes
Documentation
Tests