Skip to content

Commit 5026f6c

Browse files
committed
style: format code with ruff formatter
1 parent 2a02388 commit 5026f6c

File tree

2 files changed

+168
-1
lines changed

2 files changed

+168
-1
lines changed

src/strands/models/bedrock.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,13 @@ def _format_request(
222222
)
223223
system_blocks.append({"cachePoint": {"type": cache_prompt}})
224224

225+
# Format system blocks (returns empty list if no system blocks provided)
226+
formatted_system_blocks = self._format_bedrock_system_blocks(system_blocks)
227+
225228
return {
226229
"modelId": self.config["model_id"],
227230
"messages": self._format_bedrock_messages(messages),
228-
"system": system_blocks,
231+
"system": formatted_system_blocks,
229232
**(
230233
{
231234
"toolConfig": {
@@ -295,6 +298,31 @@ def _format_request(
295298
),
296299
}
297300

301+
def _format_bedrock_system_blocks(self, system_blocks: list[SystemContentBlock] | None) -> list[dict[str, Any]]:
302+
"""Format system content blocks for Bedrock API compatibility.
303+
304+
Similar to _format_bedrock_messages, this ensures system blocks conform to
305+
Bedrock's strict validation requirements by eagerly filtering content blocks
306+
to only include Bedrock-supported fields.
307+
308+
Args:
309+
system_blocks: List of system content blocks to format
310+
311+
Returns:
312+
Formatted system blocks for Bedrock API compatibility (empty list if no blocks)
313+
"""
314+
if not system_blocks:
315+
return []
316+
317+
cleaned_blocks: list[dict[str, Any]] = []
318+
319+
for block in system_blocks:
320+
# Format the system block using the same logic as message content blocks
321+
formatted_block = self._format_request_message_content(cast(ContentBlock, block))
322+
cleaned_blocks.append(formatted_block)
323+
324+
return cleaned_blocks
325+
298326
def _format_bedrock_messages(self, messages: Messages) -> list[dict[str, Any]]:
299327
"""Format messages for Bedrock API compatibility.
300328

tests_integ/models/test_model_bedrock.py

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,3 +280,142 @@ def test_multi_prompt_system_content():
280280
agent = Agent(system_prompt=system_prompt_content, load_tools_from_directory=False)
281281
# just verifying there is no failure
282282
agent("Hello!")
283+
284+
285+
def test_message_cache_point_formatting(streaming_model):
286+
"""Test that cachePoint blocks in messages are formatted as separate content blocks.
287+
288+
This test verifies the fix for issue #1219 where cachePoint blocks were not being
289+
handled correctly, causing Bedrock API validation errors.
290+
"""
291+
# Create a message with cachePoint as a separate block
292+
messages = [
293+
{
294+
"role": "user",
295+
"content": [
296+
{"text": "Some content for caching " * 100}, # Long text to meet cache requirements
297+
{"cachePoint": {"type": "default"}},
298+
],
299+
},
300+
]
301+
302+
# Format the messages using the model's internal method
303+
formatted = streaming_model._format_bedrock_messages(messages)
304+
305+
# Verify cachePoint remains as a separate block
306+
assert len(formatted[0]["content"]) == 2
307+
assert "text" in formatted[0]["content"][0]
308+
assert "cachePoint" in formatted[0]["content"][1]
309+
# Verify they are not merged into a single block
310+
assert len(formatted[0]["content"][0]) == 1 # Only text key
311+
assert len(formatted[0]["content"][1]) == 1 # Only cachePoint key
312+
313+
314+
def test_system_prompt_cache_point_formatting(streaming_model):
315+
"""Test that cachePoint blocks in system prompts are formatted as separate content blocks.
316+
317+
This test verifies the fix for issue #1219 where system content blocks with cachePoint
318+
were not being formatted correctly.
319+
"""
320+
# Create system content with cachePoint as a separate block
321+
system_content = [
322+
{"text": "You are a helpful assistant. " * 100}, # Long text to meet cache requirements
323+
{"cachePoint": {"type": "default"}},
324+
{"text": "Always be respectful."},
325+
]
326+
327+
# Format the system blocks using the model's internal method
328+
formatted = streaming_model._format_bedrock_system_blocks(system_content)
329+
330+
# Verify we have 3 separate blocks
331+
assert len(formatted) == 3
332+
assert "text" in formatted[0]
333+
assert "cachePoint" in formatted[1]
334+
assert "text" in formatted[2]
335+
# Verify they are not merged
336+
assert len(formatted[0]) == 1 # Only text key
337+
assert len(formatted[1]) == 1 # Only cachePoint key
338+
assert len(formatted[2]) == 1 # Only text key
339+
340+
341+
def test_system_prompt_cache_point_agent(non_streaming_model):
342+
"""Test agent with system prompt containing cachePoint blocks.
343+
344+
This is an integration test that verifies the entire flow works correctly
345+
when using cachePoint in system prompts.
346+
"""
347+
system_prompt_content = [
348+
{"text": "You are a helpful assistant. " * 100},
349+
{"cachePoint": {"type": "default"}},
350+
{"text": "Always respond concisely."},
351+
]
352+
353+
agent = Agent(
354+
model=non_streaming_model,
355+
system_prompt=system_prompt_content,
356+
load_tools_from_directory=False,
357+
)
358+
359+
# Just verify there is no failure
360+
result = agent("Hello!")
361+
assert len(str(result)) > 0
362+
363+
364+
def test_message_with_cache_point_agent(streaming_model):
365+
"""Test agent with messages containing cachePoint blocks.
366+
367+
This is an integration test that verifies the entire flow works correctly
368+
when using cachePoint in messages.
369+
"""
370+
messages = [
371+
{
372+
"role": "user",
373+
"content": [
374+
{"text": "Previous conversation context. " * 100},
375+
{"cachePoint": {"type": "default"}},
376+
],
377+
},
378+
]
379+
380+
agent = Agent(
381+
model=streaming_model,
382+
messages=messages,
383+
load_tools_from_directory=False,
384+
)
385+
386+
# Just verify there is no failure
387+
result = agent("Hello!")
388+
assert len(str(result)) > 0
389+
390+
391+
def test_cache_point_with_system_and_messages(non_streaming_model):
392+
"""Test combining cachePoint in both system prompts and messages.
393+
394+
This test verifies that cachePoint works correctly when used in both
395+
system content blocks and message content blocks simultaneously.
396+
"""
397+
system_prompt_content = [
398+
{"text": "System context. " * 100},
399+
{"cachePoint": {"type": "default"}},
400+
]
401+
402+
messages = [
403+
{
404+
"role": "user",
405+
"content": [
406+
{"text": "Message context. " * 100},
407+
{"cachePoint": {"type": "default"}},
408+
],
409+
},
410+
]
411+
412+
agent = Agent(
413+
model=non_streaming_model,
414+
system_prompt=system_prompt_content,
415+
messages=messages,
416+
load_tools_from_directory=False,
417+
)
418+
419+
# Just verify there is no failure
420+
result = agent("Hello!")
421+
assert len(str(result)) > 0

0 commit comments

Comments
 (0)