mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
Merge branch 'BerriAI:main' into main
This commit is contained in:
commit
f2c2266fd7
5 changed files with 110 additions and 10 deletions
|
|
@ -755,16 +755,12 @@ class CustomStreamWrapper:
|
|||
setattr(model_response, k, v)
|
||||
return model_response
|
||||
|
||||
def return_processed_chunk_logic( # noqa
|
||||
def is_chunk_non_empty(
|
||||
self,
|
||||
completion_obj: Dict[str, Any],
|
||||
model_response: ModelResponseStream,
|
||||
response_obj: Dict[str, Any],
|
||||
):
|
||||
|
||||
print_verbose(
|
||||
f"completion_obj: {completion_obj}, model_response.choices[0]: {model_response.choices[0]}, response_obj: {response_obj}"
|
||||
)
|
||||
) -> bool:
|
||||
if (
|
||||
"content" in completion_obj
|
||||
and (
|
||||
|
|
@ -780,6 +776,10 @@ class CustomStreamWrapper:
|
|||
"function_call" in completion_obj
|
||||
and completion_obj["function_call"] is not None
|
||||
)
|
||||
or (
|
||||
"reasoning_content" in model_response.choices[0].delta
|
||||
and model_response.choices[0].delta.reasoning_content is not None
|
||||
)
|
||||
or (model_response.choices[0].delta.provider_specific_fields is not None)
|
||||
or (
|
||||
"provider_specific_fields" in model_response
|
||||
|
|
@ -789,8 +789,27 @@ class CustomStreamWrapper:
|
|||
"provider_specific_fields" in response_obj
|
||||
and response_obj["provider_specific_fields"] is not None
|
||||
)
|
||||
): # cannot set content of an OpenAI Object to be an empty string
|
||||
):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def return_processed_chunk_logic( # noqa
|
||||
self,
|
||||
completion_obj: Dict[str, Any],
|
||||
model_response: ModelResponseStream,
|
||||
response_obj: Dict[str, Any],
|
||||
):
|
||||
|
||||
print_verbose(
|
||||
f"completion_obj: {completion_obj}, model_response.choices[0]: {model_response.choices[0]}, response_obj: {response_obj}"
|
||||
)
|
||||
is_chunk_non_empty = self.is_chunk_non_empty(
|
||||
completion_obj, model_response, response_obj
|
||||
)
|
||||
if (
|
||||
is_chunk_non_empty
|
||||
): # cannot set content of an OpenAI Object to be an empty string
|
||||
self.safety_checker()
|
||||
hold, model_response_str = self.check_special_tokens(
|
||||
chunk=completion_obj["content"],
|
||||
|
|
@ -806,7 +825,7 @@ class CustomStreamWrapper:
|
|||
for choice in original_chunk.choices:
|
||||
try:
|
||||
if isinstance(choice, BaseModel):
|
||||
choice_json = choice.model_dump()
|
||||
choice_json = choice.model_dump() # type: ignore
|
||||
choice_json.pop(
|
||||
"finish_reason", None
|
||||
) # for mistral etc. which return a value in their last chunk (not-openai compatible).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "litellm"
|
||||
version = "1.62.1"
|
||||
version = "1.62.2"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
authors = ["BerriAI"]
|
||||
license = "MIT"
|
||||
|
|
@ -96,7 +96,7 @@ requires = ["poetry-core", "wheel"]
|
|||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.commitizen]
|
||||
version = "1.62.1"
|
||||
version = "1.62.2"
|
||||
version_files = [
|
||||
"pyproject.toml:^version"
|
||||
]
|
||||
|
|
|
|||
48
tests/litellm/litellm_core_utils/test_streaming_handler.py
Normal file
48
tests/litellm/litellm_core_utils/test_streaming_handler.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(
|
||||
0, os.path.abspath("../../..")
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper
|
||||
from litellm.types.utils import ModelResponseStream
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def initialized_custom_stream_wrapper() -> CustomStreamWrapper:
|
||||
streaming_handler = CustomStreamWrapper(
|
||||
completion_stream=None,
|
||||
model=None,
|
||||
logging_obj=MagicMock(),
|
||||
custom_llm_provider=None,
|
||||
)
|
||||
return streaming_handler
|
||||
|
||||
|
||||
def test_is_chunk_non_empty(initialized_custom_stream_wrapper: CustomStreamWrapper):
|
||||
"""Unit test if non-empty when reasoning_content is present"""
|
||||
chunk = {
|
||||
"id": "e89b6501-8ac2-464c-9550-7cd3daf94350",
|
||||
"object": "chat.completion.chunk",
|
||||
"created": 1741037890,
|
||||
"model": "deepseek-reasoner",
|
||||
"system_fingerprint": "fp_5417b77867_prod0225",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"delta": {"content": None, "reasoning_content": "."},
|
||||
"logprobs": None,
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
assert initialized_custom_stream_wrapper.is_chunk_non_empty(
|
||||
completion_obj=MagicMock(),
|
||||
model_response=ModelResponseStream(**chunk),
|
||||
response_obj=MagicMock(),
|
||||
)
|
||||
|
|
@ -360,3 +360,34 @@ def test_o1_parallel_tool_calls(model):
|
|||
parallel_tool_calls=True,
|
||||
drop_params=True,
|
||||
)
|
||||
|
||||
|
||||
def test_openai_chat_completion_streaming_handler_reasoning_content():
|
||||
from litellm.llms.openai.chat.gpt_transformation import (
|
||||
OpenAIChatCompletionStreamingHandler,
|
||||
)
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
streaming_handler = OpenAIChatCompletionStreamingHandler(
|
||||
streaming_response=MagicMock(),
|
||||
sync_stream=True,
|
||||
)
|
||||
response = streaming_handler.chunk_parser(
|
||||
chunk={
|
||||
"id": "e89b6501-8ac2-464c-9550-7cd3daf94350",
|
||||
"object": "chat.completion.chunk",
|
||||
"created": 1741037890,
|
||||
"model": "deepseek-reasoner",
|
||||
"system_fingerprint": "fp_5417b77867_prod0225",
|
||||
"choices": [
|
||||
{
|
||||
"index": 0,
|
||||
"delta": {"content": None, "reasoning_content": "."},
|
||||
"logprobs": None,
|
||||
"finish_reason": None,
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
assert response.choices[0].delta.reasoning_content == "."
|
||||
|
|
|
|||
|
|
@ -340,6 +340,8 @@ def test_get_model_info_bedrock_models():
|
|||
base_model = BedrockModelInfo.get_base_model(k)
|
||||
base_model_info = litellm.model_cost[base_model]
|
||||
for base_model_key, base_model_value in base_model_info.items():
|
||||
if "invoke/" in k:
|
||||
continue
|
||||
if base_model_key.startswith("supports_"):
|
||||
assert (
|
||||
base_model_key in v
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue