26
26
DocumentUrl ,
27
27
FinishReason ,
28
28
ImageUrl ,
29
- MagicBinaryContent ,
30
- MagicDocumentUrl ,
31
29
ModelMessage ,
32
30
ModelRequest ,
33
31
ModelResponse ,
@@ -745,12 +743,7 @@ async def _map_user_prompt_items(items: Sequence[object]) -> list[ChatCompletion
745
743
async def _map_single_item (item : object ) -> list [ChatCompletionContentPartParam ]:
746
744
if isinstance (item , str ):
747
745
return [ChatCompletionContentPartTextParam (text = item , type = 'text' )]
748
- handled = await OpenAIChatModel ._handle_magic_document (item )
749
- if handled is not None :
750
- return handled
751
- handled = await OpenAIChatModel ._handle_magic_binary (item )
752
- if handled is not None :
753
- return handled
746
+ # Magic* no longer used; logic ported to base handlers
754
747
handled = OpenAIChatModel ._handle_image_url (item )
755
748
if handled is not None :
756
749
return handled
@@ -768,55 +761,6 @@ async def _map_single_item(item: object) -> list[ChatCompletionContentPartParam]
768
761
# Fallback: unknown type — return empty parts to avoid type-checker Never error
769
762
return []
770
763
771
- @staticmethod
772
- async def _handle_magic_document (item : object ) -> list [ChatCompletionContentPartParam ] | None :
773
- if not isinstance (item , MagicDocumentUrl ):
774
- return None
775
- if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
776
- downloaded = await download_item (item , data_format = 'text' , type_format = 'extension' )
777
- filename = item .filename or f'file.{ downloaded ["data_type" ] or "txt" } '
778
- inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , downloaded ['data' ])
779
- return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
780
- downloaded_item = await download_item (item , data_format = 'base64_uri' , type_format = 'extension' )
781
- return [
782
- File (
783
- file = FileFile (
784
- file_data = downloaded_item ['data' ],
785
- filename = f'filename.{ downloaded_item ["data_type" ]} ' ,
786
- ),
787
- type = 'file' ,
788
- )
789
- ]
790
-
791
- @staticmethod
792
- async def _handle_magic_binary (item : object ) -> list [ChatCompletionContentPartParam ] | None :
793
- if not isinstance (item , MagicBinaryContent ):
794
- return None
795
- if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
796
- text = item .data .decode ('utf-8' )
797
- filename = item .filename or 'file.txt'
798
- inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , text )
799
- return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
800
- base64_encoded = base64 .b64encode (item .data ).decode ('utf-8' )
801
- if item .is_image :
802
- image_url = ImageURL (url = f'data:{ item .media_type } ;base64,{ base64_encoded } ' )
803
- return [ChatCompletionContentPartImageParam (image_url = image_url , type = 'image_url' )]
804
- if item .is_audio :
805
- assert item .format in ('wav' , 'mp3' )
806
- audio = InputAudio (data = base64_encoded , format = item .format )
807
- return [ChatCompletionContentPartInputAudioParam (input_audio = audio , type = 'input_audio' )]
808
- if item .is_document :
809
- return [
810
- File (
811
- file = FileFile (
812
- file_data = f'data:{ item .media_type } ;base64,{ base64_encoded } ' ,
813
- filename = f'filename.{ item .format } ' ,
814
- ),
815
- type = 'file' ,
816
- )
817
- ]
818
- raise RuntimeError (f'Unsupported binary content type: { item .media_type } ' ) # pragma: no cover
819
-
820
764
@staticmethod
821
765
def _handle_image_url (item : object ) -> list [ChatCompletionContentPartParam ] | None :
822
766
if not isinstance (item , ImageUrl ):
@@ -828,6 +772,27 @@ def _handle_image_url(item: object) -> list[ChatCompletionContentPartParam] | No
828
772
async def _handle_binary_content (item : object ) -> list [ChatCompletionContentPartParam ] | None :
829
773
if not isinstance (item , BinaryContent ):
830
774
return None
775
+ if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
776
+ # Inline text-like binary content as a text block
777
+ text = item .data .decode ('utf-8' )
778
+ # Derive a sensible default filename from media type
779
+ media_type = item .media_type
780
+ if media_type == 'text/plain' :
781
+ filename = 'file.txt'
782
+ elif media_type == 'text/csv' :
783
+ filename = 'file.csv'
784
+ elif media_type == 'text/markdown' :
785
+ filename = 'file.md'
786
+ elif media_type == 'application/json' or media_type .endswith ('+json' ):
787
+ filename = 'file.json'
788
+ elif media_type == 'application/xml' or media_type .endswith ('+xml' ):
789
+ filename = 'file.xml'
790
+ elif media_type in ('application/x-yaml' , 'application/yaml' , 'text/yaml' ):
791
+ filename = 'file.yaml'
792
+ else :
793
+ filename = 'file.txt'
794
+ inline = OpenAIChatModel ._inline_file_block (filename , media_type , text )
795
+ return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
831
796
base64_encoded = base64 .b64encode (item .data ).decode ('utf-8' )
832
797
if item .is_image :
833
798
image_url = ImageURL (url = f'data:{ item .media_type } ;base64,{ base64_encoded } ' )
@@ -863,6 +828,11 @@ async def _handle_audio_url(item: object) -> list[ChatCompletionContentPartParam
863
828
async def _handle_document_url (item : object ) -> list [ChatCompletionContentPartParam ] | None :
864
829
if not isinstance (item , DocumentUrl ):
865
830
return None
831
+ if OpenAIChatModel ._is_text_like_media_type (item .media_type ):
832
+ downloaded_text = await download_item (item , data_format = 'text' , type_format = 'extension' )
833
+ filename = f'file.{ downloaded_text ["data_type" ] or "txt" } '
834
+ inline = OpenAIChatModel ._inline_file_block (filename , item .media_type , downloaded_text ['data' ])
835
+ return [ChatCompletionContentPartTextParam (text = inline , type = 'text' )]
866
836
downloaded_item = await download_item (item , data_format = 'base64_uri' , type_format = 'extension' )
867
837
return [
868
838
File (
0 commit comments