From f7f8ab96ccc3fb7e384bb6af91d6d2a0e9492e8f Mon Sep 17 00:00:00 2001 From: Kien Pham Date: Tue, 10 Feb 2026 10:10:26 -0800 Subject: [PATCH] feat(cache): add TTL support to CachePoint for prompt caching Add optional ttl field to CachePoint TypedDict to support AWS Bedrock's cache TTL configuration. The field accepts "5m" or "1h" values as specified in the Bedrock API. Updated BedrockModel to preserve ttl field when formatting cache point content blocks. Includes tests for TTL preservation and backward compatibility. Co-Authored-By: Claude Sonnet 4.5 --- src/strands/models/bedrock.py | 6 +++- src/strands/types/content.py | 4 ++- tests/strands/models/test_bedrock.py | 47 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/strands/models/bedrock.py b/src/strands/models/bedrock.py index 596936e6f..095216fd6 100644 --- a/src/strands/models/bedrock.py +++ b/src/strands/models/bedrock.py @@ -492,7 +492,11 @@ def _format_request_message_content(self, content: ContentBlock) -> dict[str, An """ # https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_CachePointBlock.html if "cachePoint" in content: - return {"cachePoint": {"type": content["cachePoint"]["type"]}} + cache_point = content["cachePoint"] + result = {"type": cache_point["type"]} + if "ttl" in cache_point: + result["ttl"] = cache_point["ttl"] + return {"cachePoint": result} # https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_DocumentBlock.html if "document" in content: diff --git a/src/strands/types/content.py b/src/strands/types/content.py index d75dbb87f..164f199bb 100644 --- a/src/strands/types/content.py +++ b/src/strands/types/content.py @@ -8,7 +8,7 @@ from typing import Literal -from typing_extensions import TypedDict +from typing_extensions import NotRequired, TypedDict from .citations import CitationsContentBlock from .media import DocumentContent, ImageContent, VideoContent @@ -66,9 +66,11 @@ class CachePoint(TypedDict): Attributes: type: The type of cache point, typically "default". + ttl: Optional TTL duration for cache entries. Valid values are "5m" (5 minutes) or "1h" (1 hour). """ type: str + ttl: NotRequired[Literal["5m", "1h"]] class ContentBlock(TypedDict, total=False): diff --git a/tests/strands/models/test_bedrock.py b/tests/strands/models/test_bedrock.py index 1410e129b..a013f8e68 100644 --- a/tests/strands/models/test_bedrock.py +++ b/tests/strands/models/test_bedrock.py @@ -2050,6 +2050,53 @@ def test_format_request_filters_cache_point_content_blocks(model, model_id): assert "extraField" not in cache_point_block +def test_format_request_preserves_cache_point_ttl(model, model_id): + """Test that format_request preserves the ttl field in cachePoint content blocks.""" + messages = [ + { + "role": "user", + "content": [ + { + "cachePoint": { + "type": "default", + "ttl": "1h", + } + }, + ], + } + ] + + formatted_request = model._format_request(messages) + + cache_point_block = formatted_request["messages"][0]["content"][0]["cachePoint"] + expected = {"type": "default", "ttl": "1h"} + assert cache_point_block == expected + assert cache_point_block["ttl"] == "1h" + + +def test_format_request_cache_point_without_ttl(model, model_id): + """Test that cache points work without ttl field (backward compatibility).""" + messages = [ + { + "role": "user", + "content": [ + { + "cachePoint": { + "type": "default", + } + }, + ], + } + ] + + formatted_request = model._format_request(messages) + + cache_point_block = formatted_request["messages"][0]["content"][0]["cachePoint"] + expected = {"type": "default"} + assert cache_point_block == expected + assert "ttl" not in cache_point_block + + def test_config_validation_warns_on_unknown_keys(bedrock_client, captured_warnings): """Test that unknown config keys emit a warning.""" BedrockModel(model_id="test-model", invalid_param="test")