diff --git a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py index a86b7732bcf..a972f08b8bf 100644 --- a/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py +++ b/litellm/proxy/ui_crud_endpoints/proxy_setting_endpoints.py @@ -509,13 +509,17 @@ class WebSearchInterceptionSettingsResponse(SettingsResponse): def _with_websearch_enabled_resolved(config: Mapping[str, object]) -> dict[str, object]: """ - Report whether interception is actually running, rather than what a stored flag claims. + Answer with the stored flag when there is one, and only otherwise with what + this process is running. - A proxy can activate it through litellm_settings.callbacks, which stores no - flag at all, and a write through the generic config endpoint can drop the - flag from a block that is still live. Either way the field's own default - would tell an admin the feature is off while it is serving, and saving the - page would then persist that answer. + A stored flag is the cluster's own answer, so it is the same on every pod and + is safe for the page to send back on save. Deriving the answer from this + process instead would report off on a pod that has not polled yet, and the + next save would persist that as a cluster-wide off. Without a stored flag the + only available answer is local: litellm_settings.callbacks activates + interception without storing one, and a write through the generic config + endpoint can drop the flag from a block that is still live. Reporting the + field default there would claim the feature is off while it serves. """ from litellm.integrations.websearch_interception.handler import ( WebSearchInterceptionLogger, @@ -523,6 +527,9 @@ def _with_websearch_enabled_resolved(config: Mapping[str, object]) -> dict[str, litellm_settings: Final[Mapping[str, object]] = _as_settings_section(config.get("litellm_settings")) stored: Final[Mapping[str, object]] = _as_settings_section(litellm_settings.get("websearch_interception_params")) + if "enabled" in stored: + return dict(config) + resolved: Final = { **stored, "enabled": bool(litellm.logging_callback_manager.get_custom_loggers_for_type(WebSearchInterceptionLogger)), diff --git a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py index 102b0657461..9af559e3660 100644 --- a/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py +++ b/tests/test_litellm/proxy/ui_crud_endpoints/test_proxy_setting_endpoints.py @@ -3210,13 +3210,14 @@ class TestWebSearchInterceptionSettingsEndpoints: assert resp.status_code == 200, resp.text assert resp.json()["values"]["enabled"] is True - def test_get_reports_disabled_when_the_callback_is_not_running(self, mock_proxy_config, mock_auth, monkeypatch): + def test_get_reports_disabled_when_nothing_is_stored_and_nothing_is_running( + self, mock_proxy_config, mock_auth, monkeypatch + ): import litellm monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", object()) monkeypatch.setattr(litellm, "callbacks", []) mock_proxy_config["config"]["litellm_settings"]["websearch_interception_params"] = { - "enabled": True, "enabled_providers": ["bedrock"], } @@ -3224,6 +3225,7 @@ class TestWebSearchInterceptionSettingsEndpoints: assert resp.status_code == 200, resp.text assert resp.json()["values"]["enabled"] is False + assert resp.json()["values"]["enabled_providers"] == ["bedrock"] def test_update_reapplies_settings_to_the_running_proxy(self, mock_proxy_config, monkeypatch): from unittest.mock import AsyncMock @@ -3244,6 +3246,23 @@ class TestWebSearchInterceptionSettingsEndpoints: assert resp.status_code == 200, resp.text reapply.assert_awaited_once() + def test_get_keeps_the_stored_flag_when_this_pod_has_not_reinitialized( + self, mock_proxy_config, mock_auth, monkeypatch + ): + import litellm + + monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", object()) + monkeypatch.setattr(litellm, "callbacks", []) + mock_proxy_config["config"]["litellm_settings"]["websearch_interception_params"] = { + "enabled": True, + "search_tool_name": "cluster-search", + } + + resp = client.get("/get/websearch_interception_settings") + + assert resp.status_code == 200, resp.text + assert resp.json()["values"]["enabled"] is True + def test_get_reports_no_database_instead_of_empty_settings(self, mock_proxy_config, mock_auth, monkeypatch): monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", None)