mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-18 06:26:16 +00:00
Add support for structured output thinkingConfig param
This commit is contained in:
@@ -75,6 +75,7 @@ class GoogleGenAIConfig(BaseGoogleGenAIGenerateContentConfig, VertexLLM):
|
||||
"seed",
|
||||
"response_mime_type",
|
||||
"response_schema",
|
||||
"response_json_schema",
|
||||
"routing_config",
|
||||
"model_selection_config",
|
||||
"safety_settings",
|
||||
@@ -105,13 +106,34 @@ class GoogleGenAIConfig(BaseGoogleGenAIGenerateContentConfig, VertexLLM):
|
||||
Returns:
|
||||
Mapped parameters for the provider
|
||||
"""
|
||||
from litellm.llms.vertex_ai.gemini.transformation import _snake_to_camel, _camel_to_snake
|
||||
|
||||
_generate_content_config_dict: Dict[str, Any] = {}
|
||||
supported_google_genai_params = (
|
||||
self.get_supported_generate_content_optional_params(model)
|
||||
)
|
||||
# Create a set with both camelCase and snake_case versions for faster lookup
|
||||
supported_params_set = set(supported_google_genai_params)
|
||||
supported_params_set.update(_snake_to_camel(p) for p in supported_google_genai_params)
|
||||
supported_params_set.update(_camel_to_snake(p) for p in supported_google_genai_params if "_" not in p)
|
||||
|
||||
for param, value in generate_content_config_dict.items():
|
||||
if param in supported_google_genai_params:
|
||||
_generate_content_config_dict[param] = value
|
||||
# Google GenAI API expects camelCase, so we'll always output in camelCase
|
||||
# Check if param (or its variants) is supported
|
||||
param_snake = _camel_to_snake(param)
|
||||
param_camel = _snake_to_camel(param)
|
||||
|
||||
# Check if param is supported in any format
|
||||
is_supported = (
|
||||
param in supported_google_genai_params or
|
||||
param_snake in supported_google_genai_params or
|
||||
param_camel in supported_google_genai_params
|
||||
)
|
||||
|
||||
if is_supported:
|
||||
# Always output in camelCase for Google GenAI API
|
||||
output_key = param_camel if param != param_camel else param
|
||||
_generate_content_config_dict[output_key] = value
|
||||
return _generate_content_config_dict
|
||||
|
||||
def validate_environment(
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test to verify the Google GenAI transformation logic for generateContent parameters
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(
|
||||
0, os.path.abspath("../../..")
|
||||
) # Adds the parent directory to the system path
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.llms.gemini.google_genai.transformation import GoogleGenAIConfig
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_response_json_schema_camelcase():
|
||||
"""Test that responseJsonSchema (camelCase) is passed through correctly"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"responseJsonSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"recipe_name": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"temperature": 1.0
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# responseJsonSchema should be in the result (camelCase format for Google GenAI API)
|
||||
assert "responseJsonSchema" in result
|
||||
assert result["responseJsonSchema"] == generate_content_config_dict["responseJsonSchema"]
|
||||
assert "temperature" in result
|
||||
assert result["temperature"] == 1.0
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_response_schema_snakecase():
|
||||
"""Test that response_schema (snake_case) is converted to responseJsonSchema (camelCase)"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"response_json_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"recipe_name": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"temperature": 1.0
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# response_schema should be converted to responseJsonSchema (camelCase)
|
||||
assert "responseJsonSchema" in result
|
||||
assert result["responseJsonSchema"] == generate_content_config_dict["response_json_schema"]
|
||||
assert "temperature" in result
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_thinking_config_camelcase():
|
||||
"""Test that thinkingConfig (camelCase) is passed through correctly"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"thinkingConfig": {
|
||||
"thinkingLevel": "minimal",
|
||||
"includeThoughts": True
|
||||
},
|
||||
"temperature": 1.0
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# thinkingConfig should be in the result (camelCase format for Google GenAI API)
|
||||
assert "thinkingConfig" in result
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "minimal"
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
assert "temperature" in result
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_thinking_config_snakecase():
|
||||
"""Test that thinking_config (snake_case) is converted to thinkingConfig (camelCase)"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"thinking_config": {
|
||||
"thinkingLevel": "medium",
|
||||
"includeThoughts": True
|
||||
},
|
||||
"temperature": 1.0
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# thinking_config should be converted to thinkingConfig (camelCase)
|
||||
assert "thinkingConfig" in result
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "medium"
|
||||
assert result["thinkingConfig"]["includeThoughts"] is True
|
||||
assert "thinking_config" not in result # Should not be in snake_case format
|
||||
assert "temperature" in result
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_mixed_formats():
|
||||
"""Test that both camelCase and snake_case parameters work together"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"responseJsonSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"recipe_name": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"thinking_config": {
|
||||
"thinkingLevel": "low",
|
||||
"includeThoughts": True
|
||||
},
|
||||
"temperature": 1.0,
|
||||
"max_output_tokens": 100
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# All parameters should be converted to camelCase
|
||||
assert "responseJsonSchema" in result
|
||||
assert "thinkingConfig" in result
|
||||
assert result["thinkingConfig"]["thinkingLevel"] == "low"
|
||||
assert "temperature" in result
|
||||
assert "maxOutputTokens" in result # This one stays as-is if it's in supported list
|
||||
|
||||
|
||||
def test_map_generate_content_optional_params_response_mime_type():
|
||||
"""Test that responseMimeType is handled correctly"""
|
||||
config = GoogleGenAIConfig()
|
||||
|
||||
generate_content_config_dict = {
|
||||
"responseMimeType": "application/json",
|
||||
"responseJsonSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"recipe_name": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = config.map_generate_content_optional_params(
|
||||
generate_content_config_dict=generate_content_config_dict,
|
||||
model="gemini/skyhawk"
|
||||
)
|
||||
|
||||
# responseMimeType should be passed through (it's already camelCase)
|
||||
assert "responseMimeType" in result or "response_mime_type" in result
|
||||
assert "responseJsonSchema" in result
|
||||
|
||||
Reference in New Issue
Block a user