@@ -115,6 +115,7 @@ async def fake_acompletion(model, messages=None, **kwargs):
115115 previous_response_id = None ,
116116 )
117117
118+ # reasoning_effort is string when no summary is provided (backward compatible)
118119 assert captured ["reasoning_effort" ] == "low"
119120 assert settings .extra_body == {"reasoning_effort" : "high" }
120121
@@ -155,3 +156,46 @@ async def fake_acompletion(model, messages=None, **kwargs):
155156 assert captured ["reasoning_effort" ] == "none"
156157 assert captured ["custom_param" ] == "custom"
157158 assert settings .extra_args == {"reasoning_effort" : "low" , "custom_param" : "custom" }
159+
160+
161+ @pytest .mark .allow_call_model_methods
162+ @pytest .mark .asyncio
163+ async def test_reasoning_summary_is_preserved (monkeypatch ):
164+ """
165+ Ensure reasoning.summary is preserved when passing ModelSettings.reasoning.
166+
167+ This test verifies the fix for GitHub issue:
168+ https://github.com/BerriAI/litellm/issues/17428
169+
170+ Previously, only reasoning.effort was extracted, losing the summary field.
171+ Now we pass a dict with both effort and summary to LiteLLM.
172+ """
173+ from openai .types .shared import Reasoning
174+
175+ captured : dict [str , object ] = {}
176+
177+ async def fake_acompletion (model , messages = None , ** kwargs ):
178+ captured .update (kwargs )
179+ msg = Message (role = "assistant" , content = "ok" )
180+ choice = Choices (index = 0 , message = msg )
181+ return ModelResponse (choices = [choice ], usage = Usage (0 , 0 , 0 ))
182+
183+ monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
184+ settings = ModelSettings (
185+ reasoning = Reasoning (effort = "medium" , summary = "auto" ),
186+ )
187+ model = LitellmModel (model = "test-model" )
188+
189+ await model .get_response (
190+ system_instructions = None ,
191+ input = [],
192+ model_settings = settings ,
193+ tools = [],
194+ output_schema = None ,
195+ handoffs = [],
196+ tracing = ModelTracing .DISABLED ,
197+ previous_response_id = None ,
198+ )
199+
200+ # Both effort and summary should be preserved in the dict
201+ assert captured ["reasoning_effort" ] == {"effort" : "medium" , "summary" : "auto" }
0 commit comments