diff --git a/litellm/litellm_core_utils/completion_timeout.py b/litellm/litellm_core_utils/completion_timeout.py index e1ece9170e2..73451fb3f86 100644 --- a/litellm/litellm_core_utils/completion_timeout.py +++ b/litellm/litellm_core_utils/completion_timeout.py @@ -26,9 +26,13 @@ class CompletionTimeout: ``kwargs["timeout"]``, ``kwargs["request_timeout"]``, then ``global_timeout`` (e.g. :attr:`litellm.request_timeout` from proxy ``litellm_settings``), else ``600``. - Coerce :class:`httpx.Timeout` when the provider does not support it; map ``6000`` - (:data:`~litellm.constants.DEFAULT_REQUEST_TIMEOUT_SECONDS`) to ``600`` for completion. + Coerce :class:`httpx.Timeout` when the provider does not support it. If the value + came only from ``global_timeout`` (no model/kwargs timeout) and equals ``6000`` + (:data:`~litellm.constants.DEFAULT_REQUEST_TIMEOUT_SECONDS`), use ``600`` for + completion so chat calls do not inherit the long package default; explicit + ``model_timeout`` / kwargs values of ``6000`` are left unchanged. """ + timeout_from_global_only = False if model_timeout is not None: resolved: Union[float, str, httpx.Timeout] = model_timeout elif kwargs.get("timeout") is not None: @@ -37,6 +41,7 @@ class CompletionTimeout: resolved = kwargs["request_timeout"] else: resolved = global_timeout if global_timeout is not None else 600 + timeout_from_global_only = True if isinstance(resolved, httpx.Timeout) and not supports_httpx_timeout( custom_llm_provider @@ -48,8 +53,10 @@ class CompletionTimeout: elif not isinstance(resolved, httpx.Timeout): resolved = float(resolved) # type: ignore - if not isinstance(resolved, httpx.Timeout) and float(resolved) == float( - DEFAULT_REQUEST_TIMEOUT_SECONDS + if ( + timeout_from_global_only + and not isinstance(resolved, httpx.Timeout) + and float(resolved) == float(DEFAULT_REQUEST_TIMEOUT_SECONDS) ): resolved = 600.0 diff --git a/tests/test_litellm/test_completion_timeout_resolution.py b/tests/test_litellm/test_completion_timeout_resolution.py index f2955852afe..b1ec32e6239 100644 --- a/tests/test_litellm/test_completion_timeout_resolution.py +++ b/tests/test_litellm/test_completion_timeout_resolution.py @@ -79,8 +79,8 @@ def test_global_timeout_package_default_coerced_to_600_for_completion(): ) -def test_explicit_request_timeout_6000_normalized_to_completion_default(): - """6000 is the package sentinel; completion always uses 600 instead.""" +def test_explicit_request_timeout_6000_preserved(): + """Explicit deployment/request timeout must not be truncated by the package sentinel.""" assert ( CompletionTimeout.resolve( None, @@ -89,7 +89,20 @@ def test_explicit_request_timeout_6000_normalized_to_completion_default(): global_timeout=None, supports_httpx_timeout=supports_httpx_timeout, ) - == 600.0 + == 6000.0 + ) + + +def test_explicit_model_timeout_6000_preserved(): + assert ( + CompletionTimeout.resolve( + 6000.0, + {"timeout": 1.0, "request_timeout": 2.0}, + "openai", + global_timeout=None, + supports_httpx_timeout=supports_httpx_timeout, + ) + == 6000.0 )