mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
Add tool choice mapping for giga chat
This commit is contained in:
parent
ebf0beda97
commit
acf5ad1155
2 changed files with 192 additions and 7 deletions
|
|
@ -158,13 +158,10 @@ class GigaChatConfig(BaseConfig):
|
|||
# Convert tools to functions format
|
||||
optional_params["functions"] = self._convert_tools_to_functions(value)
|
||||
elif param == "tool_choice":
|
||||
if isinstance(value, dict) and value.get("function"):
|
||||
optional_params["function_call"] = {"name": value["function"]["name"]}
|
||||
elif value == "auto":
|
||||
pass # Default behavior
|
||||
elif value == "required":
|
||||
# GigaChat doesn't have 'required', handled differently
|
||||
pass
|
||||
# Map OpenAI tool_choice to GigaChat function_call
|
||||
mapped_choice = self._map_tool_choice(value)
|
||||
if mapped_choice is not None:
|
||||
optional_params["function_call"] = mapped_choice
|
||||
elif param == "functions":
|
||||
optional_params["functions"] = value
|
||||
elif param == "function_call":
|
||||
|
|
@ -203,6 +200,48 @@ class GigaChatConfig(BaseConfig):
|
|||
})
|
||||
return functions
|
||||
|
||||
def _map_tool_choice(
|
||||
self, tool_choice: Union[str, dict]
|
||||
) -> Optional[Union[str, dict]]:
|
||||
"""
|
||||
Map OpenAI tool_choice to GigaChat function_call format.
|
||||
|
||||
OpenAI format:
|
||||
- "auto": Call zero, one, or multiple functions (default)
|
||||
- "required": Call one or more functions
|
||||
- "none": Don't call any functions
|
||||
- {"type": "function", "function": {"name": "get_weather"}}: Force specific function
|
||||
|
||||
GigaChat format:
|
||||
- "none": Disable function calls
|
||||
- "auto": Automatic mode (default)
|
||||
- {"name": "get_weather"}: Force specific function
|
||||
|
||||
Args:
|
||||
tool_choice: OpenAI tool_choice value
|
||||
|
||||
Returns:
|
||||
GigaChat function_call value or None
|
||||
"""
|
||||
if tool_choice == "none":
|
||||
return "none"
|
||||
elif tool_choice == "auto":
|
||||
return "auto"
|
||||
elif tool_choice == "required":
|
||||
# GigaChat doesn't have a direct "required" equivalent
|
||||
# Use "auto" as the closest behavior
|
||||
return "auto"
|
||||
elif isinstance(tool_choice, dict):
|
||||
# OpenAI format: {"type": "function", "function": {"name": "func_name"}}
|
||||
# GigaChat format: {"name": "func_name"}
|
||||
if tool_choice.get("type") == "function":
|
||||
func_name = tool_choice.get("function", {}).get("name")
|
||||
if func_name:
|
||||
return {"name": func_name}
|
||||
|
||||
# Default to None (don't set function_call)
|
||||
return None
|
||||
|
||||
def _upload_image(self, image_url: str) -> Optional[str]:
|
||||
"""
|
||||
Upload image to GigaChat and return file_id.
|
||||
|
|
|
|||
|
|
@ -347,3 +347,149 @@ class TestGigaChatSupportedParams:
|
|||
assert "tools" in supported
|
||||
assert "response_format" in supported
|
||||
assert "stream" in supported
|
||||
|
||||
|
||||
class TestGigaChatToolChoiceMapping:
|
||||
"""Tests for tool_choice -> function_call mapping"""
|
||||
|
||||
@pytest.fixture
|
||||
def config(self):
|
||||
from litellm.llms.gigachat.chat.transformation import GigaChatConfig
|
||||
return GigaChatConfig()
|
||||
|
||||
def test_tool_choice_none(self, config):
|
||||
"""tool_choice='none' should map to function_call='none'"""
|
||||
result = config._map_tool_choice("none")
|
||||
assert result == "none"
|
||||
|
||||
def test_tool_choice_auto(self, config):
|
||||
"""tool_choice='auto' should map to function_call='auto'"""
|
||||
result = config._map_tool_choice("auto")
|
||||
assert result == "auto"
|
||||
|
||||
def test_tool_choice_required(self, config):
|
||||
"""tool_choice='required' should map to function_call='auto' (closest equivalent)"""
|
||||
result = config._map_tool_choice("required")
|
||||
assert result == "auto"
|
||||
|
||||
def test_tool_choice_forced_function(self, config):
|
||||
"""tool_choice with forced function should map to function_call with name"""
|
||||
tool_choice = {
|
||||
"type": "function",
|
||||
"function": {"name": "get_weather"}
|
||||
}
|
||||
result = config._map_tool_choice(tool_choice)
|
||||
assert result == {"name": "get_weather"}
|
||||
|
||||
def test_tool_choice_forced_function_full(self, config):
|
||||
"""tool_choice with full function details should extract only name"""
|
||||
tool_choice = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "weather_forecast",
|
||||
"description": "Get weather forecast"
|
||||
}
|
||||
}
|
||||
result = config._map_tool_choice(tool_choice)
|
||||
assert result == {"name": "weather_forecast"}
|
||||
|
||||
def test_tool_choice_invalid_dict(self, config):
|
||||
"""tool_choice with invalid dict should return None"""
|
||||
tool_choice = {"type": "tool"} # Missing function
|
||||
result = config._map_tool_choice(tool_choice)
|
||||
assert result is None
|
||||
|
||||
def test_tool_choice_in_map_openai_params_auto(self, config):
|
||||
"""tool_choice='auto' should be mapped in map_openai_params"""
|
||||
params = {"tool_choice": "auto"}
|
||||
result = config.map_openai_params(
|
||||
non_default_params=params,
|
||||
optional_params={},
|
||||
model="GigaChat",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["function_call"] == "auto"
|
||||
|
||||
def test_tool_choice_in_map_openai_params_none(self, config):
|
||||
"""tool_choice='none' should be mapped in map_openai_params"""
|
||||
params = {"tool_choice": "none"}
|
||||
result = config.map_openai_params(
|
||||
non_default_params=params,
|
||||
optional_params={},
|
||||
model="GigaChat",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["function_call"] == "none"
|
||||
|
||||
def test_tool_choice_in_map_openai_params_required(self, config):
|
||||
"""tool_choice='required' should be mapped to 'auto' in map_openai_params"""
|
||||
params = {"tool_choice": "required"}
|
||||
result = config.map_openai_params(
|
||||
non_default_params=params,
|
||||
optional_params={},
|
||||
model="GigaChat",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["function_call"] == "auto"
|
||||
|
||||
def test_tool_choice_in_map_openai_params_forced(self, config):
|
||||
"""tool_choice with forced function should be mapped in map_openai_params"""
|
||||
params = {
|
||||
"tool_choice": {
|
||||
"type": "function",
|
||||
"function": {"name": "weather_forecast"}
|
||||
}
|
||||
}
|
||||
result = config.map_openai_params(
|
||||
non_default_params=params,
|
||||
optional_params={},
|
||||
model="GigaChat",
|
||||
drop_params=False,
|
||||
)
|
||||
assert result["function_call"] == {"name": "weather_forecast"}
|
||||
|
||||
def test_tool_choice_with_tools(self, config):
|
||||
"""tool_choice should work together with tools parameter"""
|
||||
params = {
|
||||
"tools": [{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"description": "Get weather",
|
||||
"parameters": {"type": "object", "properties": {}}
|
||||
}
|
||||
}],
|
||||
"tool_choice": {
|
||||
"type": "function",
|
||||
"function": {"name": "get_weather"}
|
||||
}
|
||||
}
|
||||
result = config.map_openai_params(
|
||||
non_default_params=params,
|
||||
optional_params={},
|
||||
model="GigaChat",
|
||||
drop_params=False,
|
||||
)
|
||||
assert "functions" in result
|
||||
assert result["function_call"] == {"name": "get_weather"}
|
||||
|
||||
def test_transform_request_with_tool_choice(self, config):
|
||||
"""Full transform_request should include function_call from tool_choice"""
|
||||
messages = [{"role": "user", "content": "What's the weather?"}]
|
||||
optional_params = {
|
||||
"functions": [{
|
||||
"name": "get_weather",
|
||||
"description": "Get weather",
|
||||
"parameters": {"type": "object", "properties": {}}
|
||||
}],
|
||||
"function_call": {"name": "get_weather"}
|
||||
}
|
||||
result = config.transform_request(
|
||||
model="gigachat/GigaChat",
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
assert "function_call" in result
|
||||
assert result["function_call"] == {"name": "get_weather"}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue