diff --git a/surfsense_backend/app/services/model_resolver.py b/surfsense_backend/app/services/model_resolver.py index f31b658a4..590290b0c 100644 --- a/surfsense_backend/app/services/model_resolver.py +++ b/surfsense_backend/app/services/model_resolver.py @@ -59,6 +59,10 @@ def to_litellm( kwargs: dict[str, Any] = {} if api_key: kwargs["api_key"] = api_key + elif provider == "lm_studio": + # LiteLLM's OpenAI-compatible adapter expects an api_key value even + # when LM Studio accepts unauthenticated local requests. + kwargs["api_key"] = "not-needed" prefix = spec.litellm_prefix or str(provider) model_string = f"{prefix}/{model_id}" if prefix else model_id diff --git a/surfsense_backend/tests/unit/services/test_model_connections.py b/surfsense_backend/tests/unit/services/test_model_connections.py index b4e7c18d7..efc056465 100644 --- a/surfsense_backend/tests/unit/services/test_model_connections.py +++ b/surfsense_backend/tests/unit/services/test_model_connections.py @@ -64,6 +64,22 @@ def test_openai_compatible_resolver_uses_explicit_api_base() -> None: assert ensure_v1("http://example.com/v1") == "http://example.com/v1" +def test_lm_studio_resolver_supplies_dummy_api_key_when_empty() -> None: + model, kwargs = to_litellm( + { + "provider": "lm_studio", + "base_url": "http://host.docker.internal:1234/v1", + "api_key": None, + "extra": {}, + }, + "tinyllama-1.1b-chat-v0.6", + ) + + assert model == "openai/tinyllama-1.1b-chat-v0.6" + assert kwargs["api_base"] == "http://host.docker.internal:1234/v1" + assert kwargs["api_key"] == "not-needed" + + def test_ollama_resolver_uses_native_api_base() -> None: model, kwargs = to_litellm( {