From 3d4c3021856022562cbf1ca64f3ddf25f685173f Mon Sep 17 00:00:00 2001 From: Alessandro <155005371+3clyp50@users.noreply.github.com> Date: Fri, 12 Jun 2026 03:27:49 +0200 Subject: [PATCH] Solidify LiteLLM global kwargs handling Limit LiteLLM module mutation to documented global switches such as drop_params, while preserving configured LiteLLM kwargs as per-call options. Avoid freezing global kwargs into provider defaults so runtime settings remain current, and extend focused tests for drop_params, additional_drop_params, and provider default behavior. --- AGENTS.md | 2 +- models.py | 13 ++++--- tests/test_stream_tool_early_stop.py | 57 +++++++++++++++++++++++++++- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 47736dbb4..a3738d8ee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -100,7 +100,7 @@ Key Files: - helpers/plugins.py: Plugin discovery and configuration logic. - webui/js/AlpineStore.js: Store factory for reactive frontend state. - helpers/api.py: Base class for all API endpoints. -- models.py: LLM provider configuration and LiteLLM wrappers; framework LiteLLM defaults such as `drop_params=True` are merged with `litellm_global_kwargs`, configured values override framework defaults, and the merged kwargs are applied at LiteLLM module and per-call boundaries. +- models.py: LLM provider configuration and LiteLLM wrappers; framework LiteLLM defaults such as `drop_params=True` are merged with `litellm_global_kwargs`, configured values override framework defaults, documented module-level switches such as `drop_params` are applied to LiteLLM, and merged kwargs are passed per call. - scripts/openrouter_release_notes_system_prompt.md: Editable system prompt used to generate GitHub release notes during Docker publishing. - knowledge/main/about/: Agent self-knowledge files, indexed into the vector DB for runtime recall. Not user-facing docs - written for the agent's internal reference. - webui/components/AGENTS.md: DOX contract for Alpine component architecture. diff --git a/models.py b/models.py index b81333a0a..811fa31e0 100644 --- a/models.py +++ b/models.py @@ -49,6 +49,11 @@ DEFAULT_LITELLM_GLOBAL_KWARGS: dict[str, Any] = { "drop_params": True, } +# LiteLLM documents drop_params as both a module-level switch and per-call kwarg. +# Other entries in litellm_global_kwargs, such as timeout or additional_drop_params, +# are kept as per-call kwargs instead of becoming arbitrary module attributes. +LITELLM_MODULE_GLOBAL_KEYS = frozenset({"drop_params"}) + def _normalize_litellm_kwargs(values: dict[str, Any]) -> dict[str, Any]: # Normalize .env/UI-style scalar strings into native types for LiteLLM. @@ -100,6 +105,8 @@ def turn_off_logging(): def set_litellm_params(): global_kwargs = get_litellm_global_kwargs() for key, value in global_kwargs.items(): + if key not in LITELLM_MODULE_GLOBAL_KEYS: + continue setattr(litellm, key, value) return global_kwargs @@ -959,12 +966,6 @@ def _merge_provider_defaults( if key and key not in ("None", "NA"): kwargs["api_key"] = key - # Merge LiteLLM global kwargs. Framework defaults are merged first, then - # configured global kwargs override those defaults; explicit provider/model - # kwargs still keep priority via setdefault. - for k, v in get_litellm_global_kwargs().items(): - kwargs.setdefault(k, v) - return provider_name, kwargs diff --git a/tests/test_stream_tool_early_stop.py b/tests/test_stream_tool_early_stop.py index 8aa7de661..a1d0ac63e 100644 --- a/tests/test_stream_tool_early_stop.py +++ b/tests/test_stream_tool_early_stop.py @@ -94,30 +94,83 @@ def test_litellm_global_kwargs_merge_defaults_and_config(monkeypatch): monkeypatch.setattr( models.settings, "get_settings", - lambda: {"litellm_global_kwargs": {"drop_params": "false", "timeout": "30"}}, + lambda: { + "litellm_global_kwargs": { + "drop_params": "false", + "timeout": "30", + "additional_drop_params": ["response_format"], + } + }, ) assert models._merge_litellm_call_kwargs({}) == { "drop_params": False, "timeout": 30, + "additional_drop_params": ["response_format"], } original_drop_params = getattr(models.litellm, "drop_params", None) had_timeout = hasattr(models.litellm, "timeout") original_timeout = getattr(models.litellm, "timeout", None) + had_additional_drop_params = hasattr(models.litellm, "additional_drop_params") + original_additional_drop_params = getattr( + models.litellm, "additional_drop_params", None + ) try: assert models.set_litellm_params() == { "drop_params": False, "timeout": 30, + "additional_drop_params": ["response_format"], } assert models.litellm.drop_params is False - assert models.litellm.timeout == 30 + if had_timeout: + assert models.litellm.timeout == original_timeout + else: + assert not hasattr(models.litellm, "timeout") + if had_additional_drop_params: + assert ( + models.litellm.additional_drop_params + == original_additional_drop_params + ) + else: + assert not hasattr(models.litellm, "additional_drop_params") finally: setattr(models.litellm, "drop_params", original_drop_params) if had_timeout: setattr(models.litellm, "timeout", original_timeout) elif hasattr(models.litellm, "timeout"): delattr(models.litellm, "timeout") + if had_additional_drop_params: + setattr( + models.litellm, + "additional_drop_params", + original_additional_drop_params, + ) + elif hasattr(models.litellm, "additional_drop_params"): + delattr(models.litellm, "additional_drop_params") + + +def test_provider_defaults_do_not_freeze_litellm_global_kwargs(monkeypatch): + monkeypatch.setattr(models, "get_provider_config", lambda *args, **kwargs: None) + monkeypatch.setattr(models, "get_api_key", lambda *_args, **_kwargs: None) + monkeypatch.setattr( + models.settings, + "get_settings", + lambda: {"litellm_global_kwargs": {"drop_params": "true"}}, + ) + + _, provider_kwargs = models._merge_provider_defaults("chat", "openai", {}) + + assert "drop_params" not in provider_kwargs + assert models._merge_litellm_call_kwargs(provider_kwargs)["drop_params"] is True + + monkeypatch.setattr( + models.settings, + "get_settings", + lambda: {"litellm_global_kwargs": {"drop_params": "false"}}, + ) + + assert models._merge_litellm_call_kwargs(provider_kwargs)["drop_params"] is False @pytest.mark.asyncio