22import re
33import uuid
44from copy import deepcopy
5-
5+ import logging
66from typing import List , Dict , Any
77
8+ # Configure logging
9+ logging .basicConfig (level = logging .INFO , format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' )
10+ logger = logging .getLogger (__name__ )
11+
812def merge_messages_with_tools (messages : list , tools : list ) -> list :
913 """
1014 Integrate tool information into the messages for open-sourced LLMs which don't support tool calling.
@@ -193,8 +197,8 @@ def decode_litellm_tool_calls(response):
193197 ```
194198 """
195199 decoded_tool_calls = []
196-
197- if response .choices [0 ].message .content is None :
200+
201+ if response .choices [0 ].message .content is None :
198202 assert response .choices [0 ].message .tool_calls is not None
199203 tool_calls = response .choices [0 ].message .tool_calls
200204
@@ -211,24 +215,53 @@ def decode_litellm_tool_calls(response):
211215 )
212216 else :
213217 assert response .choices [0 ].message .content is not None
214-
215- # breakpoint()
218+
219+ # Some providers return a JSON string; attempt to parse. If parsing fails, treat as "no tools".
216220 tool_calls = response .choices [0 ].message .content
217221 if isinstance (tool_calls , str ):
218- tool_calls = json .loads (tool_calls )
219-
222+ try :
223+ parsed = json .loads (tool_calls )
224+ if isinstance (parsed , (list , dict )):
225+ tool_calls = parsed
226+ # Unexpected JSON type → no-op; be forgiving.
227+ else :
228+ logger .info ("decode_litellm_tool_calls: unexpected JSON type for tool_calls: %s" , type (parsed ))
229+ tool_calls = []
230+ except json .JSONDecodeError :
231+ logger .info ("decode_litellm_tool_calls: non-JSON tool_calls string, treating as no tools." )
232+ tool_calls = []
233+
220234 if not isinstance (tool_calls , list ):
221235 tool_calls = [tool_calls ]
222-
223- for tool_call in tool_calls :
224- decoded_tool_calls .append (
225- {
226- "name" : tool_call ["name" ],
227- "parameters" : tool_call ["arguments" ],
228- "id" : generator_tool_call_id ()
229- }
230- )
231236
237+ try :
238+ for tool_call in tool_calls :
239+ name = None
240+ if "name" in tool_call :
241+ name = tool_call ["name" ]
242+ elif "function_name" in tool_call :
243+ name = tool_call ["function_name" ]
244+ elif "tool_name" in tool_call :
245+ name = tool_call ["tool_name" ]
246+
247+ if name is not None :
248+ parameters = None
249+ if "arguments" in tool_call :
250+ parameters = tool_call ["arguments" ]
251+ elif "parameters" in tool_call :
252+ parameters = tool_call ["parameters" ]
253+
254+ if parameters is not None :
255+ decoded_tool_calls .append (
256+ {
257+ "name" : name ,
258+ "parameters" : parameters ,
259+ "id" : generator_tool_call_id ()
260+ }
261+ )
262+ except :
263+ logger .info (f"decode_litellm_tool_calls: no valid attribute in tools, treating as no tools" )
264+
232265 return decoded_tool_calls
233266
234267def parse_tool_calls (message ):
0 commit comments