mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix(docs): correct Docker image tag in v1.82.0 release notes (#23537)
* bump: version 1.82.1 → 1.82.2 * fix(gemini): preserve toolConfig on native generate_content (#23493) * chore: regenerate poetry.lock to match pyproject.toml (#23514) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix(docs): correct Docker image tag in v1.82.0 release notes Add missing 'v' prefix to Docker image tag: main-1.82.0-stable → main-v1.82.0-stable Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: yuneng-jiang <yuneng.jiang@gmail.com> Co-authored-by: Emerson Gomes <emerson.gomes@thalesgroup.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
976f1a0115
commit
43db397854
11 changed files with 108 additions and 27 deletions
|
|
@ -26,7 +26,7 @@ import TabItem from '@theme/TabItem';
|
|||
docker run \
|
||||
-e STORE_MODEL_IN_DB=True \
|
||||
-p 4000:4000 \
|
||||
ghcr.io/berriai/litellm:main-1.82.0-stable
|
||||
ghcr.io/berriai/litellm:main-v1.82.0-stable
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ base_llm_http_handler = BaseLLMHTTPHandler()
|
|||
#################################################
|
||||
|
||||
|
||||
def _get_tool_config_from_kwargs(kwargs: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
||||
"""Read toolConfig/tool_config without dropping intentionally empty dicts."""
|
||||
if "toolConfig" in kwargs:
|
||||
return kwargs["toolConfig"]
|
||||
if "tool_config" in kwargs:
|
||||
return kwargs["tool_config"]
|
||||
return None
|
||||
|
||||
|
||||
class GenerateContentSetupResult(BaseModel):
|
||||
"""Internal Type - Result of setting up a generate content call"""
|
||||
|
||||
|
|
@ -171,12 +180,14 @@ class GenerateContentHelper:
|
|||
system_instruction = kwargs.get("systemInstruction") or kwargs.get(
|
||||
"system_instruction"
|
||||
)
|
||||
tool_config = _get_tool_config_from_kwargs(kwargs)
|
||||
request_body = (
|
||||
generate_content_provider_config.transform_generate_content_request(
|
||||
model=model,
|
||||
contents=contents,
|
||||
tools=tools,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
tool_config=tool_config,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
)
|
||||
|
|
@ -323,6 +334,7 @@ def generate_content(
|
|||
system_instruction = kwargs.get("systemInstruction") or kwargs.get(
|
||||
"system_instruction"
|
||||
)
|
||||
tool_config = _get_tool_config_from_kwargs(kwargs)
|
||||
|
||||
# Check if we should use the adapter (when provider config is None)
|
||||
if setup_result.generate_content_provider_config is None:
|
||||
|
|
@ -354,6 +366,7 @@ def generate_content(
|
|||
_is_async=_is_async,
|
||||
client=kwargs.get("client"),
|
||||
litellm_metadata=kwargs.get("litellm_metadata", {}),
|
||||
tool_config=tool_config,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
||||
|
|
@ -414,6 +427,7 @@ async def agenerate_content_stream(
|
|||
system_instruction = kwargs.get("systemInstruction") or kwargs.get(
|
||||
"system_instruction"
|
||||
)
|
||||
tool_config = _get_tool_config_from_kwargs(kwargs)
|
||||
|
||||
# Check if we should use the adapter (when provider config is None)
|
||||
if setup_result.generate_content_provider_config is None:
|
||||
|
|
@ -452,6 +466,7 @@ async def agenerate_content_stream(
|
|||
client=kwargs.get("client"),
|
||||
stream=True,
|
||||
litellm_metadata=kwargs.get("litellm_metadata", {}),
|
||||
tool_config=tool_config,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
||||
|
|
@ -520,6 +535,10 @@ def generate_content_stream(
|
|||
)
|
||||
|
||||
# Call the handler with streaming enabled (sync version)
|
||||
system_instruction = kwargs.get("systemInstruction") or kwargs.get(
|
||||
"system_instruction"
|
||||
)
|
||||
tool_config = _get_tool_config_from_kwargs(kwargs)
|
||||
return base_llm_http_handler.generate_content_handler(
|
||||
model=setup_result.model,
|
||||
contents=contents,
|
||||
|
|
@ -536,6 +555,8 @@ def generate_content_stream(
|
|||
client=kwargs.get("client"),
|
||||
stream=True,
|
||||
litellm_metadata=kwargs.get("litellm_metadata", {}),
|
||||
tool_config=tool_config,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ class BaseGoogleGenAIGenerateContentConfig(ABC):
|
|||
contents: GenerateContentContentListUnionDict,
|
||||
tools: Optional[ToolConfigDict],
|
||||
generate_content_config_dict: Dict,
|
||||
tool_config: Optional[Dict[str, Any]] = None,
|
||||
system_instruction: Optional[Any] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
|
|
@ -161,6 +162,7 @@ class BaseGoogleGenAIGenerateContentConfig(ABC):
|
|||
model: The model name
|
||||
contents: Input contents
|
||||
tools: Tools
|
||||
tool_config: Tool configuration
|
||||
generate_content_config_dict: Generation config parameters
|
||||
system_instruction: Optional system instruction
|
||||
|
||||
|
|
|
|||
|
|
@ -9329,6 +9329,7 @@ class BaseLLMHTTPHandler:
|
|||
client: Optional[Union[HTTPHandler, AsyncHTTPHandler]] = None,
|
||||
stream: bool = False,
|
||||
litellm_metadata: Optional[Dict[str, Any]] = None,
|
||||
tool_config: Optional[Dict[str, Any]] = None,
|
||||
system_instruction: Optional[Any] = None,
|
||||
) -> Any:
|
||||
"""
|
||||
|
|
@ -9346,6 +9347,7 @@ class BaseLLMHTTPHandler:
|
|||
generate_content_provider_config=generate_content_provider_config,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
tools=tools,
|
||||
tool_config=tool_config,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
litellm_params=litellm_params,
|
||||
logging_obj=logging_obj,
|
||||
|
|
@ -9384,6 +9386,7 @@ class BaseLLMHTTPHandler:
|
|||
model=model,
|
||||
contents=contents,
|
||||
tools=tools,
|
||||
tool_config=tool_config,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
|
@ -9456,6 +9459,7 @@ class BaseLLMHTTPHandler:
|
|||
client: Optional[AsyncHTTPHandler] = None,
|
||||
stream: bool = False,
|
||||
litellm_metadata: Optional[Dict[str, Any]] = None,
|
||||
tool_config: Optional[Dict[str, Any]] = None,
|
||||
system_instruction: Optional[Any] = None,
|
||||
) -> Any:
|
||||
"""
|
||||
|
|
@ -9493,6 +9497,7 @@ class BaseLLMHTTPHandler:
|
|||
model=model,
|
||||
contents=contents,
|
||||
tools=tools,
|
||||
tool_config=tool_config,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -308,6 +308,7 @@ class GoogleGenAIConfig(BaseGoogleGenAIGenerateContentConfig, VertexLLM):
|
|||
contents: GenerateContentContentListUnionDict,
|
||||
tools: Optional[ToolConfigDict],
|
||||
generate_content_config_dict: Dict,
|
||||
tool_config: Optional[Dict[str, Any]] = None,
|
||||
system_instruction: Optional[Any] = None,
|
||||
) -> dict:
|
||||
from litellm.types.google_genai.main import (
|
||||
|
|
@ -326,6 +327,8 @@ class GoogleGenAIConfig(BaseGoogleGenAIGenerateContentConfig, VertexLLM):
|
|||
|
||||
if system_instruction is not None:
|
||||
request_dict["systemInstruction"] = system_instruction
|
||||
if tool_config is not None:
|
||||
request_dict["toolConfig"] = tool_config
|
||||
return request_dict
|
||||
|
||||
def transform_generate_content_response(
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ class VertexAIGoogleGenAIConfig(GoogleGenAIConfig):
|
|||
contents: Any,
|
||||
tools: Optional[Any],
|
||||
generate_content_config_dict: Dict,
|
||||
tool_config: Optional[Dict[str, Any]] = None,
|
||||
system_instruction: Optional[Any] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
|
|
@ -89,8 +90,11 @@ class VertexAIGoogleGenAIConfig(GoogleGenAIConfig):
|
|||
if tools:
|
||||
result["tools"] = tools
|
||||
|
||||
if tool_config is not None:
|
||||
result["toolConfig"] = tool_config
|
||||
|
||||
# Add systemInstruction if provided
|
||||
if system_instruction:
|
||||
if system_instruction is not None:
|
||||
result["systemInstruction"] = system_instruction
|
||||
|
||||
# Handle generationConfig - Vertex AI expects it in the same format
|
||||
|
|
|
|||
8
poetry.lock
generated
8
poetry.lock
generated
|
|
@ -3222,15 +3222,15 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "litellm-proxy-extras"
|
||||
version = "0.4.54"
|
||||
version = "0.4.56"
|
||||
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
|
||||
optional = true
|
||||
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"proxy\""
|
||||
files = [
|
||||
{file = "litellm_proxy_extras-0.4.54-py3-none-any.whl", hash = "sha256:6621cf529f7f3647eb2dd0d2c417d91db8c7a05c3c592bef251887a122928837"},
|
||||
{file = "litellm_proxy_extras-0.4.54.tar.gz", hash = "sha256:2c777ecdf39901c4007ade4466eb6398985ed4000afe3fc2cac997e1169e8cee"},
|
||||
{file = "litellm_proxy_extras-0.4.56-py3-none-any.whl", hash = "sha256:52dbe3b5358c790e77e12f1ec5ef8e7508b383c2aaf41299750b6fb400908ee7"},
|
||||
{file = "litellm_proxy_extras-0.4.56.tar.gz", hash = "sha256:63ad59baa0defccc5c929cfd933ee7e32a6614b0fc5fa0fc45a12d7608e33f08"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -8002,4 +8002,4 @@ utils = ["numpydoc"]
|
|||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.9,<4.0"
|
||||
content-hash = "5ed0af4e3644bc7b5a02b8bfc8b3eda15c014b43aa6da7a9a97a9b070fba5366"
|
||||
content-hash = "1ade5dee030fd878c907a20b88a6a52ca26ee4ecbed15ecb045f9ae1d4b8b714"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "litellm"
|
||||
version = "1.82.1"
|
||||
version = "1.82.2"
|
||||
description = "Library to easily interface with LLM API providers"
|
||||
authors = ["BerriAI"]
|
||||
license = "MIT"
|
||||
|
|
@ -183,7 +183,7 @@ requires = ["poetry-core", "wheel"]
|
|||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.commitizen]
|
||||
version = "1.82.1"
|
||||
version = "1.82.2"
|
||||
version_files = [
|
||||
"pyproject.toml:^version"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ async def test_google_gemini_httpx_request_direct():
|
|||
],
|
||||
"role": "user"
|
||||
},
|
||||
"toolConfig": {"functionCallingConfig": {"mode": "ANY"}},
|
||||
"config": { # Note: already transformed from generationConfig
|
||||
"temperature": 0,
|
||||
"topP": 1,
|
||||
|
|
@ -240,6 +241,7 @@ async def test_google_gemini_httpx_request_direct():
|
|||
generate_content_provider_config=provider_config,
|
||||
generate_content_config_dict=sample_payload["config"],
|
||||
tools=None,
|
||||
tool_config=sample_payload["toolConfig"],
|
||||
custom_llm_provider="gemini",
|
||||
litellm_params=litellm_params,
|
||||
logging_obj=logging_obj,
|
||||
|
|
@ -265,6 +267,7 @@ async def test_google_gemini_httpx_request_direct():
|
|||
request_data = call_kwargs.get('json')
|
||||
if request_data:
|
||||
assert 'contents' in request_data, "Expected 'contents' in request data"
|
||||
assert request_data["toolConfig"] == sample_payload["toolConfig"]
|
||||
|
||||
# The config should be included in the request as generationConfig
|
||||
if 'generationConfig' in request_data:
|
||||
|
|
|
|||
|
|
@ -1,24 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test to verify the Google GenAI generate_content adapter functionality
|
||||
"""
|
||||
import json
|
||||
"""Tests for Google GenAI main entrypoints."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(
|
||||
0, os.path.abspath("../../..")
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import litellm
|
||||
sys.path.insert(0, os.path.abspath("../../.."))
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -26,8 +15,6 @@ async def test_agenerate_content_stream():
|
|||
"""
|
||||
Test that the agenerate_content_stream function works
|
||||
"""
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from litellm.google_genai.main import (
|
||||
agenerate_content_stream,
|
||||
base_llm_http_handler,
|
||||
|
|
@ -36,10 +23,40 @@ async def test_agenerate_content_stream():
|
|||
with patch.object(
|
||||
base_llm_http_handler, "generate_content_handler", new=AsyncMock()
|
||||
) as mock_post:
|
||||
result = await agenerate_content_stream(
|
||||
await agenerate_content_stream(
|
||||
model="gemini/gemini-2.0-flash-001",
|
||||
contents="Hello, world!",
|
||||
stream=True,
|
||||
)
|
||||
mock_post.assert_called_once()
|
||||
mock_post.call_args.kwargs["stream"] == True
|
||||
assert mock_post.call_args.kwargs["stream"] is True
|
||||
|
||||
|
||||
def test_generate_content_stream_forwards_system_instruction():
|
||||
"""Test that generate_content_stream forwards systemInstruction and toolConfig."""
|
||||
from litellm.google_genai.main import (
|
||||
base_llm_http_handler,
|
||||
generate_content_stream,
|
||||
)
|
||||
|
||||
mock_response = MagicMock()
|
||||
tool_config = {"functionCallingConfig": {"mode": "ANY"}}
|
||||
|
||||
with patch.object(
|
||||
base_llm_http_handler, "generate_content_handler", return_value=mock_response
|
||||
) as mock_post:
|
||||
result = generate_content_stream(
|
||||
model="gemini/gemini-2.0-flash-001",
|
||||
contents="Hello, world!",
|
||||
stream=True,
|
||||
systemInstruction={"parts": [{"text": "You are helpful"}]},
|
||||
toolConfig=tool_config,
|
||||
)
|
||||
|
||||
assert result is mock_response
|
||||
mock_post.assert_called_once()
|
||||
assert mock_post.call_args.kwargs["stream"] is True
|
||||
assert mock_post.call_args.kwargs["tool_config"] == tool_config
|
||||
assert mock_post.call_args.kwargs["system_instruction"] == {
|
||||
"parts": [{"text": "You are helpful"}]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ sys.path.insert(
|
|||
import pytest
|
||||
|
||||
from litellm.llms.gemini.google_genai.transformation import GoogleGenAIConfig
|
||||
from litellm.llms.vertex_ai.google_genai.transformation import (
|
||||
VertexAIGoogleGenAIConfig,
|
||||
)
|
||||
from litellm.responses.litellm_completion_transformation.transformation import (
|
||||
LiteLLMCompletionResponsesConfig,
|
||||
)
|
||||
|
|
@ -173,6 +176,26 @@ def test_map_generate_content_optional_params_response_mime_type():
|
|||
assert "responseJsonSchema" in result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config_cls",
|
||||
[GoogleGenAIConfig, VertexAIGoogleGenAIConfig],
|
||||
)
|
||||
def test_transform_generate_content_request_preserves_tool_config(config_cls):
|
||||
config = config_cls()
|
||||
tool_config = {"functionCallingConfig": {"mode": "ANY"}}
|
||||
|
||||
result = config.transform_generate_content_request(
|
||||
model="gemini-3-flash-preview",
|
||||
contents=[{"role": "user", "parts": [{"text": "hello"}]}],
|
||||
tools=[{"functionDeclarations": [{"name": "execute_command"}]}],
|
||||
tool_config=tool_config,
|
||||
generate_content_config_dict={"temperature": 1},
|
||||
system_instruction={"parts": [{"text": "system"}]},
|
||||
)
|
||||
|
||||
assert result["toolConfig"] == tool_config
|
||||
|
||||
|
||||
def test_responses_api_reasoning_dict_format():
|
||||
"""Test that reasoning parameter with dict format is mapped to reasoning_effort"""
|
||||
from litellm.types.llms.openai import ResponsesAPIOptionalRequestParams
|
||||
|
|
@ -274,6 +297,7 @@ def test_transform_generate_content_request_with_system_instruction():
|
|||
model="gemini-3-flash-preview",
|
||||
contents=contents,
|
||||
tools=None,
|
||||
tool_config=None,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
|
@ -305,6 +329,7 @@ def test_transform_generate_content_request_without_system_instruction():
|
|||
model="gemini-3-flash-preview",
|
||||
contents=contents,
|
||||
tools=None,
|
||||
tool_config=None,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
system_instruction=None,
|
||||
)
|
||||
|
|
@ -356,6 +381,7 @@ def test_transform_generate_content_request_system_instruction_with_tools():
|
|||
model="gemini-3-flash-preview",
|
||||
contents=contents,
|
||||
tools=tools,
|
||||
tool_config=None,
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
system_instruction=system_instruction,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue