Solidify LiteLLM global kwargs handling
Some checks are pending
Build And Publish Docker Images / plan (push) Waiting to run
Build And Publish Docker Images / build (push) Blocked by required conditions

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.
This commit is contained in:
Alessandro 2026-06-12 03:27:49 +02:00
parent b8c390f50d
commit 3d4c302185
3 changed files with 63 additions and 9 deletions

View file

@ -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.

View file

@ -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

View file

@ -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