Add mapping for reasoning effort to summary of responses API

This commit is contained in:
Sameer Kankute 2026-01-05 11:21:34 +05:30
parent fcabc059ca
commit 42d4aab3e7
3 changed files with 89 additions and 7 deletions

View File

@ -691,19 +691,19 @@ class LiteLLMResponsesTransformationHandler(CompletionTransformationBridge):
if isinstance(reasoning_effort, dict):
return Reasoning(**reasoning_effort) # type: ignore[typeddict-item]
# If string is passed, map without summary (default)
# If string is passed, map with summary="concise"
if reasoning_effort == "none":
return Reasoning(effort="none") # type: ignore
return Reasoning(effort="none", summary="concise") # type: ignore
elif reasoning_effort == "high":
return Reasoning(effort="high")
return Reasoning(effort="high", summary="concise")
elif reasoning_effort == "xhigh":
return Reasoning(effort="xhigh") # type: ignore[typeddict-item]
return Reasoning(effort="xhigh", summary="concise") # type: ignore[typeddict-item]
elif reasoning_effort == "medium":
return Reasoning(effort="medium")
return Reasoning(effort="medium", summary="concise")
elif reasoning_effort == "low":
return Reasoning(effort="low")
return Reasoning(effort="low", summary="concise")
elif reasoning_effort == "minimal":
return Reasoning(effort="minimal")
return Reasoning(effort="minimal", summary="concise")
return None
def _transform_response_format_to_text_format(

View File

@ -11640,6 +11640,7 @@
"supports_tool_choice": true
},
"gemini-1.5-flash": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 2e-06,
"input_cost_per_audio_per_second_above_128k_tokens": 4e-06,
"input_cost_per_character": 1.875e-08,
@ -11744,6 +11745,7 @@
"supports_vision": true
},
"gemini-1.5-flash-exp-0827": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 2e-06,
"input_cost_per_audio_per_second_above_128k_tokens": 4e-06,
"input_cost_per_character": 1.875e-08,
@ -11778,6 +11780,7 @@
"supports_vision": true
},
"gemini-1.5-flash-preview-0514": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 2e-06,
"input_cost_per_audio_per_second_above_128k_tokens": 4e-06,
"input_cost_per_character": 1.875e-08,
@ -11811,6 +11814,7 @@
"supports_vision": true
},
"gemini-1.5-pro": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 3.125e-05,
"input_cost_per_audio_per_second_above_128k_tokens": 6.25e-05,
"input_cost_per_character": 3.125e-07,
@ -11898,6 +11902,7 @@
"supports_vision": true
},
"gemini-1.5-pro-preview-0215": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 3.125e-05,
"input_cost_per_audio_per_second_above_128k_tokens": 6.25e-05,
"input_cost_per_character": 3.125e-07,
@ -11925,6 +11930,7 @@
"supports_tool_choice": true
},
"gemini-1.5-pro-preview-0409": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 3.125e-05,
"input_cost_per_audio_per_second_above_128k_tokens": 6.25e-05,
"input_cost_per_character": 3.125e-07,
@ -11951,6 +11957,7 @@
"supports_tool_choice": true
},
"gemini-1.5-pro-preview-0514": {
"deprecation_date": "2025-09-29",
"input_cost_per_audio_per_second": 3.125e-05,
"input_cost_per_audio_per_second_above_128k_tokens": 6.25e-05,
"input_cost_per_character": 3.125e-07,
@ -12222,6 +12229,7 @@
"tpm": 250000
},
"gemini-2.0-flash-preview-image-generation": {
"deprecation_date": "2025-11-14",
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_audio_token": 7e-07,
"input_cost_per_token": 1e-07,
@ -12260,6 +12268,7 @@
"supports_web_search": true
},
"gemini-2.0-flash-thinking-exp": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 0.0,
"input_cost_per_audio_per_second": 0,
"input_cost_per_audio_per_second_above_128k_tokens": 0,
@ -12308,6 +12317,7 @@
"supports_web_search": true
},
"gemini-2.0-flash-thinking-exp-01-21": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 0.0,
"input_cost_per_audio_per_second": 0,
"input_cost_per_audio_per_second_above_128k_tokens": 0,
@ -12494,6 +12504,7 @@
"tpm": 8000000
},
"gemini-2.5-flash-image-preview": {
"deprecation_date": "2026-01-15",
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_audio_token": 1e-06,
"input_cost_per_token": 3e-07,
@ -12804,6 +12815,7 @@
"tpm": 8000000
},
"gemini-2.5-flash-lite-preview-06-17": {
"deprecation_date": "2025-11-18",
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_audio_token": 5e-07,
"input_cost_per_token": 1e-07,
@ -12893,6 +12905,7 @@
"supports_web_search": true
},
"gemini-2.5-flash-preview-05-20": {
"deprecation_date": "2025-11-18",
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_audio_token": 1e-06,
"input_cost_per_token": 3e-07,
@ -13164,6 +13177,7 @@
"supports_web_search": true
},
"gemini-2.5-pro-preview-03-25": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 3.125e-07,
"input_cost_per_audio_token": 1.25e-06,
"input_cost_per_token": 1.25e-06,
@ -13209,6 +13223,7 @@
"supports_web_search": true
},
"gemini-2.5-pro-preview-05-06": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 3.125e-07,
"input_cost_per_audio_token": 1.25e-06,
"input_cost_per_token": 1.25e-06,
@ -13424,6 +13439,7 @@
"tpm": 10000000
},
"gemini/gemini-1.5-flash": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 7.5e-08,
"input_cost_per_token_above_128k_tokens": 1.5e-07,
"litellm_provider": "gemini",
@ -13507,6 +13523,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-flash-8b": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 0,
"input_cost_per_token_above_128k_tokens": 0,
"litellm_provider": "gemini",
@ -13533,6 +13550,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-flash-8b-exp-0827": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 0,
"input_cost_per_token_above_128k_tokens": 0,
"litellm_provider": "gemini",
@ -13558,6 +13576,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-flash-8b-exp-0924": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 0,
"input_cost_per_token_above_128k_tokens": 0,
"litellm_provider": "gemini",
@ -13584,6 +13603,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-flash-exp-0827": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 0,
"input_cost_per_token_above_128k_tokens": 0,
"litellm_provider": "gemini",
@ -13609,6 +13629,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-flash-latest": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 7.5e-08,
"input_cost_per_token_above_128k_tokens": 1.5e-07,
"litellm_provider": "gemini",
@ -13635,6 +13656,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-pro": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 3.5e-06,
"input_cost_per_token_above_128k_tokens": 7e-06,
"litellm_provider": "gemini",
@ -13696,6 +13718,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-pro-exp-0801": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 3.5e-06,
"input_cost_per_token_above_128k_tokens": 7e-06,
"litellm_provider": "gemini",
@ -13715,6 +13738,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-pro-exp-0827": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 0,
"input_cost_per_token_above_128k_tokens": 0,
"litellm_provider": "gemini",
@ -13734,6 +13758,7 @@
"tpm": 4000000
},
"gemini/gemini-1.5-pro-latest": {
"deprecation_date": "2025-09-29",
"input_cost_per_token": 3.5e-06,
"input_cost_per_token_above_128k_tokens": 7e-06,
"litellm_provider": "gemini",
@ -13916,6 +13941,7 @@
"tpm": 4000000
},
"gemini/gemini-2.0-flash-lite-preview-02-05": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 1.875e-08,
"input_cost_per_audio_token": 7.5e-08,
"input_cost_per_token": 7.5e-08,
@ -13953,6 +13979,7 @@
"tpm": 10000000
},
"gemini/gemini-2.0-flash-live-001": {
"deprecation_date": "2025-12-09",
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_audio_token": 2.1e-06,
"input_cost_per_image": 2.1e-06,
@ -14001,6 +14028,7 @@
"tpm": 250000
},
"gemini/gemini-2.0-flash-preview-image-generation": {
"deprecation_date": "2025-11-14",
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_audio_token": 7e-07,
"input_cost_per_token": 1e-07,
@ -14040,6 +14068,7 @@
"tpm": 10000000
},
"gemini/gemini-2.0-flash-thinking-exp": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 0.0,
"input_cost_per_audio_per_second": 0,
"input_cost_per_audio_per_second_above_128k_tokens": 0,
@ -14089,6 +14118,7 @@
"tpm": 4000000
},
"gemini/gemini-2.0-flash-thinking-exp-01-21": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 0.0,
"input_cost_per_audio_per_second": 0,
"input_cost_per_audio_per_second_above_128k_tokens": 0,
@ -14277,6 +14307,7 @@
"tpm": 8000000
},
"gemini/gemini-2.5-flash-image-preview": {
"deprecation_date": "2026-01-15",
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_audio_token": 1e-06,
"input_cost_per_token": 3e-07,
@ -14597,6 +14628,7 @@
"tpm": 250000
},
"gemini/gemini-2.5-flash-lite-preview-06-17": {
"deprecation_date": "2025-11-18",
"cache_read_input_token_cost": 2.5e-08,
"input_cost_per_audio_token": 5e-07,
"input_cost_per_token": 1e-07,
@ -14688,6 +14720,7 @@
"tpm": 250000
},
"gemini/gemini-2.5-flash-preview-05-20": {
"deprecation_date": "2025-11-18",
"cache_read_input_token_cost": 7.5e-08,
"input_cost_per_audio_token": 1e-06,
"input_cost_per_token": 3e-07,
@ -15034,6 +15067,7 @@
"tpm": 250000
},
"gemini/gemini-2.5-pro-preview-03-25": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 3.125e-07,
"input_cost_per_audio_token": 7e-07,
"input_cost_per_token": 1.25e-06,
@ -15074,6 +15108,7 @@
"tpm": 10000000
},
"gemini/gemini-2.5-pro-preview-05-06": {
"deprecation_date": "2025-12-02",
"cache_read_input_token_cost": 3.125e-07,
"input_cost_per_audio_token": 7e-07,
"input_cost_per_token": 1.25e-06,
@ -15349,6 +15384,7 @@
"source": "https://cloud.google.com/vertex-ai/generative-ai/pricing"
},
"gemini/imagen-3.0-generate-002": {
"deprecation_date": "2025-11-10",
"litellm_provider": "gemini",
"mode": "image_generation",
"output_cost_per_image": 0.04,
@ -15415,6 +15451,7 @@
]
},
"gemini/veo-3.0-fast-generate-preview": {
"deprecation_date": "2025-11-12",
"litellm_provider": "gemini",
"max_input_tokens": 1024,
"max_tokens": 1024,
@ -15429,6 +15466,7 @@
]
},
"gemini/veo-3.0-generate-preview": {
"deprecation_date": "2025-11-12",
"litellm_provider": "gemini",
"max_input_tokens": 1024,
"max_tokens": 1024,
@ -25126,6 +25164,7 @@
"source": "https://docs.mistral.ai/capabilities/code_generation/"
},
"text-embedding-004": {
"deprecation_date": "2026-01-14",
"input_cost_per_character": 2.5e-08,
"input_cost_per_token": 1e-07,
"litellm_provider": "vertex_ai-embedding-models",
@ -27896,6 +27935,7 @@
"source": "https://cloud.google.com/vertex-ai/generative-ai/pricing"
},
"vertex_ai/imagen-3.0-generate-002": {
"deprecation_date": "2025-11-10",
"litellm_provider": "vertex_ai-image-models",
"mode": "image_generation",
"output_cost_per_image": 0.04,
@ -28406,6 +28446,7 @@
]
},
"vertex_ai/veo-3.0-fast-generate-preview": {
"deprecation_date": "2025-11-12",
"litellm_provider": "vertex_ai-video-models",
"max_input_tokens": 1024,
"max_tokens": 1024,
@ -28420,6 +28461,7 @@
]
},
"vertex_ai/veo-3.0-generate-preview": {
"deprecation_date": "2025-11-12",
"litellm_provider": "vertex_ai-video-models",
"max_input_tokens": 1024,
"max_tokens": 1024,

View File

@ -1007,3 +1007,43 @@ def test_multiple_tool_calls_in_single_choice():
assert tool_calls[2]["function"]["name"] == "get_horoscope"
print("✓ Multiple tool calls are correctly grouped in a single choice")
def test_map_reasoning_effort_adds_summary_detailed():
"""
Test that _map_reasoning_effort adds summary="detailed" when user provides reasoning_effort as a string.
This ensures that when users pass reasoning_effort in the completions API for OpenAI responses/models,
the transformation automatically includes summary="detailed" in the reasoning parameter.
"""
from litellm.completion_extras.litellm_responses_transformation.transformation import (
LiteLLMResponsesTransformationHandler,
)
handler = LiteLLMResponsesTransformationHandler()
# Test all string effort levels
effort_levels = ["none", "low", "medium", "high", "xhigh", "minimal"]
for effort in effort_levels:
result = handler._map_reasoning_effort(effort)
assert result is not None, f"Result should not be None for effort={effort}"
assert result["effort"] == effort, f"Effort should be {effort}"
assert result["summary"] == "concise", f"Summary should be 'detailed' for effort={effort}"
print(f"✓ reasoning_effort='{effort}' correctly maps to effort='{effort}', summary='detailed'")
# Test that dict input is passed through as-is (no modification)
dict_input = {"effort": "high", "summary": "custom_summary"}
result_dict = handler._map_reasoning_effort(dict_input)
assert result_dict["effort"] == "high"
assert result_dict["summary"] == "custom_summary"
print("✓ Dict input is passed through without modification")
# Test that None/unknown values return None
result_unknown = handler._map_reasoning_effort("unknown_value")
assert result_unknown is None
print("✓ Unknown reasoning_effort values return None")
print("✓ All reasoning_effort string values correctly map to summary='detailed'")