Repository navigation
Description
Summary
When a Bedrock Claude model's modelID is an application inference profile ARN, OpenCode sends no cachePoint blocks, so prompt caching is silently off. Every step pays the full input price. For us this took cached input from ~93% to 0% and more than doubled daily Bedrock cost.
Environment
- opencode version: 2.0.18 (bug is still present on
maininpackages/ai/src/protocols/utils/bedrock-cache.ts) - OS: Darwin 25.6.0 arm64 (macOS)
- Terminal: xterm-256color (also reproduced headless with
opencode run --standalone) - Shell: /bin/zsh
- Install/channel: latest
- Active plugins: none found in config
Reproduction
-
Configure a Bedrock provider (
@ai-sdk/amazon-bedrock/ built-in Bedrock route) with a Claude model whosemodelIDis an application inference profile ARN backed by Claude Sonnet:{ "providers": { "claude": { "models": { "global.anthropic.claude-sonnet-5": { "modelID": "arn:aws:bedrock:us-east-1:<account>:application-inference-profile/<id>", "compatibility": { "cacheFormat": "anthropic" } } } } } } -
Run a multi-step prompt:
opencode run --standalone --format json --model claude/global.anthropic.claude-sonnet-5 "Read a.txt with the read tool, then read it again, then reply DONE" -
Inspect the step usage in the JSON output.
-
Remove the
modelIDoverride (so the plain model ID is used) and repeat.
Expected Behavior
Caching works the same as with the plain model ID: step 1 writes the cache and later steps read it. A profile ARN is a recommended AWS way to tag cost per user or team. Using one should not turn off caching.
Actual Behavior
With the ARN, every step reports "cache":{"read":0,"write":0}, for example "input":11863 then "input":18431.
With the plain model ID, the same prompt gives "write":11860, then "read":11860, "write":6589.
compatibility.cacheFormat: "anthropic" does not help.
Additional Context
Cause, in packages/ai/src/protocols/utils/bedrock-cache.ts:
supported: modelID.includes("anthropic.claude-") && (...)The comment says substring matching handles "model-bearing ARNs". An application inference profile ARN (arn:aws:bedrock:<region>:<account>:application-inference-profile/<id>) carries no model name, so supported is always false.
Suggested fixes, any of:
- Use the configured model's catalog identity, such as the
modelsmap key,family, or thecanonicalmodel, rather than the rawmodelID. - Honor
compatibility.cacheFormat(or a Bedrock-specific flag) on the Bedrock Converse route to force cache points on.
Related: #53756 (same root cause: model family is read from an ARN, for effort variants), #53751.
Workaround: don't use profile ARNs, which loses per-user cost attribution.
Frequency: 100% reproducible.
Activity
opencode-agent commentedon Oct 16, 2026
Thanks for the detailed report and for tracing the cause. I could reproduce this on 2.0.18, and it still happens on the latest
dev(eeec76bb).Setup: a mock Bedrock runtime records each Converse request and counts its
cachePointblocks. OpenCode points at it throughproviders.amazon-bedrock.settings.baseURL, with a Claude Sonnet model andcompatibility.cacheFormat: "anthropic"./model/global.anthropic.claude-sonnet-4-5-.../converse-streamcarry 2 and 4cachePointblocks.modelIDset to an application inference profile ARN: the requests to/model/arn:aws:bedrock:...:application-inference-profile/abc123/converse-streamcarry 0, with or withoutcacheFormat: "anthropic".The mock can't show real cache read/write numbers, but with no cache points in the request Bedrock has nothing to cache, which fits the 0 read / 0 write you saw. As you found,
BedrockCache.breakpoints()decides support only from the wire model ID, which an application profile ARN doesn't contain.The script below reproduces it. Related: #53756 is the same ARN problem for effort variants, and PR #53820 addresses that part only.
Reproduction script (run.sh)
Run it:
bash run.sh