Skip to content

fix(agents): honor cacheRetention for custom anthropic providers#59049

Merged
vincentkoc merged 5 commits intomainfrom
vk/pr-58756-cache-retention
Apr 2, 2026
Merged

fix(agents): honor cacheRetention for custom anthropic providers#59049
vincentkoc merged 5 commits intomainfrom
vk/pr-58756-cache-retention

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • Problem: custom providers using the anthropic-messages API never honored explicit cacheRetention settings because retention was gated on provider id instead of model API.
  • Why it matters: Anthropic-compatible proxy/custom-provider users pay full prompt cost and lose cache behavior even when they explicitly configure retention.
  • What changed: thread model.api into cache-retention resolution and allow explicit retention for custom anthropic-messages providers; add targeted regression tests.
  • What did NOT change (scope boundary): direct Anthropic defaults stay the same, Bedrock behavior stays the same, and custom providers still do not get implicit caching unless they opt in.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause / Regression History (if applicable)

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/pi-embedded-runner/extra-params.cache-retention-default.test.ts
  • Scenario the test should lock in: explicit cacheRetention is passed through for custom providers using anthropic-messages, while the no-config default remains disabled.
  • Why this is the smallest reliable guardrail: the regression lives entirely in pre-stream extra-param resolution.
  • Existing test that already covers this (if any): existing direct Anthropic and Bedrock coverage in the same file.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Custom providers using anthropic-messages now honor explicit cacheRetention values. No behavior change for direct Anthropic or Bedrock users.

Diagram (if applicable)

Before:
custom anthropic-messages provider + cacheRetention=long -> provider-id gate fails -> no cache retention sent

After:
custom anthropic-messages provider + cacheRetention=long -> model-api gate passes -> cache retention sent

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node 22 / pnpm
  • Model/provider: custom provider with anthropic-messages
  • Integration/channel (if any): N/A
  • Relevant config (redacted): provider configured with explicit cacheRetention

Steps

  1. Configure a custom provider whose model reports api: "anthropic-messages".
  2. Set explicit cacheRetention in effective extra params.
  3. Run the stream path through pre-plugin wrappers.

Expected

  • Explicit cache retention is preserved for the request.

Actual

  • Before this change, cache retention was dropped for custom providers.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

  • Verified scenarios: custom anthropic-messages provider with explicit short and long retention; custom provider without explicit config stays unset.
  • Edge cases checked: direct Anthropic default path still uses short retention; explicit direct-Anthropic none/short/long behavior still covered.
  • What you did not verify: live provider round-trip against an external Anthropic-compatible proxy.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: a custom provider may advertise anthropic-messages but reject Anthropic cache fields.
    • Mitigation: custom providers only get retention when explicitly configured; there is no new implicit default for them.

@vincentkoc vincentkoc self-assigned this Apr 1, 2026
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S maintainer Maintainer-authored PR labels Apr 1, 2026
@vincentkoc
Copy link
Copy Markdown
Member Author

Supersedes #58756. Refreshed onto current main, revalidated locally, and kept the fix scoped to explicit cache retention for custom anthropic-messages providers.

@vincentkoc vincentkoc marked this pull request as ready for review April 1, 2026 14:01
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 1, 2026

Greptile Summary

This PR fixes a targeted bug where custom providers using the anthropic-messages API were silently ignored by resolveCacheRetention, causing explicitly-configured cacheRetention values to be dropped. The fix threads model.api through the call chain and adds a new isCustomAnthropicApi guard that activates cache retention for any provider reporting api === "anthropic-messages" when explicit config is present — without introducing implicit defaults.

Key changes:

  • resolveCacheRetention gains an optional modelApi parameter; the new isCustomAnthropicApi branch requires both modelApi === "anthropic-messages" and an explicit cacheRetention/cacheControlTtl value, so no implicit default is added for custom providers.
  • createStreamFnWithExtraParams and applyPrePluginStreamWrappers are updated to forward ctx.model?.api — all existing call sites that omit model are unaffected via optional chaining.
  • Direct Anthropic and Bedrock paths are unchanged, satisfying the stated scope boundary.
  • Three new test cases are added; the direct unit test for the "no default for custom provider" case is well-targeted. The two integration-style tests only assert streamFn is defined (always true due to unconditional wrappers), so they don't tightly lock in the cacheRetention injection itself — direct resolveCacheRetention unit tests for the \"long\"/\"short\" positive cases would provide stronger regression coverage.

