Skip to content

Commit 6d56b21

Browse files
committed
feat(opencode): add cache_point_ttl option for Bedrock provider
1 parent 1ee712e commit 6d56b21

3 files changed

Lines changed: 122 additions & 4 deletions

File tree

packages/opencode/src/config/provider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ export class Info extends Schema.Class<Info>("ProviderConfig")({
102102
description:
103103
"Timeout in milliseconds between streamed SSE chunks for this provider. If no chunk arrives within this window, the request is aborted.",
104104
}),
105+
cache_point_ttl: Schema.optional(Schema.Literals(["5m", "1h"])).annotate({
106+
description: "TTL for Bedrock cache points. Only applies to amazon-bedrock provider.",
107+
}),
105108
}),
106109
[Schema.Record(Schema.String, Schema.Any)],
107110
),

packages/opencode/src/provider/transform.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,16 @@ function normalizeMessages(
213213
return msgs
214214
}
215215

216-
function applyCaching(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
216+
function applyCaching(msgs: ModelMessage[], model: Provider.Model, options?: Record<string, unknown>): ModelMessage[] {
217217
const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
218218
const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
219219

220+
const ttl = options?.cache_point_ttl as string | undefined
221+
const bedrockCachePoint: Record<string, unknown> = { type: "default" }
222+
if (ttl) {
223+
bedrockCachePoint.ttl = ttl
224+
}
225+
220226
const providerOptions = {
221227
anthropic: {
222228
cacheControl: { type: "ephemeral" },
@@ -225,7 +231,7 @@ function applyCaching(msgs: ModelMessage[], model: Provider.Model): ModelMessage
225231
cacheControl: { type: "ephemeral" },
226232
},
227233
bedrock: {
228-
cachePoint: { type: "default" },
234+
cachePoint: bedrockCachePoint,
229235
},
230236
openaiCompatible: {
231237
cache_control: { type: "ephemeral" },
@@ -313,10 +319,12 @@ export function message(msgs: ModelMessage[], model: Provider.Model, options: Re
313319
model.id.includes("anthropic") ||
314320
model.id.includes("claude") ||
315321
model.api.npm === "@ai-sdk/anthropic" ||
316-
model.api.npm === "@ai-sdk/alibaba") &&
322+
model.api.npm === "@ai-sdk/alibaba" ||
323+
model.providerID.includes("bedrock") ||
324+
model.api.npm === "@ai-sdk/amazon-bedrock") &&
317325
model.api.npm !== "@ai-sdk/gateway"
318326
) {
319-
msgs = applyCaching(msgs, model)
327+
msgs = applyCaching(msgs, model, options)
320328
}
321329

322330
// Remap providerOptions keys from stored providerID to expected SDK key

packages/opencode/test/provider/transform.test.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,3 +3113,110 @@ describe("ProviderTransform.variants", () => {
31133113
})
31143114
})
31153115
})
3116+
3117+
describe("ProviderTransform.message - bedrock cache_point_ttl", () => {
3118+
const bedrockModel = {
3119+
id: "amazon-bedrock/anthropic.claude-opus-4-6",
3120+
providerID: "amazon-bedrock",
3121+
api: {
3122+
id: "anthropic.claude-opus-4-6",
3123+
url: "https://bedrock-runtime.us-east-1.amazonaws.com",
3124+
npm: "@ai-sdk/amazon-bedrock",
3125+
},
3126+
name: "Claude Opus 4.6",
3127+
capabilities: {
3128+
temperature: true,
3129+
reasoning: false,
3130+
attachment: true,
3131+
toolcall: true,
3132+
input: { text: true, audio: false, image: true, video: false, pdf: true },
3133+
output: { text: true, audio: false, image: false, video: false, pdf: false },
3134+
interleaved: false,
3135+
},
3136+
cost: {
3137+
input: 0.003,
3138+
output: 0.015,
3139+
cache: { read: 0.0003, write: 0.00375 },
3140+
},
3141+
limit: {
3142+
context: 200000,
3143+
output: 8192,
3144+
},
3145+
status: "active",
3146+
options: {},
3147+
headers: {},
3148+
} as any
3149+
3150+
test("should add ttl to bedrock cachePoint when cache_point_ttl is set to 5m", () => {
3151+
const msgs = [
3152+
{
3153+
role: "system",
3154+
content: "You are a helpful assistant.",
3155+
},
3156+
{
3157+
role: "user",
3158+
content: "Hello",
3159+
},
3160+
] as any[]
3161+
3162+
const result = ProviderTransform.message(msgs, bedrockModel, { cache_point_ttl: "5m" })
3163+
3164+
expect(result).toHaveLength(2)
3165+
expect(result[0].providerOptions?.bedrock?.cachePoint).toEqual({
3166+
type: "default",
3167+
ttl: "5m",
3168+
})
3169+
expect(result[1].providerOptions?.bedrock?.cachePoint).toEqual({
3170+
type: "default",
3171+
ttl: "5m",
3172+
})
3173+
})
3174+
3175+
test("should add ttl to bedrock cachePoint when cache_point_ttl is set to 1h", () => {
3176+
const msgs = [
3177+
{
3178+
role: "system",
3179+
content: "You are a helpful assistant.",
3180+
},
3181+
{
3182+
role: "user",
3183+
content: "Hello",
3184+
},
3185+
] as any[]
3186+
3187+
const result = ProviderTransform.message(msgs, bedrockModel, { cache_point_ttl: "1h" })
3188+
3189+
expect(result).toHaveLength(2)
3190+
expect(result[0].providerOptions?.bedrock?.cachePoint).toEqual({
3191+
type: "default",
3192+
ttl: "1h",
3193+
})
3194+
expect(result[1].providerOptions?.bedrock?.cachePoint).toEqual({
3195+
type: "default",
3196+
ttl: "1h",
3197+
})
3198+
})
3199+
3200+
test("should not add ttl to bedrock cachePoint when cache_point_ttl is not set", () => {
3201+
const msgs = [
3202+
{
3203+
role: "system",
3204+
content: "You are a helpful assistant.",
3205+
},
3206+
{
3207+
role: "user",
3208+
content: "Hello",
3209+
},
3210+
] as any[]
3211+
3212+
const result = ProviderTransform.message(msgs, bedrockModel, {})
3213+
3214+
expect(result).toHaveLength(2)
3215+
expect(result[0].providerOptions?.bedrock?.cachePoint).toEqual({
3216+
type: "default",
3217+
})
3218+
expect(result[1].providerOptions?.bedrock?.cachePoint).toEqual({
3219+
type: "default",
3220+
})
3221+
})
3222+
})

0 commit comments

Comments
 (0)