litellm-mirror/litellm/tests/test_utils.py
2024-02-28 17:36:15 -08:00

343 lines
10 KiB
Python

import sys, os
from dotenv import load_dotenv
import copy
load_dotenv()
import os
sys.path.insert(
0, os.path.abspath("../..")
) # Adds the parent directory to the system path
import pytest
import litellm
from litellm.utils import (
trim_messages,
get_token_count,
get_valid_models,
check_valid_key,
validate_environment,
function_to_dict,
token_counter,
)
# Assuming your trim_messages, shorten_message_to_fit_limit, and get_token_count functions are all in a module named 'message_utils'
# Test 1: Check trimming of normal message
def test_basic_trimming():
messages = [
{
"role": "user",
"content": "This is a long message that definitely exceeds the token limit.",
}
]
trimmed_messages = trim_messages(messages, model="claude-2", max_tokens=8)
print("trimmed messages")
print(trimmed_messages)
# print(get_token_count(messages=trimmed_messages, model="claude-2"))
assert (get_token_count(messages=trimmed_messages, model="claude-2")) <= 8
# test_basic_trimming()
def test_basic_trimming_no_max_tokens_specified():
messages = [
{
"role": "user",
"content": "This is a long message that is definitely under the token limit.",
}
]
trimmed_messages = trim_messages(messages, model="gpt-4")
print("trimmed messages for gpt-4")
print(trimmed_messages)
# print(get_token_count(messages=trimmed_messages, model="claude-2"))
assert (
get_token_count(messages=trimmed_messages, model="gpt-4")
) <= litellm.model_cost["gpt-4"]["max_tokens"]
# test_basic_trimming_no_max_tokens_specified()
def test_multiple_messages_trimming():
messages = [
{
"role": "user",
"content": "This is a long message that will exceed the token limit.",
},
{
"role": "user",
"content": "This is another long message that will also exceed the limit.",
},
]
trimmed_messages = trim_messages(
messages=messages, model="gpt-3.5-turbo", max_tokens=20
)
# print(get_token_count(messages=trimmed_messages, model="gpt-3.5-turbo"))
assert (get_token_count(messages=trimmed_messages, model="gpt-3.5-turbo")) <= 20
# test_multiple_messages_trimming()
def test_multiple_messages_no_trimming():
messages = [
{
"role": "user",
"content": "This is a long message that will exceed the token limit.",
},
{
"role": "user",
"content": "This is another long message that will also exceed the limit.",
},
]
trimmed_messages = trim_messages(
messages=messages, model="gpt-3.5-turbo", max_tokens=100
)
print("Trimmed messages")
print(trimmed_messages)
assert messages == trimmed_messages
# test_multiple_messages_no_trimming()
def test_large_trimming_multiple_messages():
messages = [
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."},
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."},
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."},
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."},
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."},
]
trimmed_messages = trim_messages(messages, max_tokens=20, model="gpt-4-0613")
print("trimmed messages")
print(trimmed_messages)
assert (get_token_count(messages=trimmed_messages, model="gpt-4-0613")) <= 20
# test_large_trimming()
def test_large_trimming_single_message():
messages = [
{"role": "user", "content": "This is a singlelongwordthatexceedsthelimit."}
]
trimmed_messages = trim_messages(messages, max_tokens=5, model="gpt-4-0613")
assert (get_token_count(messages=trimmed_messages, model="gpt-4-0613")) <= 5
assert (get_token_count(messages=trimmed_messages, model="gpt-4-0613")) > 0
def test_trimming_with_system_message_within_max_tokens():
# This message is 33 tokens long
messages = [
{"role": "system", "content": "This is a short system message"},
{
"role": "user",
"content": "This is a medium normal message, let's say litellm is awesome.",
},
]
trimmed_messages = trim_messages(
messages, max_tokens=30, model="gpt-4-0613"
) # The system message should fit within the token limit
assert len(trimmed_messages) == 2
assert trimmed_messages[0]["content"] == "This is a short system message"
def test_trimming_with_system_message_exceeding_max_tokens():
# This message is 33 tokens long. The system message is 13 tokens long.
messages = [
{"role": "system", "content": "This is a short system message"},
{
"role": "user",
"content": "This is a medium normal message, let's say litellm is awesome.",
},
]
trimmed_messages = trim_messages(messages, max_tokens=12, model="gpt-4-0613")
assert len(trimmed_messages) == 1
def test_trimming_should_not_change_original_messages():
messages = [
{"role": "system", "content": "This is a short system message"},
{
"role": "user",
"content": "This is a medium normal message, let's say litellm is awesome.",
},
]
messages_copy = copy.deepcopy(messages)
trimmed_messages = trim_messages(messages, max_tokens=12, model="gpt-4-0613")
assert messages == messages_copy
def test_get_valid_models():
old_environ = os.environ
os.environ = {"OPENAI_API_KEY": "temp"} # mock set only openai key in environ
valid_models = get_valid_models()
print(valid_models)
# list of openai supported llms on litellm
expected_models = (
litellm.open_ai_chat_completion_models + litellm.open_ai_text_completion_models
)
assert valid_models == expected_models
# reset replicate env key
os.environ = old_environ
# test_get_valid_models()
def test_bad_key():
key = "bad-key"
response = check_valid_key(model="gpt-3.5-turbo", api_key=key)
print(response, key)
assert response == False
def test_good_key():
key = os.environ["OPENAI_API_KEY"]
response = check_valid_key(model="gpt-3.5-turbo", api_key=key)
assert response == True
# test validate environment
def test_validate_environment_empty_model():
api_key = validate_environment()
if api_key is None:
raise Exception()
# test_validate_environment_empty_model()
def test_function_to_dict():
print("testing function to dict for get current weather")
def get_current_weather(location: str, unit: str):
"""Get the current weather in a given location
Parameters
----------
location : str
The city and state, e.g. San Francisco, CA
unit : {'celsius', 'fahrenheit'}
Temperature unit
Returns
-------
str
a sentence indicating the weather
"""
if location == "Boston, MA":
return "The weather is 12F"
function_json = litellm.utils.function_to_dict(get_current_weather)
print(function_json)
expected_output = {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {
"type": "string",
"description": "Temperature unit",
"enum": "['fahrenheit', 'celsius']",
},
},
"required": ["location", "unit"],
},
}
print(expected_output)
assert function_json["name"] == expected_output["name"]
assert function_json["description"] == expected_output["description"]
assert function_json["parameters"]["type"] == expected_output["parameters"]["type"]
assert (
function_json["parameters"]["properties"]["location"]
== expected_output["parameters"]["properties"]["location"]
)
# the enum can change it can be - which is why we don't assert on unit
# {'type': 'string', 'description': 'Temperature unit', 'enum': "['fahrenheit', 'celsius']"}
# {'type': 'string', 'description': 'Temperature unit', 'enum': "['celsius', 'fahrenheit']"}
assert (
function_json["parameters"]["required"]
== expected_output["parameters"]["required"]
)
print("passed")
# test_function_to_dict()
def test_token_counter():
try:
messages = [{"role": "user", "content": "hi how are you what time is it"}]
tokens = token_counter(model="gpt-3.5-turbo", messages=messages)
print("gpt-35-turbo")
print(tokens)
assert tokens > 0
tokens = token_counter(model="claude-2", messages=messages)
print("claude-2")
print(tokens)
assert tokens > 0
tokens = token_counter(model="palm/chat-bison", messages=messages)
print("palm/chat-bison")
print(tokens)
assert tokens > 0
tokens = token_counter(model="ollama/llama2", messages=messages)
print("ollama/llama2")
print(tokens)
assert tokens > 0
tokens = token_counter(model="anthropic.claude-instant-v1", messages=messages)
print("anthropic.claude-instant-v1")
print(tokens)
assert tokens > 0
except Exception as e:
pytest.fail(f"Error occurred: {e}")
# test_token_counter()
def test_supports_function_calling():
try:
assert litellm.supports_function_calling(model="gpt-3.5-turbo") == True
assert (
litellm.supports_function_calling(model="azure/gpt-4-1106-preview") == True
)
assert (
litellm.supports_function_calling(
model="bedrock/anthropic.claude-instant-v1"
)
== False
)
assert litellm.supports_function_calling(model="palm/chat-bison") == False
assert litellm.supports_function_calling(model="ollama/llama2") == False
assert (
litellm.supports_function_calling(model="anthropic.claude-instant-v1")
== False
)
assert litellm.supports_function_calling(model="claude-2") == False
except Exception as e:
pytest.fail(f"Error occurred: {e}")