Confidence Score: 5/5

Safe to merge; the logic change is minimal and well-scoped, with no behavior change for direct Anthropic or Bedrock users.

All findings are P2 style/test-coverage suggestions. The core fix in anthropic-cache-retention.ts is correct: the new guard requires both anthropic-messages API and explicit config, preserving existing defaults for all other providers. The optional chaining in extra-params.ts ensures backward compatibility. No P0 or P1 issues found.

No files require special attention; the only suggestions are about adding tighter direct unit tests in extra-params.cache-retention-default.test.ts.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/extra-params.cache-retention-default.test.ts
Line: 154-173

Comment:
**Integration tests only verify `streamFn` is defined, not that `cacheRetention` was applied**

`applyAndExpectWrapped` asserts `expect(agent.streamFn).toBeDefined()`, but `createAnthropicToolPayloadCompatibilityWrapper` is unconditionally applied inside `applyPrePluginStreamWrappers`, meaning `streamFn` will always be defined regardless of whether the `cacheRetention` path was exercised. The new tests at lines 154–173 and 179–198 would both pass even if `resolveCacheRetention` returned `undefined` for the custom provider path.

The one direct unit test (`resolveCacheRetention(undefined, "litellm", "anthropic-messages")` at line 175–177) correctly validates the no-default path. Consider adding similar direct-unit-test coverage for the positive cases (`"long"` / `"short"`) to lock in the actual regression scenario without relying on indirect `streamFn` presence:

```ts
it("passes cacheRetention 'long' through for custom anthropic-messages provider", () => {
  expect(
    resolveCacheRetention({ cacheRetention: "long" }, "litellm", "anthropic-messages"),
  ).toBe("long");
});

it("passes cacheRetention 'short' through for custom anthropic-messages provider", () => {
  expect(
    resolveCacheRetention({ cacheRetention: "short" }, "litellm", "anthropic-messages"),
  ).toBe("short");
});
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/extra-params.cache-retention-default.test.ts
Line: 175-177

Comment:
**`cacheRetention: "none"` for custom provider not covered**

The new tests cover `"long"` and `"short"` for custom `anthropic-messages` providers, but there is no test that a custom provider with `cacheRetention: "none"` actually passes `"none"` through (rather than being dropped). Given that `"none"` is the explicit opt-out value, a missed regression here could silently re-enable caching for providers that opted out. A direct unit test is straightforward:

```ts
it("passes cacheRetention 'none' through for custom anthropic-messages provider", () => {
  expect(
    resolveCacheRetention({ cacheRetention: "none" }, "litellm", "anthropic-messages"),
  ).toBe("none");
});
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Merge branch 'main' into vk/pr-58756-cac..." | Re-trigger Greptile

@wwerst
Copy link
Copy Markdown

wwerst commented Apr 1, 2026

@vincentkoc Thanks for picking this up! I fixed tests and addressed greptile comments in #59216

Anything I can help with to get this merged?

@wwerst
Copy link
Copy Markdown

wwerst commented Apr 1, 2026

#59216 tests passed. I rebased onto main, tests are running again now.

@vincentkoc
Copy link
Copy Markdown
Member Author

Addressed Greptile test coverage feedback in 46c05e8.

Added direct unit assertions for custom anthropic-messages providers so the regression is locked in at the actual decision point:

  • cacheRetention: "long" -> "long"
  • cacheRetention: "none" -> "none"
  • cacheRetention: "short" -> "short"
  • no explicit config -> undefined remains covered

This avoids relying on streamFn wrapping as a proxy for retention behavior.

Local verification:

  • pnpm test -- src/agents/pi-embedded-runner/extra-params.cache-retention-default.test.ts
  • pnpm check

@vincentkoc vincentkoc merged commit ed6012e into main Apr 2, 2026
135 of 136 checks passed
@vincentkoc vincentkoc deleted the vk/pr-58756-cache-retention branch April 2, 2026 05:34
ngutman pushed a commit that referenced this pull request Apr 3, 2026
)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
ancientitguybot-dev pushed a commit to KaiWalter/openclaw that referenced this pull request Apr 3, 2026
…nclaw#59049)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
steipete pushed a commit to duncanita/openclaw that referenced this pull request Apr 4, 2026
…nclaw#59049)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…nclaw#59049)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…nclaw#59049)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…nclaw#59049)

* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: S

Projects

None yet

2 participants