From 4ea21cb75cf9105a0c0ef8403b21a5dcc2395970 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 19 Sep 2026 15:42:16 -0700 Subject: [PATCH] fix(ui): answer the interception panel from the stored flag, not the local pod Deriving enabled from whether this process has the callback registered makes a pod that has not polled yet report off while the cluster runs it, and the next save writes that off back for every pod. The stored flag is the cluster's own answer, so prefer it and fall back to local registration only when none is stored, which is the config-activated case that has no flag to read. --- .../proxy_setting_endpoints.py | 19 ++++++++++----- .../test_proxy_setting_endpoints.py | 23 +++++++++++++++++-- 2 files changed, 34 insertions(+), 8 deletions(-) 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)