Skip to content

Commit 41640aa

Browse files
authored
Add base64 encoding to tool_return_ta (#2186)
1 parent 1130748 commit 41640aa

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

pydantic_ai_slim/pydantic_ai/messages.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ def otel_event(self, settings: InstrumentationSettings) -> Event:
433433
__repr__ = _utils.dataclasses_no_defaults_repr
434434

435435

436-
tool_return_ta: pydantic.TypeAdapter[Any] = pydantic.TypeAdapter(Any, config=pydantic.ConfigDict(defer_build=True))
436+
tool_return_ta: pydantic.TypeAdapter[Any] = pydantic.TypeAdapter(
437+
Any, config=pydantic.ConfigDict(defer_build=True, ser_json_bytes='base64', val_json_bytes='base64')
438+
)
437439

438440

439441
@dataclass(repr=False)

tests/test_agent.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2934,6 +2934,47 @@ def test_binary_content_all_messages_json():
29342934
assert messages == result.all_messages()
29352935

29362936

2937+
def test_tool_return_part_binary_content_serialization():
2938+
"""Test that ToolReturnPart can properly serialize BinaryContent."""
2939+
png_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc```\x00\x00\x00\x04\x00\x01\xf6\x178\x00\x00\x00\x00IEND\xaeB`\x82'
2940+
binary_content = BinaryContent(png_data, media_type='image/png')
2941+
2942+
tool_return = ToolReturnPart(tool_name='test_tool', content=binary_content, tool_call_id='test_call_123')
2943+
2944+
response_str = tool_return.model_response_str()
2945+
2946+
assert '"kind":"binary"' in response_str
2947+
assert '"media_type":"image/png"' in response_str
2948+
assert '"data":"' in response_str
2949+
2950+
response_obj = tool_return.model_response_object()
2951+
assert response_obj['return_value']['kind'] == 'binary'
2952+
assert response_obj['return_value']['media_type'] == 'image/png'
2953+
assert 'data' in response_obj['return_value']
2954+
2955+
2956+
def test_tool_returning_binary_content_directly():
2957+
"""Test that a tool returning BinaryContent directly works correctly."""
2958+
2959+
def llm(messages: list[ModelMessage], info: AgentInfo) -> ModelResponse:
2960+
if len(messages) == 1:
2961+
return ModelResponse(parts=[ToolCallPart('get_image', {})])
2962+
else:
2963+
return ModelResponse(parts=[TextPart('Image received')])
2964+
2965+
agent = Agent(FunctionModel(llm))
2966+
2967+
@agent.tool_plain
2968+
def get_image() -> BinaryContent:
2969+
"""Return a simple image."""
2970+
png_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc```\x00\x00\x00\x04\x00\x01\xf6\x178\x00\x00\x00\x00IEND\xaeB`\x82'
2971+
return BinaryContent(png_data, media_type='image/png')
2972+
2973+
# This should work without the serialization error
2974+
result = agent.run_sync('Get an image')
2975+
assert result.output == 'Image received'
2976+
2977+
29372978
def test_instructions_raise_error_when_system_prompt_is_set():
29382979
agent = Agent('test', instructions='An instructions!')
29392980

0 commit comments

Comments
 (0)