Litellm dev 04 05 2025 p2 (#9774)

* test: move test to just checking async

* fix(transformation.py): handle function call with no schema

* fix(utils.py): handle pydantic base model in message tool calls

Fix https://github.com/BerriAI/litellm/issues/9321

* fix(vertex_and_google_ai_studio.py): handle tools=[]

Fixes https://github.com/BerriAI/litellm/issues/9080

* test: remove max token restriction

* test: fix basic test

* fix(get_supported_openai_params.py): fix check

* fix(converse_transformation.py): support fake streaming for meta.llama3-3-70b-instruct-v1:0

* fix: fix test

* fix: parse out empty dictionary on dbrx streaming + tool calls

* fix(handle-'strict'-param-when-calling-fireworks-ai): fireworks ai does not support 'strict' param

* fix: fix ruff check

'

* fix: handle no strict in function

* fix: revert bedrock change - handle in separate PR
This commit is contained in:
Krish Dholakia 2025-04-07 21:02:52 -07:00 committed by GitHub
parent d8f47fc9e5
commit fcf17d114f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 214 additions and 11 deletions

View file

@ -804,6 +804,35 @@ class BaseLLMChatTest(ABC):
url = f"data:application/pdf;base64,{encoded_file}"
return url
def test_empty_tools(self):
"""
Related Issue: https://github.com/BerriAI/litellm/issues/9080
"""
try:
from litellm import completion, ModelResponse
litellm.set_verbose = True
litellm._turn_on_debug()
from litellm.utils import supports_function_calling
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
base_completion_call_args = self.get_base_completion_call_args()
if not supports_function_calling(base_completion_call_args["model"], None):
print("Model does not support function calling")
pytest.skip("Model does not support function calling")
response = completion(**base_completion_call_args, messages=[{"role": "user", "content": "Hello, how are you?"}], tools=[]) # just make sure call doesn't fail
print("response: ", response)
assert response is not None
except litellm.InternalServerError:
pytest.skip("Model is overloaded")
except litellm.RateLimitError:
pass
except Exception as e:
pytest.fail(f"Error occurred: {e}")
def test_basic_tool_calling(self):
try:
@ -1003,6 +1032,101 @@ class BaseLLMChatTest(ABC):
elif input_type == "audio_url":
assert test_file_id in json.dumps(raw_request), "Audio URL not sent to gemini"
def test_function_calling_with_tool_response(self):
from litellm.utils import supports_function_calling
from litellm import completion
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
litellm.model_cost = litellm.get_model_cost_map(url="")
base_completion_call_args = self.get_base_completion_call_args()
if not supports_function_calling(base_completion_call_args["model"], None):
print("Model does not support function calling")
pytest.skip("Model does not support function calling")
def get_weather(city: str):
return f"City: {city}, Weather: Sunny with 34 degree Celcius"
TOOLS = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather in a city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to get the weather for",
}
},
"required": ["city"],
"additionalProperties": False,
},
"strict": True,
},
}
]
messages = [{ "content": "How is the weather in Mumbai?","role": "user"}]
response, iteration = "", 0
while True:
if response:
break
# Create a streaming response with tool calling enabled
stream = completion(
**base_completion_call_args,
messages=messages,
tools=TOOLS,
stream=True,
)
final_tool_calls = {}
for chunk in stream:
delta = chunk.choices[0].delta
print(delta)
if delta.content:
response += delta.content
elif delta.tool_calls:
for tool_call in chunk.choices[0].delta.tool_calls or []:
index = tool_call.index
if index not in final_tool_calls:
final_tool_calls[index] = tool_call
else:
final_tool_calls[
index
].function.arguments += tool_call.function.arguments
if final_tool_calls:
for tool_call in final_tool_calls.values():
if tool_call.function.name == "get_weather":
city = json.loads(tool_call.function.arguments)["city"]
tool_response = get_weather(city)
messages.append(
{
"role": "assistant",
"tool_calls": [tool_call],
"content": None,
}
)
messages.append(
{
"role": "tool",
"tool_call_id": tool_call.id,
"content": tool_response,
}
)
iteration += 1
if iteration > 2:
print("Something went wrong!")
break
print(response)
class BaseOSeriesModelsTest(ABC): # test across azure/openai
@abstractmethod
def get_base_completion_call_args(self):