Skip to content

Commit 6fab8a1

Browse files
JackYPCOnlineUnshure
authored andcommitted
fix: filter 'SDK_UNKNOWN_MEMBER' from response content (strands-agents#798)
Co-authored-by: Jack Yuan <[email protected]>
1 parent d5d9b18 commit 6fab8a1

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

src/strands/models/bedrock.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def get_config(self) -> BedrockConfig:
180180
def _should_include_tool_result_status(self) -> bool:
181181
"""Determine whether to include tool result status based on current config."""
182182
include_status = self.config.get("include_tool_result_status", "auto")
183-
183+
184184
if include_status is True:
185185
return True
186186
elif include_status is False:
@@ -275,6 +275,7 @@ def _format_bedrock_messages(self, messages: Messages) -> Messages:
275275
"""Format messages for Bedrock API compatibility.
276276
277277
This function ensures messages conform to Bedrock's expected format by:
278+
- Filtering out SDK_UNKNOWN_MEMBER content blocks
278279
- Cleaning tool result content blocks by removing additional fields that may be
279280
useful for retaining information in hooks but would cause Bedrock validation
280281
exceptions when presented with unexpected fields
@@ -292,11 +293,17 @@ def _format_bedrock_messages(self, messages: Messages) -> Messages:
292293
https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolResultBlock.html
293294
"""
294295
cleaned_messages = []
296+
filtered_unknown_members = False
295297

296298
for message in messages:
297299
cleaned_content: list[ContentBlock] = []
298300

299301
for content_block in message["content"]:
302+
# Filter out SDK_UNKNOWN_MEMBER content blocks
303+
if "SDK_UNKNOWN_MEMBER" in content_block:
304+
filtered_unknown_members = True
305+
continue
306+
300307
if "toolResult" in content_block:
301308
# Create a new content block with only the cleaned toolResult
302309
tool_result: ToolResult = content_block["toolResult"]
@@ -323,6 +330,12 @@ def _format_bedrock_messages(self, messages: Messages) -> Messages:
323330
# Create new message with cleaned content
324331
cleaned_message: Message = Message(content=cleaned_content, role=message["role"])
325332
cleaned_messages.append(cleaned_message)
333+
334+
if filtered_unknown_members:
335+
logger.warning(
336+
"Filtered out SDK_UNKNOWN_MEMBER content blocks from messages, consider upgrading boto3 version"
337+
)
338+
326339
return cleaned_messages
327340

328341
def _has_blocked_guardrail(self, guardrail_data: dict[str, Any]) -> bool:

tests/strands/models/test_bedrock.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,15 +1331,15 @@ def test_format_request_removes_status_field_when_configured(model, model_id):
13311331
def test_auto_behavior_anthropic_vs_non_anthropic(bedrock_client):
13321332
model_anthropic = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0")
13331333
assert model_anthropic.get_config()["include_tool_result_status"] == "auto"
1334-
1334+
13351335
model_non_anthropic = BedrockModel(model_id="amazon.titan-text-v1")
13361336
assert model_non_anthropic.get_config()["include_tool_result_status"] == "auto"
13371337

13381338

13391339
def test_explicit_boolean_values_preserved(bedrock_client):
13401340
model = BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0", include_tool_result_status=True)
13411341
assert model.get_config()["include_tool_result_status"] is True
1342-
1342+
13431343
model2 = BedrockModel(model_id="amazon.titan-text-v1", include_tool_result_status=False)
13441344
assert model2.get_config()["include_tool_result_status"] is False
13451345
"""Test that format_request keeps status field by default for anthropic.claude models."""
@@ -1368,3 +1368,27 @@ def test_explicit_boolean_values_preserved(bedrock_client):
13681368
expected = {"content": [{"text": "Tool output"}], "toolUseId": "tool123", "status": "success"}
13691369
assert tool_result == expected
13701370
assert "status" in tool_result
1371+
1372+
1373+
def test_format_request_filters_sdk_unknown_member_content_blocks(model, model_id, caplog):
1374+
"""Test that format_request filters out SDK_UNKNOWN_MEMBER content blocks."""
1375+
messages = [
1376+
{
1377+
"role": "assistant",
1378+
"content": [
1379+
{"text": "Hello"},
1380+
{"SDK_UNKNOWN_MEMBER": {"name": "reasoningContent"}},
1381+
{"text": "World"},
1382+
],
1383+
}
1384+
]
1385+
1386+
formatted_request = model.format_request(messages)
1387+
1388+
content = formatted_request["messages"][0]["content"]
1389+
assert len(content) == 2
1390+
assert content[0] == {"text": "Hello"}
1391+
assert content[1] == {"text": "World"}
1392+
1393+
for block in content:
1394+
assert "SDK_UNKNOWN_MEMBER" not in block

0 commit comments

Comments
 (0)