diff --git a/litellm/litellm_core_utils/model_param_helper.py b/litellm/litellm_core_utils/model_param_helper.py index b4fa5cb60aa..855e52098c4 100644 --- a/litellm/litellm_core_utils/model_param_helper.py +++ b/litellm/litellm_core_utils/model_param_helper.py @@ -1,3 +1,4 @@ +from functools import lru_cache from typing import Set from openai.types.chat.completion_create_params import ( @@ -54,9 +55,17 @@ class ModelParamHelper: return combined_kwargs @staticmethod + @lru_cache(maxsize=1) def _get_all_llm_api_params() -> Set[str]: """ - Gets the supported kwargs for each call type and combines them + Gets the supported kwargs for each call type and combines them. + + The result is derived from static type annotations and fixed sets, so it + is constant for the process lifetime. It is computed once and cached + because it is rebuilt on every request through both the cache-key path + (``Cache.get_cache_key``) and the spend-logging path + (``_get_relevant_args_to_use_for_logging``). Callers treat the result as + read-only. """ chat_completion_kwargs = ( ModelParamHelper._get_litellm_supported_chat_completion_kwargs() diff --git a/tests/test_litellm/litellm_core_utils/test_model_param_helper.py b/tests/test_litellm/litellm_core_utils/test_model_param_helper.py new file mode 100644 index 00000000000..df01bd636b8 --- /dev/null +++ b/tests/test_litellm/litellm_core_utils/test_model_param_helper.py @@ -0,0 +1,26 @@ +import os +import sys + +sys.path.insert( + 0, os.path.abspath("../../..") +) # Adds the parent directory to the system path + +from litellm.litellm_core_utils.model_param_helper import ModelParamHelper + + +def test_get_all_llm_api_params_is_correct(): + """The cached result must equal a fresh, uncached computation.""" + cached = ModelParamHelper._get_all_llm_api_params() + uncached = ModelParamHelper._get_all_llm_api_params.__wrapped__() + assert cached == uncached + assert {"model", "temperature", "stream"} <= cached + assert "metadata" not in cached # excluded via _get_exclude_kwargs + + +def test_get_all_llm_api_params_is_memoized(): + """Regression: the param set is static and is rebuilt on every request via + the cache-key and spend-logging paths, so it must be memoized. Without the + cache each call returns a freshly built set (a different object).""" + first = ModelParamHelper._get_all_llm_api_params() + second = ModelParamHelper._get_all_llm_api_params() + assert first is second