-
-
Notifications
You must be signed in to change notification settings - Fork 48
fix(prompt-cache): repair Bedrock Converse mapping and gate injection by model capability#76
Merged
veerareddyvishal144 merged 2 commits intoJun 18, 2026
Conversation
invokeModel runs injectPromptCaching() before dispatch, which rewrites a
string `system` field and message `content` into Anthropic cache_control
blocks (arrays of `{ type, text, cache_control }`). The Bedrock Converse
path then copied only `c.text` from message blocks (dropping cache_control,
so Bedrock never caches) and wrapped the now-array `system` as
`{ text: <array> }`, which violates the Converse contract
(`system: [{ text: "<string>" }]`) and triggers a ValidationException.
Normalize the body for Converse before building the request: strip
cache_control and flatten any array-shaped system/content back to plain
strings. The Converse API has no cache_control concept, so this is the
correct shape. Normalization operates on a copy and leaves the caller's
body untouched.
Add test/databricks-bedrock-converse.test.js covering the post-injection
Converse shape.
needsCacheInjection() only checks provider membership, so cache_control markers were injected for every model behind an explicit-cache provider. Aggregating providers like bedrock and openrouter route to many model families, and most (Llama, Mistral, Titan, Cohere, GPT, ...) do not support cache_control — injecting markers there produces request shapes the upstream model rejects or ignores. Add a model-capability check inside injectPromptCaching, which has access to the resolved model id (body._tierModel / body.model). The check is fail-open: Anthropic-only providers and unknown/absent model ids still inject, so the provider-only needsCacheInjection signature stays backward-compatible. Only families known not to support cache_control are skipped. Extend test/prompt-cache-injection.test.js with capability-gate coverage.
sumleo
commented
Jun 18, 2026
Contributor
Author
Hi @veerareddyvishal144, gentle nudge on this when you have a moment. It's a small, self-contained prompt-caching fix, and I'm happy to rebase or tweak anything if that would make review easier. Thanks for the project and your time!
vishalveerareddy123
commented
Jun 18, 2026
Collaborator
Hey
Thank you so much for your contribution
Give me sometime I shall review it once
@veerareddyvishal144
veerareddyvishal144
merged commit Jun 18, 2026
09977a5
into
Fast-Editor:main
1 check passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two related prompt-caching defects on the Bedrock / aggregating-provider paths.
invokeModelrunsinjectPromptCaching(body, provider)before dispatch, which rewrites stringsystemfields and messagecontentinto Anthropiccache_controlblocks. Two downstream problems follow from that:Bedrock Converse mapping is broken (
src/clients/databricks.js,invokeBedrock). The message map (content: ... c.text ...) copies onlyc.text, droppingcache_controlso Bedrock never actually caches. Worse, the system field is wrapped asconverseBody.system = [{ text: bedrockBody.system }]whilebedrockBody.systemis now an array of blocks — producingsystem: [{ text: [ ... ] }], which violates the Converse contract (system: [{ text: "<string>" }]) and triggers aValidationException.Injection is not gated by model capability (
src/clients/prompt-cache-injection.js,needsCacheInjection/injectPromptCaching).needsCacheInjectiononly checks provider membership inEXPLICIT_CACHE_PROVIDERS. Butbedrockandopenrouterroute to many model families, and most (Llama, Mistral, Titan, Cohere, GPT, ...) don't supportcache_control. Markers were injected regardless, yielding request shapes those models reject or silently ignore.Type of Change
Changes Made
src/clients/databricks.js): addednormalizeBodyForConverse(), called at the top ofinvokeBedrockbefore the Converse request is built. It stripscache_controland flattens any array-shapedsystem/ messagecontentback to plain strings (the Converse API has nocache_controlconcept). It works on a shallow copy, so the caller's body is untouched.src/clients/prompt-cache-injection.js): addedmodelSupportsCacheControl(body, provider)and call it insideinjectPromptCaching. It inspects the resolved model id (body._tierModel/body.model) and skips injection for families known not to supportcache_control. It is intentionally fail-open: Anthropic-only providers and unknown/absent model ids still inject, so the existing provider-onlyneedsCacheInjection(provider)signature and behavior are preserved.Testing
test/prompt-cache-injection.test.js, unchanged assertions still green)test/databricks-bedrock-converse.test.js— asserts that afterinjectPromptCaching(body, 'bedrock')the normalized Converse payload has a stringsystemand{ text: string }content blocks.test/prompt-cache-injection.test.jswith capability-gate cases (Claude allowed, Llama/Titan/Mistral/Cohere/GPT skipped, unknown model id still injects).node --testrunner)Checklist
Notes for reviewers
npm installagainst the default registry fails in my environment (the lockfile resolves to a private registry I can't reach), so I installed dev deps from the public npm registry to run eslint and the tests; the committedpackage-lock.jsonis unchanged. Linting the two touched source files adds zero new errors over the currentmainbaseline.