@@ -159,6 +159,45 @@ def get_retry_advice(self, request: ModelRetryAdviceRequest) -> ModelRetryAdvice
159159 # Reuse the same normalization to expose retry-after and explicit retry/no-retry hints.
160160 return get_openai_retry_advice (request )
161161
162+ def _get_reasoning_effort (self , model_settings : ModelSettings ) -> Any | None :
163+ """
164+ Resolve the top-level LiteLLM reasoning_effort argument for the chat-completions path.
165+
166+ LiteLLM's public acompletion() surface accepts a scalar reasoning_effort value. Keep the
167+ ModelSettings.reasoning path aligned with that contract and leave extra_body / extra_args as
168+ the explicit escape hatches for advanced provider-specific overrides.
169+ """
170+ reasoning_effort : Any | None = None
171+
172+ if model_settings .reasoning :
173+ reasoning_effort = model_settings .reasoning .effort
174+ if model_settings .reasoning .summary is not None :
175+ logger .warning (
176+ "LitellmModel does not forward Reasoning.summary on the LiteLLM "
177+ "chat-completions path; ignoring summary and passing reasoning_effort only."
178+ )
179+
180+ # Enable developers to pass non-OpenAI compatible reasoning_effort data like "none".
181+ # Priority order:
182+ # 1. model_settings.reasoning.effort
183+ # 2. model_settings.extra_body["reasoning_effort"]
184+ # 3. model_settings.extra_args["reasoning_effort"]
185+ if (
186+ reasoning_effort is None
187+ and isinstance (model_settings .extra_body , dict )
188+ and "reasoning_effort" in model_settings .extra_body
189+ ):
190+ reasoning_effort = model_settings .extra_body ["reasoning_effort" ]
191+
192+ if (
193+ reasoning_effort is None
194+ and model_settings .extra_args
195+ and "reasoning_effort" in model_settings .extra_args
196+ ):
197+ reasoning_effort = model_settings .extra_args ["reasoning_effort" ]
198+
199+ return reasoning_effort
200+
162201 async def get_response (
163202 self ,
164203 system_instructions : str | None ,
@@ -456,37 +495,7 @@ async def _fetch_response(
456495 f"Response format: { response_format } \n "
457496 )
458497
459- # Build reasoning_effort - use dict only when summary is present (OpenAI feature)
460- # Otherwise pass string for backward compatibility with all providers
461- reasoning_effort : dict [str , Any ] | str | None = None
462- if model_settings .reasoning :
463- if model_settings .reasoning .summary is not None :
464- # Dict format when summary is needed (OpenAI only)
465- reasoning_effort = {
466- "effort" : model_settings .reasoning .effort ,
467- "summary" : model_settings .reasoning .summary ,
468- }
469- elif model_settings .reasoning .effort is not None :
470- # String format for compatibility with all providers
471- reasoning_effort = model_settings .reasoning .effort
472-
473- # Enable developers to pass non-OpenAI compatible reasoning_effort data like "none"
474- # Priority order:
475- # 1. model_settings.reasoning (effort + summary)
476- # 2. model_settings.extra_body["reasoning_effort"]
477- # 3. model_settings.extra_args["reasoning_effort"]
478- if (
479- reasoning_effort is None # Unset in model_settings
480- and isinstance (model_settings .extra_body , dict )
481- and "reasoning_effort" in model_settings .extra_body
482- ):
483- reasoning_effort = model_settings .extra_body ["reasoning_effort" ]
484- if (
485- reasoning_effort is None # Unset in both model_settings and model_settings.extra_body
486- and model_settings .extra_args
487- and "reasoning_effort" in model_settings .extra_args
488- ):
489- reasoning_effort = model_settings .extra_args ["reasoning_effort" ]
498+ reasoning_effort = self ._get_reasoning_effort (model_settings )
490499
491500 stream_options = None
492501 if stream and model_settings .include_usage is not None :
0 commit comments