mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-25 05:54:53 +00:00
test(images): keep the existing test file formatting
Restore the formatting from cab48123d1 while preserving the new parametrized test and its Mapping import
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
55ae32934e
commit
607d3fff6f
1 changed files with 83 additions and 86 deletions
|
|
@ -19,19 +19,7 @@ from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response impo
|
|||
safe_convert_created_field,
|
||||
should_convert_tool_call_to_json_mode,
|
||||
)
|
||||
from litellm.types.utils import (
|
||||
ChatCompletionMessageCustomToolCall,
|
||||
ChatCompletionMessageToolCall,
|
||||
Choices,
|
||||
CompletionTokensDetailsWrapper,
|
||||
Function,
|
||||
ImageObject,
|
||||
ImageResponse,
|
||||
Message,
|
||||
ModelResponse,
|
||||
PromptTokensDetailsWrapper,
|
||||
Usage,
|
||||
)
|
||||
from litellm.types.utils import ChatCompletionMessageCustomToolCall, ChatCompletionMessageToolCall, Choices, CompletionTokensDetailsWrapper, Function, ImageObject, ImageResponse, Message, ModelResponse, PromptTokensDetailsWrapper, Usage
|
||||
from tests._vcr_conftest_common import install_live_call_probe, record_vcr_outcome
|
||||
|
||||
FIXED_TIME: Final[datetime] = datetime(2025, 1, 1, 12, 0, 0)
|
||||
|
|
@ -54,7 +42,7 @@ OPENAI_CUSTOM_TOOL_CALL_RESPONSE = {
|
|||
"type": "custom",
|
||||
"custom": {
|
||||
"name": "ApplyPatch",
|
||||
"input": '*** Begin Patch\n*** Update File: main.py\n@@\n+def hello():\n+ print("Hello")\n*** End Patch\n',
|
||||
"input": "*** Begin Patch\n*** Update File: main.py\n@@\n+def hello():\n+ print(\"Hello\")\n*** End Patch\n",
|
||||
},
|
||||
}
|
||||
],
|
||||
|
|
@ -238,7 +226,6 @@ def _vcr_outcome_gate(request, vcr):
|
|||
yield
|
||||
record_vcr_outcome(request, vcr)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def event_loop():
|
||||
try:
|
||||
|
|
@ -248,7 +235,6 @@ def event_loop():
|
|||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def setup_and_teardown(event_loop):
|
||||
import litellm
|
||||
|
|
@ -282,7 +268,6 @@ def setup_and_teardown(event_loop):
|
|||
if pending:
|
||||
event_loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
||||
|
||||
|
||||
_SCALAR_DEFAULTS = {
|
||||
"num_retries": getattr(litellm, "num_retries", None),
|
||||
"set_verbose": getattr(litellm, "set_verbose", False),
|
||||
|
|
@ -297,7 +282,6 @@ _SCALAR_DEFAULTS = {
|
|||
"cohere_key": getattr(litellm, "cohere_key", None),
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_basic():
|
||||
# Test basic conversion with minimal input
|
||||
|
|
@ -312,7 +296,6 @@ def test_convert_to_image_response_basic():
|
|||
assert result.created == 1234567890
|
||||
assert result.data[0].url == "http://example.com/image.jpg"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_hidden_params():
|
||||
# Test with hidden params
|
||||
|
|
@ -326,7 +309,6 @@ def test_convert_to_image_response_with_hidden_params():
|
|||
|
||||
assert result._hidden_params == {"api_key": "test_key"}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_multiple_images():
|
||||
# Test handling multiple images in response
|
||||
|
|
@ -344,7 +326,6 @@ def test_convert_to_image_response_multiple_images():
|
|||
assert result.data[0].url == "http://example.com/image1.jpg"
|
||||
assert result.data[1].url == "http://example.com/image2.jpg"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_b64_json():
|
||||
# Test handling b64_json in response
|
||||
|
|
@ -357,7 +338,6 @@ def test_convert_to_image_response_with_b64_json():
|
|||
|
||||
assert result.data[0].b64_json == "base64encodedstring"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_extra_fields():
|
||||
response_dict = {
|
||||
|
|
@ -379,7 +359,6 @@ def test_convert_to_image_response_with_extra_fields():
|
|||
assert result.data[0].url == "http://example.com/image1.jpg"
|
||||
assert result.data[1].url == "http://example.com/image2.jpg"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_extra_fields_2():
|
||||
"""
|
||||
|
|
@ -557,7 +536,6 @@ def test_convert_to_image_response_with_none_usage_fields():
|
|||
assert result.usage.input_tokens_details.image_tokens == 0
|
||||
assert result.usage.input_tokens_details.text_tokens == 0
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_partial_none_usage_fields():
|
||||
"""
|
||||
|
|
@ -591,7 +569,6 @@ def test_convert_to_image_response_with_partial_none_usage_fields():
|
|||
assert result.usage.input_tokens_details.image_tokens == 0
|
||||
assert result.usage.input_tokens_details.text_tokens == 0
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_vcr_outcome_gate", "setup_and_teardown")
|
||||
def test_convert_to_image_response_with_valid_usage_fields():
|
||||
"""
|
||||
|
|
@ -626,7 +603,6 @@ def test_convert_to_image_response_with_valid_usage_fields():
|
|||
assert result.usage.input_tokens_details.image_tokens == 30
|
||||
assert result.usage.input_tokens_details.text_tokens == 20
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_basic():
|
||||
"""Test basic conversion with all fields present."""
|
||||
response_object = {
|
||||
|
|
@ -689,8 +665,12 @@ def test_convert_to_model_response_object_basic():
|
|||
assert result.usage.prompt_tokens == 19
|
||||
assert result.usage.completion_tokens == 10
|
||||
assert result.usage.total_tokens == 29
|
||||
assert result.usage.prompt_tokens_details == PromptTokensDetailsWrapper(cached_tokens=0)
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(reasoning_tokens=0)
|
||||
assert result.usage.prompt_tokens_details == PromptTokensDetailsWrapper(
|
||||
cached_tokens=0
|
||||
)
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(
|
||||
reasoning_tokens=0
|
||||
)
|
||||
|
||||
# Other fields
|
||||
assert result.system_fingerprint == "fp_6b68a8204b"
|
||||
|
|
@ -698,7 +678,6 @@ def test_convert_to_model_response_object_basic():
|
|||
# hidden params
|
||||
assert result._hidden_params is not None
|
||||
|
||||
|
||||
def test_convert_image_input_dict_response_to_chat_completion_response():
|
||||
"""Test conversion on a response with an image input."""
|
||||
response_object = {
|
||||
|
|
@ -749,17 +728,21 @@ def test_convert_image_input_dict_response_to_chat_completion_response():
|
|||
assert choice.index == 0
|
||||
assert isinstance(choice.message, Message)
|
||||
assert choice.message.role == "assistant"
|
||||
assert choice.message.content == "\n\nThis image shows a wooden boardwalk extending through a lush green marshland."
|
||||
assert (
|
||||
choice.message.content
|
||||
== "\n\nThis image shows a wooden boardwalk extending through a lush green marshland."
|
||||
)
|
||||
assert choice.finish_reason == "stop"
|
||||
|
||||
assert result.usage.prompt_tokens == 9
|
||||
assert result.usage.completion_tokens == 12
|
||||
assert result.usage.total_tokens == 21
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(reasoning_tokens=0)
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(
|
||||
reasoning_tokens=0
|
||||
)
|
||||
|
||||
assert result._hidden_params is not None
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_tool_calls_invalid_json_arguments():
|
||||
"""
|
||||
Critical test - this is a basic response from OpenAI API
|
||||
|
|
@ -822,8 +805,13 @@ def test_convert_to_model_response_object_tool_calls_invalid_json_arguments():
|
|||
assert len(result.choices) == 1
|
||||
assert result.choices[0].message.content is None
|
||||
assert len(result.choices[0].message.tool_calls) == 1
|
||||
assert result.choices[0].message.tool_calls[0].function.name == "get_current_weather"
|
||||
assert result.choices[0].message.tool_calls[0].function.arguments == '{"location":"Boston, MA","unit":"fahren'
|
||||
assert (
|
||||
result.choices[0].message.tool_calls[0].function.name == "get_current_weather"
|
||||
)
|
||||
assert (
|
||||
result.choices[0].message.tool_calls[0].function.arguments
|
||||
== '{"location":"Boston, MA","unit":"fahren'
|
||||
)
|
||||
assert result.choices[0].finish_reason == "length"
|
||||
assert result.model == "gpt-4o-2024-08-06"
|
||||
assert result.created == 1729337288
|
||||
|
|
@ -832,7 +820,6 @@ def test_convert_to_model_response_object_tool_calls_invalid_json_arguments():
|
|||
assert result.usage.total_tokens == 102
|
||||
assert result.system_fingerprint == "fp_45c6de4934"
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_tool_calls_valid_json_arguments():
|
||||
"""
|
||||
Critical test - this is a basic response from OpenAI API
|
||||
|
|
@ -895,8 +882,13 @@ def test_convert_to_model_response_object_tool_calls_valid_json_arguments():
|
|||
assert len(result.choices) == 1
|
||||
assert result.choices[0].message.content is None
|
||||
assert len(result.choices[0].message.tool_calls) == 1
|
||||
assert result.choices[0].message.tool_calls[0].function.name == "get_current_weather"
|
||||
assert result.choices[0].message.tool_calls[0].function.arguments == '{"location":"Boston, MA","unit":"fahrenheit"}'
|
||||
assert (
|
||||
result.choices[0].message.tool_calls[0].function.name == "get_current_weather"
|
||||
)
|
||||
assert (
|
||||
result.choices[0].message.tool_calls[0].function.arguments
|
||||
== '{"location":"Boston, MA","unit":"fahrenheit"}'
|
||||
)
|
||||
assert result.choices[0].finish_reason == "length"
|
||||
assert result.model == "gpt-4o-2024-08-06"
|
||||
assert result.created == 1729337288
|
||||
|
|
@ -905,7 +897,6 @@ def test_convert_to_model_response_object_tool_calls_valid_json_arguments():
|
|||
assert result.usage.total_tokens == 102
|
||||
assert result.system_fingerprint == "fp_45c6de4934"
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_json_mode():
|
||||
"""
|
||||
This test is verifying that when convert_tool_call_to_json_mode is True, a single tool call's arguments are correctly converted into the message content of the response.
|
||||
|
|
@ -956,7 +947,6 @@ def test_convert_to_model_response_object_json_mode():
|
|||
assert result.usage.prompt_tokens == 5
|
||||
assert result.usage.completion_tokens == 5
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_logprobs():
|
||||
"""
|
||||
|
||||
|
|
@ -1192,12 +1182,13 @@ def test_convert_to_model_response_object_with_logprobs():
|
|||
assert result.usage.prompt_tokens == 9
|
||||
assert result.usage.completion_tokens == 9
|
||||
assert result.usage.total_tokens == 18
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(reasoning_tokens=0)
|
||||
assert result.usage.completion_tokens_details == CompletionTokensDetailsWrapper(
|
||||
reasoning_tokens=0
|
||||
)
|
||||
|
||||
assert result.system_fingerprint is None
|
||||
assert result._hidden_params is not None
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_error():
|
||||
"""Test error handling for None response object."""
|
||||
with pytest.raises(Exception, match="Error in response object format"):
|
||||
|
|
@ -1212,7 +1203,6 @@ def test_convert_to_model_response_object_error():
|
|||
convert_tool_call_to_json_mode=False,
|
||||
)
|
||||
|
||||
|
||||
def test_image_generation_openai_with_pydantic_warning(caplog):
|
||||
try:
|
||||
import logging
|
||||
|
|
@ -1250,7 +1240,6 @@ def test_image_generation_openai_with_pydantic_warning(caplog):
|
|||
except Exception as e:
|
||||
pytest.fail(f"Test failed with exception: {e}")
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_empty_str():
|
||||
"""Test that convert_to_model_response_object handles empty strings correctly."""
|
||||
|
||||
|
|
@ -1354,7 +1343,6 @@ def test_convert_to_model_response_object_with_empty_str():
|
|||
assert resp is not None
|
||||
assert resp.choices[0].message.content is not None
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_thinking_content():
|
||||
"""Test that convert_to_model_response_object handles thinking content correctly."""
|
||||
|
||||
|
|
@ -1402,7 +1390,6 @@ def test_convert_to_model_response_object_with_thinking_content():
|
|||
assert resp is not None
|
||||
assert resp.choices[0].message.reasoning_content is not None
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_empty_error_object():
|
||||
"""
|
||||
Test that convert_to_model_response_object handles empty error objects gracefully.
|
||||
|
|
@ -1460,8 +1447,9 @@ def test_convert_to_model_response_object_with_empty_error_object():
|
|||
assert isinstance(result, ModelResponse)
|
||||
assert result.model == "minimax-m2.1"
|
||||
assert len(result.choices) == 1
|
||||
assert result.choices[0].message.content == "Hey! I'm doing well, thanks for asking!"
|
||||
|
||||
assert (
|
||||
result.choices[0].message.content == "Hey! I'm doing well, thanks for asking!"
|
||||
)
|
||||
|
||||
def test_convert_to_model_response_object_with_real_error():
|
||||
"""
|
||||
|
|
@ -1494,7 +1482,6 @@ def test_convert_to_model_response_object_with_real_error():
|
|||
assert hasattr(exc_info.value, "message")
|
||||
assert "Rate limit exceeded" in str(exc_info.value.message)
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_empty_dict_error():
|
||||
"""
|
||||
Test that convert_to_model_response_object handles completely empty error dict.
|
||||
|
|
@ -1534,7 +1521,6 @@ def test_convert_to_model_response_object_with_empty_dict_error():
|
|||
assert isinstance(result, ModelResponse)
|
||||
assert result.choices[0].message.content == "Hello!"
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_preserves_provider_specific_fields_from_proxy():
|
||||
"""
|
||||
Test that provider_specific_fields (e.g. Anthropic citations) are preserved
|
||||
|
|
@ -1612,13 +1598,18 @@ def test_convert_to_model_response_object_preserves_provider_specific_fields_fro
|
|||
assert result.id == "chatcmpl-proxy-123"
|
||||
|
||||
choice = result.choices[0]
|
||||
assert choice.message.content == "Based on current reviews, the Sony WH-1000XM5 remains one of the best headphones."
|
||||
assert (
|
||||
choice.message.content
|
||||
== "Based on current reviews, the Sony WH-1000XM5 remains one of the best headphones."
|
||||
)
|
||||
assert choice.message.provider_specific_fields is not None
|
||||
assert "citations" in choice.message.provider_specific_fields
|
||||
assert choice.message.provider_specific_fields["citations"] == citations
|
||||
assert "web_search_results" in choice.message.provider_specific_fields
|
||||
assert choice.message.provider_specific_fields["web_search_results"] == web_search_results
|
||||
|
||||
assert (
|
||||
choice.message.provider_specific_fields["web_search_results"]
|
||||
== web_search_results
|
||||
)
|
||||
|
||||
def test_convert_to_model_response_object_keeps_reasoning_items_from_a_cached_response():
|
||||
reasoning_items: Final = [
|
||||
|
|
@ -1706,7 +1697,6 @@ def test_convert_to_model_response_object_provider_specific_fields_merges_extra_
|
|||
assert "custom_extra_field" in psf
|
||||
assert psf["custom_extra_field"] == "extra_value"
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_no_provider_specific_fields_still_works():
|
||||
"""
|
||||
Test that responses without provider_specific_fields continue to work as before.
|
||||
|
|
@ -1752,7 +1742,6 @@ def test_convert_to_model_response_object_no_provider_specific_fields_still_work
|
|||
assert result.choices[0].message.refusal is None
|
||||
assert result.choices[0].message.provider_specific_fields is None
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_error_code_only():
|
||||
"""
|
||||
Test that errors with only a code (no message) are still treated as real errors.
|
||||
|
|
@ -1778,7 +1767,6 @@ def test_convert_to_model_response_object_with_error_code_only():
|
|||
|
||||
assert exc_info.value.status_code == 500
|
||||
|
||||
|
||||
def test_model_prefix_preservation():
|
||||
"""
|
||||
Test that when model_response_object has a prefix like 'openai/gpt-4'
|
||||
|
|
@ -1807,7 +1795,6 @@ def test_model_prefix_preservation():
|
|||
|
||||
assert result.model == "openai/gpt-4o"
|
||||
|
||||
|
||||
def test_model_without_prefix():
|
||||
"""
|
||||
Test that when model_response_object has no prefix (e.g. 'gpt-4'),
|
||||
|
|
@ -1836,7 +1823,6 @@ def test_model_without_prefix():
|
|||
|
||||
assert result.model == "gpt-4"
|
||||
|
||||
|
||||
def test_extra_response_fields_preserved():
|
||||
"""
|
||||
Test that extra response fields (e.g. service_tier) are preserved
|
||||
|
|
@ -1866,7 +1852,6 @@ def test_extra_response_fields_preserved():
|
|||
|
||||
assert result.service_tier == "default"
|
||||
|
||||
|
||||
def test_hidden_params_and_response_headers_set():
|
||||
"""
|
||||
Test that _hidden_params and _response_headers are correctly set
|
||||
|
|
@ -1901,7 +1886,6 @@ def test_hidden_params_and_response_headers_set():
|
|||
assert "additional_headers" in result._hidden_params
|
||||
assert result._response_headers == response_headers
|
||||
|
||||
|
||||
def test_response_ms_computed():
|
||||
"""
|
||||
Test that _response_ms is computed correctly from start_time and end_time.
|
||||
|
|
@ -1931,7 +1915,6 @@ def test_response_ms_computed():
|
|||
|
||||
assert result._response_ms == pytest.approx(250.0)
|
||||
|
||||
|
||||
def test_error_message_includes_function_args():
|
||||
"""
|
||||
Test that when an exception occurs, the error message includes
|
||||
|
|
@ -1944,7 +1927,7 @@ def test_error_message_includes_function_args():
|
|||
"choices": [{"index": 0}],
|
||||
}
|
||||
|
||||
with pytest.raises(Exception, match="in convert_to_model_response_object") as exc_info:
|
||||
with pytest.raises(Exception, match='in convert_to_model_response_object') as exc_info:
|
||||
convert_to_model_response_object(
|
||||
model_response_object=ModelResponse(),
|
||||
response_object=response_object,
|
||||
|
|
@ -1958,7 +1941,6 @@ def test_error_message_includes_function_args():
|
|||
assert "response_object" in error_msg
|
||||
assert "response_type" in error_msg
|
||||
|
||||
|
||||
@pytest.mark.parametrize("falsy_id", [None, ""])
|
||||
def test_convert_to_model_response_object_falsy_id_preserves_auto_generated(falsy_id):
|
||||
"""Test that a falsy id in response_object preserves the auto-generated id."""
|
||||
|
|
@ -1986,7 +1968,6 @@ def test_convert_to_model_response_object_falsy_id_preserves_auto_generated(fals
|
|||
assert result.id == original_id
|
||||
assert result.id.startswith("chatcmpl-")
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_default_usage_overwritten():
|
||||
"""
|
||||
Regression test: convert_to_model_response_object must properly set Usage
|
||||
|
|
@ -2030,7 +2011,6 @@ def test_convert_to_model_response_object_default_usage_overwritten():
|
|||
assert result.usage.completion_tokens == 7
|
||||
assert result.usage.total_tokens == 22
|
||||
|
||||
|
||||
def test_convert_to_model_response_object_with_null_top_logprobs():
|
||||
"""
|
||||
Test that convert_to_model_response_object handles null top_logprobs
|
||||
|
|
@ -2122,7 +2102,6 @@ def test_convert_to_model_response_object_with_null_top_logprobs():
|
|||
assert token_logprob.top_logprobs == []
|
||||
assert isinstance(token_logprob.top_logprobs, list)
|
||||
|
||||
|
||||
class TestMissingChoicesGuard:
|
||||
"""
|
||||
Tests for the defense-in-depth guard that raises APIError when a provider
|
||||
|
|
@ -2248,7 +2227,9 @@ class TestMissingChoicesGuard:
|
|||
|
||||
async def consume():
|
||||
chunks = []
|
||||
async for chunk in convert_to_streaming_response_async(response_object=response_object):
|
||||
async for chunk in convert_to_streaming_response_async(
|
||||
response_object=response_object
|
||||
):
|
||||
chunks.append(chunk)
|
||||
return chunks
|
||||
|
||||
|
|
@ -2276,7 +2257,6 @@ class TestMissingChoicesGuard:
|
|||
|
||||
assert "copilot_usage" in exc_info.value.message
|
||||
|
||||
|
||||
class TestNormalizeImagesForMessage:
|
||||
def test_none_returns_none(self):
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -2312,7 +2292,6 @@ class TestNormalizeImagesForMessage:
|
|||
result = _normalize_images_for_message(images)
|
||||
assert result[0]["index"] == 5
|
||||
|
||||
|
||||
class TestSafeConvertCreatedField:
|
||||
def test_none_returns_current_time(self):
|
||||
import time
|
||||
|
|
@ -2355,7 +2334,6 @@ class TestSafeConvertCreatedField:
|
|||
result = safe_convert_created_field("not-a-number")
|
||||
assert abs(result - int(time.time())) <= 1
|
||||
|
||||
|
||||
class TestConvertToStreamingResponse:
|
||||
def test_none_raises(self):
|
||||
|
||||
|
|
@ -2448,7 +2426,9 @@ class TestConvertToStreamingResponse:
|
|||
|
||||
async def run():
|
||||
chunks = []
|
||||
async for chunk in convert_to_streaming_response_async(response_object=response_object):
|
||||
async for chunk in convert_to_streaming_response_async(
|
||||
response_object=response_object
|
||||
):
|
||||
chunks.append(chunk)
|
||||
return chunks
|
||||
|
||||
|
|
@ -2457,7 +2437,6 @@ class TestConvertToStreamingResponse:
|
|||
assert chunks[0].choices[0].delta.tool_calls[0].id == "call_1"
|
||||
assert chunks[0].choices[0].delta.tool_calls[0].function.name == "get_weather"
|
||||
|
||||
|
||||
class TestConvertToStreamingResponseAsync:
|
||||
def test_none_raises(self):
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -2495,7 +2474,9 @@ class TestConvertToStreamingResponseAsync:
|
|||
|
||||
async def run():
|
||||
chunks = []
|
||||
async for chunk in convert_to_streaming_response_async(response_object=response_object):
|
||||
async for chunk in convert_to_streaming_response_async(
|
||||
response_object=response_object
|
||||
):
|
||||
chunks.append(chunk)
|
||||
return chunks
|
||||
|
||||
|
|
@ -2510,7 +2491,6 @@ class TestConvertToStreamingResponseAsync:
|
|||
assert chunks[-1].choices[0].finish_reason == "stop"
|
||||
assert chunks[-1].usage.prompt_tokens == 3
|
||||
|
||||
|
||||
class TestHandleInvalidParallelToolCalls:
|
||||
def test_none_input(self):
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -2590,7 +2570,6 @@ class TestHandleInvalidParallelToolCalls:
|
|||
assert len(result) == 1
|
||||
assert result[0].id == "call_1"
|
||||
|
||||
|
||||
class TestShouldConvertToolCallToJsonMode:
|
||||
def test_returns_true_when_conditions_met(self):
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -2599,7 +2578,12 @@ class TestShouldConvertToolCallToJsonMode:
|
|||
from litellm.constants import RESPONSE_FORMAT_TOOL_NAME
|
||||
|
||||
tool_calls = [{"function": {"name": RESPONSE_FORMAT_TOOL_NAME}}]
|
||||
assert should_convert_tool_call_to_json_mode(tool_calls=tool_calls, convert_tool_call_to_json_mode=True) is True
|
||||
assert (
|
||||
should_convert_tool_call_to_json_mode(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=True
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
def test_returns_false_when_flag_off(self):
|
||||
from litellm.litellm_core_utils.llm_response_utils.convert_dict_to_response import (
|
||||
|
|
@ -2609,7 +2593,10 @@ class TestShouldConvertToolCallToJsonMode:
|
|||
|
||||
tool_calls = [{"function": {"name": RESPONSE_FORMAT_TOOL_NAME}}]
|
||||
assert (
|
||||
should_convert_tool_call_to_json_mode(tool_calls=tool_calls, convert_tool_call_to_json_mode=False) is False
|
||||
should_convert_tool_call_to_json_mode(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=False
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
def test_returns_false_when_wrong_tool_name(self):
|
||||
|
|
@ -2619,7 +2606,10 @@ class TestShouldConvertToolCallToJsonMode:
|
|||
|
||||
tool_calls = [{"function": {"name": "some_other_tool"}}]
|
||||
assert (
|
||||
should_convert_tool_call_to_json_mode(tool_calls=tool_calls, convert_tool_call_to_json_mode=True) is False
|
||||
should_convert_tool_call_to_json_mode(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=True
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
def test_returns_false_when_multiple_tool_calls(self):
|
||||
|
|
@ -2633,7 +2623,10 @@ class TestShouldConvertToolCallToJsonMode:
|
|||
{"function": {"name": "other"}},
|
||||
]
|
||||
assert (
|
||||
should_convert_tool_call_to_json_mode(tool_calls=tool_calls, convert_tool_call_to_json_mode=True) is False
|
||||
should_convert_tool_call_to_json_mode(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=True
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
def test_returns_false_when_none(self):
|
||||
|
|
@ -2641,8 +2634,12 @@ class TestShouldConvertToolCallToJsonMode:
|
|||
should_convert_tool_call_to_json_mode,
|
||||
)
|
||||
|
||||
assert should_convert_tool_call_to_json_mode(tool_calls=None, convert_tool_call_to_json_mode=True) is False
|
||||
|
||||
assert (
|
||||
should_convert_tool_call_to_json_mode(
|
||||
tool_calls=None, convert_tool_call_to_json_mode=True
|
||||
)
|
||||
is False
|
||||
)
|
||||
|
||||
class TestConvertToolCallToJsonMode:
|
||||
def test_converts_when_should(self):
|
||||
|
|
@ -2662,7 +2659,9 @@ class TestConvertToolCallToJsonMode:
|
|||
),
|
||||
)
|
||||
]
|
||||
message, finish_reason = convert_fn(tool_calls=tool_calls, convert_tool_call_to_json_mode=True)
|
||||
message, finish_reason = convert_fn(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=True
|
||||
)
|
||||
assert message is not None
|
||||
assert message.content == '{"key": "value"}'
|
||||
assert finish_reason == "stop"
|
||||
|
|
@ -2684,11 +2683,12 @@ class TestConvertToolCallToJsonMode:
|
|||
),
|
||||
)
|
||||
]
|
||||
message, finish_reason = convert_fn(tool_calls=tool_calls, convert_tool_call_to_json_mode=False)
|
||||
message, finish_reason = convert_fn(
|
||||
tool_calls=tool_calls, convert_tool_call_to_json_mode=False
|
||||
)
|
||||
assert message is None
|
||||
assert finish_reason is None
|
||||
|
||||
|
||||
class TestConvertToModelResponseObjectEmbedding:
|
||||
def test_basic_embedding_response(self):
|
||||
from litellm.types.utils import EmbeddingResponse
|
||||
|
|
@ -2714,7 +2714,6 @@ class TestConvertToModelResponseObjectEmbedding:
|
|||
assert result.data == [{"embedding": [0.1, 0.2, 0.3], "index": 0}]
|
||||
assert result.usage.prompt_tokens == 5
|
||||
|
||||
|
||||
class TestConvertToModelResponseObjectAudioTranscription:
|
||||
def test_basic_transcription(self):
|
||||
from litellm.types.utils import TranscriptionResponse
|
||||
|
|
@ -2774,7 +2773,6 @@ class TestConvertToModelResponseObjectAudioTranscription:
|
|||
assert result.usage.output_tokens == 5
|
||||
assert result.usage.input_token_details.audio_tokens == 4
|
||||
|
||||
|
||||
class TestConvertToModelResponseObjectRerank:
|
||||
def test_basic_rerank(self):
|
||||
from litellm.types.utils import RerankResponse
|
||||
|
|
@ -2793,7 +2791,6 @@ class TestConvertToModelResponseObjectRerank:
|
|||
assert result.id == "rerank-123"
|
||||
assert result.results[0]["relevance_score"] == 0.9
|
||||
|
||||
|
||||
class TestConvertToModelResponseObjectCompletion:
|
||||
def test_tool_calls_finish_reason_override(self):
|
||||
response_object = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue