Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/strands/models/bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,20 @@ def _inject_cache_point(self, messages: list[dict[str, Any]]) -> None:
last_user_idx = msg_idx

if last_user_idx is not None and messages[last_user_idx].get("content"):
messages[last_user_idx]["content"].append({"cachePoint": {"type": "default"}})
content = messages[last_user_idx]["content"]

# Insert before non-PDF document blocks to avoid Bedrock ValidationException
first_non_pdf_doc_idx = None
for i, block in enumerate(content):
if "document" in block and block["document"].get("format", "") != "pdf":
first_non_pdf_doc_idx = i
break

if first_non_pdf_doc_idx is not None:
content.insert(first_non_pdf_doc_idx, {"cachePoint": {"type": "default"}})
else:
content.append({"cachePoint": {"type": "default"}})

logger.debug("msg_idx=<%s> | added cache point to last user message", last_user_idx)

def _find_last_user_text_message_index(self, messages: Messages) -> int | None:
Expand Down
76 changes: 76 additions & 0 deletions tests/strands/models/test_bedrock.py
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,82 @@ def test_inject_cache_point_strips_existing_cache_points(bedrock_client):
assert "cachePoint" in cleaned_messages[2]["content"][-1]


def test_inject_cache_point_before_non_pdf_document(bedrock_client):
"""Test that cache point is inserted before non-PDF document blocks."""
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", cache_config=CacheConfig(strategy="auto")
)

cleaned_messages = [
{
"role": "user",
"content": [
{"text": "Analyze this file"},
{"document": {"format": "md", "name": "readme", "source": {"bytes": b"# Hello"}}},
],
},
]

model._inject_cache_point(cleaned_messages)

content = cleaned_messages[0]["content"]
assert len(content) == 3
assert content[0] == {"text": "Analyze this file"}
assert "cachePoint" in content[1]
assert "document" in content[2]


def test_inject_cache_point_after_pdf_document(bedrock_client):
"""Test that cache point is appended at end when only PDF documents are present."""
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", cache_config=CacheConfig(strategy="auto")
)

cleaned_messages = [
{
"role": "user",
"content": [
{"text": "Analyze this PDF"},
{"document": {"format": "pdf", "name": "report", "source": {"bytes": b"%PDF-1.4"}}},
],
},
]

model._inject_cache_point(cleaned_messages)

content = cleaned_messages[0]["content"]
assert len(content) == 3
assert "document" in content[1]
assert "cachePoint" in content[2]


def test_inject_cache_point_mixed_pdf_and_non_pdf_documents(bedrock_client):
"""Test that cache point is inserted before the first non-PDF document in mixed content."""
model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", cache_config=CacheConfig(strategy="auto")
)

cleaned_messages = [
{
"role": "user",
"content": [
{"text": "Analyze these files"},
{"document": {"format": "pdf", "name": "report", "source": {"bytes": b"%PDF-1.4"}}},
{"document": {"format": "csv", "name": "data", "source": {"bytes": b"a,b,c"}}},
],
},
]

model._inject_cache_point(cleaned_messages)

content = cleaned_messages[0]["content"]
assert len(content) == 4
assert "text" in content[0]
assert "document" in content[1] and content[1]["document"]["format"] == "pdf"
assert "cachePoint" in content[2]
assert "document" in content[3] and content[3]["document"]["format"] == "csv"


def test_inject_cache_point_anthropic_strategy_skips_model_check(bedrock_client):
"""Test that anthropic strategy injects cache point without model support check."""
model = BedrockModel(
Expand Down