2121 BuiltinToolReturnPart ,
2222 FilePart ,
2323 FileUrl ,
24+ DocumentUrl ,
2425 FinishReason ,
2526 ModelMessage ,
2627 ModelRequest ,
9192 'you can use the `google` optional group — `pip install "pydantic-ai-slim[google]"`'
9293 ) from _import_error
9394
95+
96+ class Test ():
97+ def __init__ (self , num ):
98+ self .num = num
99+ def multiply (self ):
100+ return self .num * 3
101+
94102LatestGoogleModelNames = Literal [
95103 'gemini-2.0-flash' ,
96104 'gemini-2.0-flash-lite' ,
@@ -567,17 +575,34 @@ async def _map_user_prompt(self, part: UserPromptPart) -> list[PartDict]:
567575 if isinstance (item , str ):
568576 content .append ({'text' : item })
569577 elif isinstance (item , BinaryContent ):
570- inline_data_dict : BlobDict = {'data' : item .data , 'mime_type' : item .media_type }
571- part_dict : PartDict = {'inline_data' : inline_data_dict }
572- if item .vendor_metadata :
573- part_dict ['video_metadata' ] = cast (VideoMetadataDict , item .vendor_metadata )
574- content .append (part_dict )
578+ if self ._is_text_like_media_type (item .media_type ):
579+ content .append ({'text' : item .data .decode ('utf-8' )})
580+ else :
581+ inline_data_dict : BlobDict = {'data' : item .data , 'mime_type' : item .media_type }
582+ part_dict : PartDict = {'inline_data' : inline_data_dict }
583+ if item .vendor_metadata :
584+ part_dict ['video_metadata' ] = cast (VideoMetadataDict , item .vendor_metadata )
585+ content .append (part_dict )
586+
587+ elif isinstance (item , DocumentUrl ):
588+ if self ._is_text_like_media_type (item .media_type ):
589+ downloaded_text = await download_item (item , data_format = 'text' )
590+ content .append ({'text' : downloaded_text ['data' ]})
591+ else :
592+ downloaded_item = await download_item (item , data_format = 'bytes' )
593+ inline_data_dict : BlobDict = {
594+ 'data' : downloaded_item ['data' ],
595+ 'mime_type' : downloaded_item ['data_type' ],
596+ }
597+ content .append ({'inline_data' : inline_data_dict })
598+
575599 elif isinstance (item , VideoUrl ) and item .is_youtube :
576600 file_data_dict : FileDataDict = {'file_uri' : item .url , 'mime_type' : item .media_type }
577601 part_dict : PartDict = {'file_data' : file_data_dict }
578602 if item .vendor_metadata : # pragma: no branch
579603 part_dict ['video_metadata' ] = cast (VideoMetadataDict , item .vendor_metadata )
580604 content .append (part_dict )
605+
581606 elif isinstance (item , FileUrl ):
582607 if item .force_download or (
583608 # google-gla does not support passing file urls directly, except for youtube videos
@@ -596,7 +621,29 @@ async def _map_user_prompt(self, part: UserPromptPart) -> list[PartDict]:
596621 content .append ({'file_data' : file_data_dict }) # pragma: lax no cover
597622 else :
598623 assert_never (item )
599- return content
624+
625+ return content
626+
627+ @staticmethod
628+ def _is_text_like_media_type (media_type : str ) -> bool :
629+ return (
630+ media_type .startswith ('text/' )
631+ or media_type == 'application/json'
632+ or media_type .endswith ('+json' )
633+ or media_type == 'application/xml'
634+ or media_type .endswith ('+xml' )
635+ or media_type in ('application/x-yaml' , 'application/yaml' )
636+ )
637+ @staticmethod
638+ def _inline_text_file_part (text : str , * , media_type : str , identifier : str ) -> ChatCompletionContentPartTextParam :
639+ text = '\n ' .join (
640+ [
641+ f'-----BEGIN FILE id="{ identifier } " type="{ media_type } "-----' ,
642+ text ,
643+ f'-----END FILE id="{ identifier } "-----' ,
644+ ]
645+ )
646+ return {'text' : text }
600647
601648 def _map_response_schema (self , o : OutputObjectDefinition ) -> dict [str , Any ]:
602649 response_schema = o .json_schema .copy ()
0 commit comments