2626 DocumentUrl ,
2727 FinishReason ,
2828 ImageUrl ,
29- MagicBinaryContent ,
30- MagicDocumentUrl ,
3129 ModelMessage ,
3230 ModelRequest ,
3331 ModelResponse ,
@@ -734,12 +732,7 @@ async def _map_user_prompt_items(items: Sequence[object]) -> list[ChatCompletion
734732 async def _map_single_item (item : object ) -> list [ChatCompletionContentPartParam ]:
735733 if isinstance (item , str ):
736734 return [ChatCompletionContentPartTextParam (text = item , type = 'text' )]
737- handled = await OpenAIChatModel ._handle_magic_document (item )
738- if handled is not None :
739- return handled
740- handled = await OpenAIChatModel ._handle_magic_binary (item )
741- if handled is not None :
742- return handled
735+ # Magic* no longer used; logic ported to base handlers
743736 handled = OpenAIChatModel ._handle_image_url (item )
744737 if handled is not None :
745738 return handled
@@ -757,55 +750,6 @@ async def _map_single_item(item: object) -> list[ChatCompletionContentPartParam]
757750 # Fallback: unknown type — return empty parts to avoid type-checker Never error
758751 return []
759752
760- @staticmethod
761- async def _handle_magic_document (item : object ) -> list [ChatCompletionContentPartParam ] | None :
762- if not isinstance (item , MagicDocumentUrl ):
763- return None
764- if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
765- downloaded = await download_item (item , data_format = 'text' , type_format = 'extension' )
766- filename = item .filename or f'file.{ downloaded ["data_type" ] or "txt" } '
767- inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , downloaded ['data' ])
768- return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
769- downloaded_item = await download_item (item , data_format = 'base64_uri' , type_format = 'extension' )
770- return [
771- File (
772- file = FileFile (
773- file_data = downloaded_item ['data' ],
774- filename = f'filename.{ downloaded_item ["data_type" ]} ' ,
775- ),
776- type = 'file' ,
777- )
778- ]
779-
780- @staticmethod
781- async def _handle_magic_binary (item : object ) -> list [ChatCompletionContentPartParam ] | None :
782- if not isinstance (item , MagicBinaryContent ):
783- return None
784- if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
785- text = item .data .decode ('utf-8' )
786- filename = item .filename or 'file.txt'
787- inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , text )
788- return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
789- base64_encoded = base64 .b64encode (item .data ).decode ('utf-8' )
790- if item .is_image :
791- image_url = ImageURL (url = f'data:{ item .media_type } ;base64,{ base64_encoded } ' )
792- return [ChatCompletionContentPartImageParam (image_url = image_url , type = 'image_url' )]
793- if item .is_audio :
794- assert item .format in ('wav' , 'mp3' )
795- audio = InputAudio (data = base64_encoded , format = item .format )
796- return [ChatCompletionContentPartInputAudioParam (input_audio = audio , type = 'input_audio' )]
797- if item .is_document :
798- return [
799- File (
800- file = FileFile (
801- file_data = f'data:{ item .media_type } ;base64,{ base64_encoded } ' ,
802- filename = f'filename.{ item .format } ' ,
803- ),
804- type = 'file' ,
805- )
806- ]
807- raise RuntimeError (f'Unsupported binary content type: { item .media_type } ' ) # pragma: no cover
808-
809753 @staticmethod
810754 def _handle_image_url (item : object ) -> list [ChatCompletionContentPartParam ] | None :
811755 if not isinstance (item , ImageUrl ):
@@ -817,6 +761,27 @@ def _handle_image_url(item: object) -> list[ChatCompletionContentPartParam] | No
817761 async def _handle_binary_content (item : object ) -> list [ChatCompletionContentPartParam ] | None :
818762 if not isinstance (item , BinaryContent ):
819763 return None
764+ if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
765+ # Inline text-like binary content as a text block
766+ text = item .data .decode ('utf-8' )
767+ # Derive a sensible default filename from media type
768+ media_type = item .media_type
769+ if media_type == 'text/plain' :
770+ filename = 'file.txt'
771+ elif media_type == 'text/csv' :
772+ filename = 'file.csv'
773+ elif media_type == 'text/markdown' :
774+ filename = 'file.md'
775+ elif media_type == 'application/json' or media_type .endswith ('+json' ):
776+ filename = 'file.json'
777+ elif media_type == 'application/xml' or media_type .endswith ('+xml' ):
778+ filename = 'file.xml'
779+ elif media_type in ('application/x-yaml' , 'application/yaml' , 'text/yaml' ):
780+ filename = 'file.yaml'
781+ else :
782+ filename = 'file.txt'
783+ inline = OpenAIChatModel ._inline_file_block (filename , media_type , text )
784+ return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
820785 base64_encoded = base64 .b64encode (item .data ).decode ('utf-8' )
821786 if item .is_image :
822787 image_url = ImageURL (url = f'data:{ item .media_type } ;base64,{ base64_encoded } ' )
@@ -852,6 +817,11 @@ async def _handle_audio_url(item: object) -> list[ChatCompletionContentPartParam
852817 async def _handle_document_url (item : object ) -> list [ChatCompletionContentPartParam ] | None :
853818 if not isinstance (item , DocumentUrl ):
854819 return None
820+ if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
821+ downloaded_text = await download_item (item , data_format = 'text' , type_format = 'extension' )
822+ filename = f'file.{ downloaded_text ["data_type" ] or "txt" } '
823+ inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , downloaded_text ['data' ])
824+ return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
855825 downloaded_item = await download_item (item , data_format = 'base64_uri' , type_format = 'extension' )
856826 return [
857827 File (
0 commit comments