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.
This commit is contained in:
Yuneng Jiang 2026-09-19 15:42:16 -07:00
parent e7fd89fc02
commit 4ea21cb75c
No known key found for this signature in database
2 changed files with 34 additions and 8 deletions

View file

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

View file

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