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
13 changes: 10 additions & 3 deletions instructor/providers/bedrock/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,10 +225,14 @@ def _to_bedrock_content_items(content: Any) -> list[dict[str, Any]]:
{"text":"..."}
{"image":{"format":"jpeg|png|gif|webp","source":{"bytes": <raw bytes>}}}
{"document":{"format":"pdf|csv|doc|docx|xls|xlsx|html|txt|md","name":"...","source":{"bytes": <raw bytes>}}}
{"cachePoint":{"type":"default"}}
Any other valid Bedrock ContentBlock dict (guardContent, toolUse,
toolResult, audio, video, reasoningContent, etc.)

Note:
- We do not validate or normalize Bedrock-native image/document blocks here.
Caller is responsible for providing valid 'format' and raw 'bytes'.
- We do not validate or normalize Bedrock-native blocks here.
Caller is responsible for providing valid structure.
The Bedrock API will reject malformed content blocks.
"""
# Plain string
if isinstance(content, str):
Expand Down Expand Up @@ -269,7 +273,10 @@ def _to_bedrock_content_items(content: Any) -> list[dict[str, Any]]:
items.append(p)
continue

raise ValueError(f"Unsupported dict content for Bedrock: {p}")
# Pass-through any other Bedrock-native content block (cachePoint,
# guardContent, toolUse, toolResult, audio, video, etc.)
items.append(p)
continue

# Plain string elements inside list
if isinstance(p, str):
Expand Down
49 changes: 49 additions & 0 deletions tests/llm/test_bedrock/test_bedrock_native_passthrough.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from __future__ import annotations

import pytest

from instructor.providers.bedrock.utils import _to_bedrock_content_items


Expand All @@ -18,3 +21,49 @@ def test_bedrock_native_document_passthrough(tiny_pdf_bytes: bytes):
native = {"document": {"format": "pdf", "source": {"bytes": tiny_pdf_bytes}}}
items = _to_bedrock_content_items([native])
assert items[0] == native


def test_bedrock_native_cachepoint_passthrough():
"""Regression test for #1954: cachePoint dicts must pass through."""
cache_point = {"cachePoint": {"type": "default"}}
items = _to_bedrock_content_items([cache_point])
assert items == [cache_point]


def test_bedrock_native_cachepoint_with_ttl():
cache_point = {"cachePoint": {"type": "default", "ttl": "5m"}}
items = _to_bedrock_content_items([cache_point])
assert items == [cache_point]


def test_bedrock_native_guard_content_passthrough():
guard = {"guardContent": {"text": {"text": "test content"}}}
items = _to_bedrock_content_items([guard])
assert items == [guard]


@pytest.mark.parametrize(
"block",
[
{"cachePoint": {"type": "default"}},
{"guardContent": {"text": {"text": "check this"}}},
{"video": {"format": "mp4", "source": {"bytes": b"fake"}}},
{"audio": {"format": "mp3", "source": {"bytes": b"fake"}}},
],
ids=["cachePoint", "guardContent", "video", "audio"],
)
def test_bedrock_native_content_block_passthrough(block: dict):
"""All Bedrock-native content blocks should pass through unchanged."""
items = _to_bedrock_content_items([block])
assert items == [block]


def test_mixed_content_with_cachepoint():
"""Regression test for #1954: cachePoint mixed with text in real usage."""
content = [
{"text": "Say hello world."},
{"cachePoint": {"type": "default"}},
{"text": "This is a test message."},
]
items = _to_bedrock_content_items(content)
assert items == content