feat(ui): report whether the serving proxy has applied the interception setting

The stored flag is the cluster's desired state and is what the form saves, so it
cannot also stand as proof that this process activated the callback: a pod that
lagged or failed to apply it would still read as on. Report the process's own
registration as a separate read-only field and warn on the page when the two
disagree, so a failed activation is visible instead of only logged.
This commit is contained in:
Yuneng Jiang 2026-09-19 16:00:11 -07:00
parent 4ea21cb75c
commit c0bc45224c
No known key found for this signature in database
5 changed files with 100 additions and 2 deletions

View file

@ -506,6 +506,16 @@ class WebSearchInterceptionSettings(BaseModel):
class WebSearchInterceptionSettingsResponse(SettingsResponse):
"""Response model for web search interception settings"""
active_on_this_pod: bool = Field(
default=False,
description=(
"Whether the process answering this request has the interception callback "
"registered. Read-only: it reports what is running here, while values.enabled "
"is the cluster-wide setting, and the two disagree while a pod is still "
"applying a change or failed to apply it."
),
)
def _with_websearch_enabled_resolved(config: Mapping[str, object]) -> dict[str, object]:
"""
@ -1496,11 +1506,22 @@ async def get_websearch_interception_settings(
config: Final = await proxy_config.get_config()
return await _get_settings_with_schema(
from litellm.integrations.websearch_interception.handler import (
WebSearchInterceptionLogger,
)
settings: Final = await _get_settings_with_schema(
settings_key="websearch_interception_params",
settings_class=WebSearchInterceptionSettings,
config=_with_websearch_enabled_resolved(config),
)
return WebSearchInterceptionSettingsResponse(
values=settings["values"],
field_schema=settings["field_schema"],
active_on_this_pod=bool(
litellm.logging_callback_manager.get_custom_loggers_for_type(WebSearchInterceptionLogger)
),
)
@router.patch(

View file

@ -3263,6 +3263,38 @@ class TestWebSearchInterceptionSettingsEndpoints:
assert resp.status_code == 200, resp.text
assert resp.json()["values"]["enabled"] is True
def test_get_flags_a_pod_that_has_not_applied_the_stored_setting(
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}
resp = client.get("/get/websearch_interception_settings")
assert resp.status_code == 200, resp.text
assert resp.json()["values"]["enabled"] is True
assert resp.json()["active_on_this_pod"] is False
def test_get_reports_the_pod_as_active_once_the_callback_is_registered(
self, mock_proxy_config, mock_auth, monkeypatch
):
import litellm
from litellm.integrations.websearch_interception.handler import (
WebSearchInterceptionLogger,
)
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", object())
monkeypatch.setattr(litellm, "callbacks", [WebSearchInterceptionLogger(search_tool_name="running")])
mock_proxy_config["config"]["litellm_settings"]["websearch_interception_params"] = {"enabled": True}
resp = client.get("/get/websearch_interception_settings")
assert resp.status_code == 200, resp.text
assert resp.json()["active_on_this_pod"] 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)

View file

@ -127,6 +127,32 @@ describe("WebSearchInterceptionSettings", () => {
expect(mockMutate.mock.calls[0][0]).toEqual(ENABLED_PAYLOAD);
});
it("warns when the cluster has it on but the serving pod has not applied it", async () => {
vi.mocked(useWebSearchInterceptionSettings).mockReturnValue({
data: { ...storedSettings, values: { ...storedSettings.values, enabled: true }, active_on_this_pod: false },
isLoading: false,
isError: false,
error: null,
} as any);
await renderSettings();
expect(screen.getByText(/has not applied it/i)).toBeInTheDocument();
});
it("stays quiet when the serving pod has applied the cluster setting", async () => {
vi.mocked(useWebSearchInterceptionSettings).mockReturnValue({
data: { ...storedSettings, values: { ...storedSettings.values, enabled: true }, active_on_this_pod: true },
isLoading: false,
isError: false,
error: null,
} as any);
await renderSettings();
expect(screen.queryByText(/has not applied it/i)).not.toBeInTheDocument();
});
it("ignores stored values whose types do not match the field", async () => {
vi.mocked(useWebSearchInterceptionSettings).mockReturnValue({
data: {

View file

@ -5,7 +5,7 @@ import { useUpdateWebSearchInterceptionSettings } from "@/app/(dashboard)/hooks/
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
import { toast } from "@/lib/toast";
import { Skeleton } from "@/components/ui/skeleton";
import { CircleHelp, Info, Save } from "lucide-react";
import { CircleHelp, Info, Save, TriangleAlert } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/shared/Alert";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
@ -293,9 +293,22 @@ export default function WebSearchInterceptionSettings() {
}
const values: WebSearchInterceptionStoredValues = toStoredValues(data?.values ?? NO_STORED_VALUES);
const notAppliedHere = values.enabled === true && data?.active_on_this_pod === false;
return (
<div className="w-full">
{notAppliedHere && (
<Alert variant="warning" className="mb-6">
<TriangleAlert />
<AlertTitle>Not running on the proxy that answered this page</AlertTitle>
<AlertDescription>
Interception is switched on for the cluster, but the proxy serving this page has not applied it. That is
expected for about 10 seconds after a change or a restart. If it persists, check that proxy&apos;s logs:
requests it handles are not being intercepted.
</AlertDescription>
</Alert>
)}
<Alert variant="info" className="mb-6">
<Info />
<AlertTitle>Web Search Interception</AlertTitle>

View file

@ -41232,6 +41232,12 @@ export interface components {
* @description Response model for web search interception settings
*/
WebSearchInterceptionSettingsResponse: {
/**
* Active On This Pod
* @description Whether the process answering this request has the interception callback registered. Read-only: it reports what is running here, while values.enabled is the cluster-wide setting, and the two disagree while a pod is still applying a change or failed to apply it.
* @default false
*/
active_on_this_pod: boolean;
/** Field Schema */
field_schema: {
[key: string]: unknown;