1919]
2020
2121class MessageManager ():
22- def __init__ (self , model_id : str ):
22+ def __init__ (self , model_id : str , api_type : str = "chat/completions" ):
2323 self .model_id = model_id
24+ self .api_type = api_type
2425
2526 def get_clean_message_list (self ,
2627 message_list : list [ChatMessage ],
2728 role_conversions : dict [MessageRole , MessageRole ] | dict [str , str ] = {},
2829 convert_images_to_image_urls : bool = False ,
2930 flatten_messages_as_text : bool = False ,
31+ api_type : str = "chat/completions" ,
3032 ) -> list [dict [str , Any ]]:
3133 """
3234 Creates a list of messages to give as input to the LLM. These messages are dictionaries and chat template compatible with transformers LLM chat template.
@@ -38,6 +40,25 @@ def get_clean_message_list(self,
3840 convert_images_to_image_urls (`bool`, default `False`): Whether to convert images to image URLs.
3941 flatten_messages_as_text (`bool`, default `False`): Whether to flatten messages as text.
4042 """
43+ api_type = api_type or self .api_type
44+ if api_type == "responses" :
45+ return self ._get_responses_message_list (
46+ message_list , role_conversions , convert_images_to_image_urls , flatten_messages_as_text
47+ )
48+ else :
49+ return self ._get_chat_completions_message_list (
50+ message_list , role_conversions , convert_images_to_image_urls , flatten_messages_as_text
51+ )
52+
53+ def _get_chat_completions_message_list (self ,
54+ message_list : list [ChatMessage ],
55+ role_conversions : dict [MessageRole , MessageRole ] | dict [str , str ] = {},
56+ convert_images_to_image_urls : bool = False ,
57+ flatten_messages_as_text : bool = False ,
58+ ) -> list [dict [str , Any ]]:
59+ """
60+ Creates a list of messages in chat completions format.
61+ """
4162 output_message_list : list [dict [str , Any ]] = []
4263 message_list = deepcopy (message_list ) # Avoid modifying the original list
4364 for message in message_list :
@@ -87,6 +108,106 @@ def get_clean_message_list(self,
87108 )
88109 return output_message_list
89110
111+ def _get_responses_message_list (self ,
112+ message_list : list [ChatMessage ],
113+ role_conversions : dict [MessageRole , MessageRole ] | dict [str , str ] = {},
114+ convert_images_to_image_urls : bool = False ,
115+ flatten_messages_as_text : bool = False ,
116+ ) -> list [dict [str , Any ]]:
117+ """
118+ Creates a list of messages in responses format (OpenAI responses API).
119+ """
120+ output_message_list : list [dict [str , Any ]] = []
121+ message_list = deepcopy (message_list ) # Avoid modifying the original list
122+
123+ for message in message_list :
124+ role = message .role
125+ if role not in MessageRole .roles ():
126+ raise ValueError (f"Incorrect role { role } , only { MessageRole .roles ()} are supported for now." )
127+
128+ if role in role_conversions :
129+ message .role = role_conversions [role ] # type: ignore
130+
131+ # Handle content processing
132+ if isinstance (message .content , list ):
133+ # Process each content element
134+ processed_content = []
135+ for element in message .content :
136+ assert isinstance (element , dict ), "Error: this element should be a dict:" + str (element )
137+
138+ if element ["type" ] == "image" :
139+ assert not flatten_messages_as_text , f"Cannot use images with { flatten_messages_as_text = } "
140+ if convert_images_to_image_urls :
141+ processed_content .append ({
142+ "type" : "image_url" ,
143+ "image_url" : {"url" : make_image_url (encode_image_base64 (element .pop ("image" )))},
144+ })
145+ else :
146+ processed_content .append ({
147+ "type" : "image" ,
148+ "image" : encode_image_base64 (element ["image" ])
149+ })
150+ elif element ["type" ] == "text" :
151+ processed_content .append (element )
152+ else :
153+ processed_content .append (element )
154+
155+ content = processed_content
156+ else :
157+ # Handle string content
158+ if flatten_messages_as_text :
159+ content = message .content
160+ else :
161+ content = [{"type" : "text" , "text" : message .content }] if message .content else []
162+
163+ # Handle tool calls for responses format
164+ tool_calls = None
165+ if message .tool_calls :
166+ tool_calls = []
167+ for tool_call in message .tool_calls :
168+ tool_calls .append ({
169+ "id" : tool_call .id ,
170+ "type" : tool_call .type ,
171+ "function" : {
172+ "name" : tool_call .function .name ,
173+ "arguments" : tool_call .function .arguments ,
174+ "description" : tool_call .function .description
175+ }
176+ })
177+
178+ # Create message in responses format
179+ message_dict = {
180+ "role" : message .role ,
181+ "content" : content ,
182+ }
183+
184+ if tool_calls :
185+ message_dict ["tool_calls" ] = tool_calls
186+
187+ # Merge consecutive messages with same role
188+ if len (output_message_list ) > 0 and message .role == output_message_list [- 1 ]["role" ]:
189+ if flatten_messages_as_text :
190+ if isinstance (content , list ) and content and content [0 ]["type" ] == "text" :
191+ output_message_list [- 1 ]["content" ] += "\n " + content [0 ]["text" ]
192+ else :
193+ output_message_list [- 1 ]["content" ] += "\n " + str (content )
194+ else :
195+ # Merge content lists
196+ if isinstance (output_message_list [- 1 ]["content" ], list ) and isinstance (content , list ):
197+ output_message_list [- 1 ]["content" ].extend (content )
198+ else :
199+ output_message_list [- 1 ]["content" ] = content
200+
201+ # Merge tool calls
202+ if tool_calls and "tool_calls" in output_message_list [- 1 ]:
203+ output_message_list [- 1 ]["tool_calls" ].extend (tool_calls )
204+ elif tool_calls :
205+ output_message_list [- 1 ]["tool_calls" ] = tool_calls
206+ else :
207+ output_message_list .append (message_dict )
208+
209+ return output_message_list
210+
90211 def get_tool_json_schema (self ,
91212 tool : Any ,
92213 model_id : Optional [str ] = None
0 commit comments