diff --git a/pydantic_ai_slim/pydantic_ai/ui/vercel_ai/_adapter.py b/pydantic_ai_slim/pydantic_ai/ui/vercel_ai/_adapter.py index 855a9dc3a7..52b7d3d656 100644 --- a/pydantic_ai_slim/pydantic_ai/ui/vercel_ai/_adapter.py +++ b/pydantic_ai_slim/pydantic_ai/ui/vercel_ai/_adapter.py @@ -272,7 +272,13 @@ def load_messages(cls, messages: Sequence[UIMessage]) -> list[ModelMessage]: # user_prompt_content: str | list[UserContent] = [] for part in msg.parts: if isinstance(part, TextUIPart): - user_prompt_content.append(part.text) + provider_meta = load_provider_metadata(part.provider_metadata) + if 'metadata' in provider_meta: + user_prompt_content.append( + TextContent(content=part.text, metadata=provider_meta['metadata']) + ) + else: + user_prompt_content.append(part.text) elif isinstance(part, FileUIPart): try: file = BinaryContent.from_data_uri(part.url) @@ -884,7 +890,13 @@ def _convert_user_prompt_part(part: UserPromptPart) -> list[UIMessagePart]: if isinstance(item, str): ui_parts.append(TextUIPart(text=item, state='done')) elif isinstance(item, TextContent): - ui_parts.append(TextUIPart(text=item.content, state='done')) + ui_parts.append( + TextUIPart( + text=item.content, + state='done', + provider_metadata=dump_provider_metadata(metadata=item.metadata), + ) + ) elif isinstance(item, BinaryContent): ui_parts.append(FileUIPart(url=item.data_uri, media_type=item.media_type)) elif isinstance(item, ImageUrl | AudioUrl | VideoUrl | DocumentUrl): diff --git a/tests/test_vercel_ai.py b/tests/test_vercel_ai.py index f51e429363..03f29767fe 100644 --- a/tests/test_vercel_ai.py +++ b/tests/test_vercel_ai.py @@ -5792,7 +5792,48 @@ async def test_convert_user_prompt_part_text_content(): part = UserPromptPart(content=['Just some text', TextContent(content='More text', metadata={'key': 'value'})]) ui_parts = _convert_user_prompt_part(part) assert ui_parts == snapshot( - [TextUIPart(text='Just some text', state='done'), TextUIPart(text='More text', state='done')] + [ + TextUIPart(text='Just some text', state='done'), + TextUIPart( + text='More text', + state='done', + provider_metadata={'pydantic_ai': {'metadata': {'key': 'value'}}}, + ), + ] + ) + + +async def test_adapter_text_content_metadata_roundtrip(): + original_messages = [ + ModelRequest( + parts=[ + UserPromptPart( + content=[ + 'Just some text', + TextContent(content='More text', metadata={'key': 'value'}), + ] + ) + ] + ) + ] + + ui_messages = VercelAIAdapter.dump_messages(original_messages) + reloaded_messages = VercelAIAdapter.load_messages(ui_messages) + + assert reloaded_messages == snapshot( + [ + ModelRequest( + parts=[ + UserPromptPart( + content=[ + 'Just some text', + TextContent(content='More text', metadata={'key': 'value'}), + ], + timestamp=IsDatetime(), + ) + ] + ) + ] )