diff --git a/litellm/proxy/alerting_endpoints/model_deprecation_alerts.py b/litellm/proxy/alerting_endpoints/model_deprecation_alerts.py index f0a057c4be2..1b13372ec68 100644 --- a/litellm/proxy/alerting_endpoints/model_deprecation_alerts.py +++ b/litellm/proxy/alerting_endpoints/model_deprecation_alerts.py @@ -39,7 +39,7 @@ def _require_admin(user: UserAPIKeyAuth, *, write: bool) -> None: raise HTTPException(status_code=403, detail="Only gateway admins can manage model deprecation alerts") -@router.get("/alerting/model-deprecations/state", tags=["alerting"], response_model=DeprecationAlertState) +@router.get("/alerts/model-deprecations/state", tags=["alerts"], response_model=DeprecationAlertState) async def get_deprecation_alert_state( model: Annotated[str, Query(min_length=1, max_length=1024)], deprecation_date: date, @@ -53,7 +53,7 @@ async def get_deprecation_alert_state( return DeprecationAlertState.model_validate(record.param_value) -@router.put("/alerting/model-deprecations/state", tags=["alerting"], response_model=DeprecationAlertState) +@router.put("/alerts/model-deprecations/state", tags=["alerts"], response_model=DeprecationAlertState) async def update_deprecation_alert_state( data: DeprecationAlertUpdate, user: Annotated[UserAPIKeyAuth, Depends(user_api_key_auth)], @@ -69,7 +69,7 @@ async def update_deprecation_alert_state( return state -@router.get("/alerting/model-deprecations/tags", tags=["alerting"], response_model=tuple[DeprecationTagUsage, ...]) +@router.get("/alerts/model-deprecations/tags", tags=["alerts"], response_model=tuple[DeprecationTagUsage, ...]) async def get_deprecation_usage_tags( model: Annotated[str, Query(min_length=1, max_length=1024)], api_keys: Annotated[tuple[str, ...], Query(min_length=1, max_length=100)], diff --git a/litellm/types/proxy/issues.py b/litellm/types/proxy/issues.py index 42c4ff223ac..4fe4db81e3c 100644 --- a/litellm/types/proxy/issues.py +++ b/litellm/types/proxy/issues.py @@ -126,9 +126,9 @@ class AlertInput(BaseModel, frozen=True): if self.range_start > self.range_end: raise ValueError("range_start must not follow range_end") if (self.kind == "model_deprecation") != (self.deprecation is not None): - raise ValueError("Model deprecation issues require deprecation details") + raise ValueError("Model deprecation alerts require deprecation details") if (self.kind == "model_deprecation") != (self.family == "retirement"): - raise ValueError("Only model deprecation issues use the retirement family") + raise ValueError("Only model deprecation alerts use the retirement family") if self.observed_at.tzinfo is None: raise ValueError("observed_at must include a timezone") return self @@ -142,7 +142,7 @@ class Alert(AlertInput, frozen=True): scope_label: str | None = None active: bool = True can_update_status: bool | None = Field( - default=None, description="Current reader's status permission, evaluated by the issue-detail endpoint" + default=None, description="Current reader's status permission, evaluated by the alert detail endpoint" ) can_view_activity: bool | None = Field( default=None, description="Current reader's permission to inspect Activity, keys, users and impact" diff --git a/tests/unit/proxy/management_endpoints/test_model_deprecation_alerts.py b/tests/unit/proxy/management_endpoints/test_model_deprecation_alerts.py index 434dcc7a83c..3408ba890cb 100644 --- a/tests/unit/proxy/management_endpoints/test_model_deprecation_alerts.py +++ b/tests/unit/proxy/management_endpoints/test_model_deprecation_alerts.py @@ -38,7 +38,7 @@ def client() -> Iterator[tuple[TestClient, UserAPIKeyAuth]]: IDENTITY = {"model": "anthropic/claude-sonnet-4-5", "deprecation_date": "2026-11-30"} UPDATE = {**IDENTITY, "status": "resolved", "last_seen_date": "2026-11-04", "last_seen_requests": 123} -PATH = "/alerting/model-deprecations/state" +PATH = "/alerts/model-deprecations/state" def test_new_alert_is_open(client: tuple[TestClient, UserAPIKeyAuth]) -> None: @@ -109,7 +109,7 @@ def test_tags_are_scoped_to_model_dates_and_the_visible_keys(client: tuple[TestC table=SimpleNamespace(group_by=grouped) ) response = http.get( - "/alerting/model-deprecations/tags", + "/alerts/model-deprecations/tags", params={ "model": "openai/gpt-4-turbo", "api_keys": ["reporting-one", "reporting-two"], @@ -146,7 +146,7 @@ def test_tag_access_matches_alert_visibility( table=SimpleNamespace(group_by=grouped) ) response = http.get( - "/alerting/model-deprecations/tags", + "/alerts/model-deprecations/tags", params={"model": "test-model", "api_keys": ["one"], "start_date": "2026-10-06", "end_date": "2026-11-04"}, ) assert response.status_code == expected @@ -168,7 +168,7 @@ def test_tag_query_rejects_more_than_100_keys_before_database_access(client: tup table=SimpleNamespace(group_by=grouped) ) response = http.get( - "/alerting/model-deprecations/tags", + "/alerts/model-deprecations/tags", params={ "model": "test-model", "api_keys": [f"reporting-{index}" for index in range(101)], diff --git a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/MigrationDetail.tsx b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/MigrationDetail.tsx index 80984a36805..80967695311 100644 --- a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/MigrationDetail.tsx +++ b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/MigrationDetail.tsx @@ -100,7 +100,7 @@ export default function MigrationDetail({ queryKey: ["deprecationUsageTags", scope, model, range, keys], enabled: keys.length > 0, queryFn: async ({ signal }: { signal: AbortSignal }) => { - const { data } = await backgroundFetchClient.GET("/alerting/model-deprecations/tags", { + const { data } = await backgroundFetchClient.GET("/alerts/model-deprecations/tags", { params: { query: { ...range, model, api_keys: keys } }, signal, }); @@ -141,7 +141,7 @@ export default function MigrationDetail({ last_seen_date: selected.lastUsedDate, last_seen_requests: selected.lastDayRequests, }; - const { data } = await backgroundFetchClient.PUT("/alerting/model-deprecations/state", { body }); + const { data } = await backgroundFetchClient.PUT("/alerts/model-deprecations/state", { body }); if (!data) throw new Error("Could not save alert status"); return data; }, diff --git a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/ModelAlertsPage.integration.test.tsx b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/ModelAlertsPage.integration.test.tsx index f8698556d49..64a5faacbf9 100644 --- a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/ModelAlertsPage.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/ModelAlertsPage.integration.test.tsx @@ -50,8 +50,8 @@ describe("model migration impact", () => { body: request.method === "PUT" ? await request.clone().json() : null, }; calls.push(call); - if (url.pathname === "/alerting/model-deprecations/tags") return apiResponse([]); - if (request.method === "PUT" && url.pathname === "/alerting/model-deprecations/state") + if (url.pathname === "/alerts/model-deprecations/tags") return apiResponse([]); + if (request.method === "PUT" && url.pathname === "/alerts/model-deprecations/state") return apiResponse({ status: "resolved" }); if (url.pathname.endsWith("/aggregated/keys")) { const offset = Number(url.searchParams.get("offset") || 0); @@ -111,7 +111,7 @@ describe("model migration impact", () => { }; await waitFor(() => expect( - calls.find((call) => call.method === "PUT" && call.path === "/alerting/model-deprecations/state")?.body, + calls.find((call) => call.method === "PUT" && call.path === "/alerts/model-deprecations/state")?.body, ).toEqual(expectedAcknowledgement), ); diff --git a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.integration.test.tsx b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.integration.test.tsx index 897850393e2..85126526181 100644 --- a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.integration.test.tsx @@ -65,7 +65,7 @@ describe("deprecation alert API wiring", () => { renderWithProviders(); expect(await screen.findByText("1 alerts")).toBeInTheDocument(); expect(backgroundFetchClient.GET).toHaveBeenLastCalledWith( - "/alerting/model-deprecations/state", + "/alerts/model-deprecations/state", expect.objectContaining({ params: { query: { model: model.litellm_model, deprecation_date: model.deprecation_date } }, }), diff --git a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.ts b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.ts index ce126d5cd4f..0f94f4314a3 100644 --- a/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.ts +++ b/ui/litellm-dashboard/src/components/ModelDeprecationAlerts/useDeprecationAlerts.ts @@ -32,7 +32,7 @@ export function useDeprecationAlerts(accessToken: string | null) { const alerts = usedDeprecationAlerts(models, activity.results ?? []); return Promise.all( alerts.map(async (alert) => { - const { data: state } = await backgroundFetchClient.GET("/alerting/model-deprecations/state", { + const { data: state } = await backgroundFetchClient.GET("/alerts/model-deprecations/state", { params: { query: { model: alert.usageModel, deprecation_date: alert.model.deprecation_date } }, signal, }); diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts index f84513b3e56..fae4af387b5 100644 --- a/ui/litellm-dashboard/src/lib/http/schema.d.ts +++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts @@ -944,44 +944,6 @@ export interface paths { patch?: never; trace?: never; }; - "/alerting/model-deprecations/state": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** Get Deprecation Alert State */ - get: operations["get_deprecation_alert_state_alerting_model_deprecations_state_get"]; - /** Update Deprecation Alert State */ - put: operations["update_deprecation_alert_state_alerting_model_deprecations_state_put"]; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/alerting/model-deprecations/tags": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** - * Get Deprecation Usage Tags - * @description Distinct tags observed with this model for a page of affected reporting key IDs. - */ - get: operations["get_deprecation_usage_tags_alerting_model_deprecations_tags_get"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; "/alerting/settings": { parameters: { query?: never; @@ -1053,6 +1015,44 @@ export interface paths { patch: operations["update_alert_default_alerts_defaults__family__patch"]; trace?: never; }; + "/alerts/model-deprecations/state": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get Deprecation Alert State */ + get: operations["get_deprecation_alert_state_alerts_model_deprecations_state_get"]; + /** Update Deprecation Alert State */ + put: operations["update_deprecation_alert_state_alerts_model_deprecations_state_put"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/alerts/model-deprecations/tags": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get Deprecation Usage Tags + * @description Distinct tags observed with this model for a page of affected reporting key IDs. + */ + get: operations["get_deprecation_usage_tags_alerts_model_deprecations_tags_get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/alerts/models": { parameters: { query?: never; @@ -27280,7 +27280,7 @@ export interface components { active: boolean; /** * Can Update Status - * @description Current reader's status permission, evaluated by the issue-detail endpoint + * @description Current reader's status permission, evaluated by the alert detail endpoint */ can_update_status?: boolean | null; /** @@ -55211,105 +55211,6 @@ export interface operations { }; }; }; - get_deprecation_alert_state_alerting_model_deprecations_state_get: { - parameters: { - query: { - model: string; - deprecation_date: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DeprecationAlertState"]; - }; - }; - /** @description Validation Error */ - 422: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - update_deprecation_alert_state_alerting_model_deprecations_state_put: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["DeprecationAlertUpdate"]; - }; - }; - responses: { - /** @description Successful Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DeprecationAlertState"]; - }; - }; - /** @description Validation Error */ - 422: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; - get_deprecation_usage_tags_alerting_model_deprecations_tags_get: { - parameters: { - query: { - model: string; - api_keys: string[]; - start_date: string; - end_date: string; - }; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Successful Response */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["DeprecationTagUsage"][]; - }; - }; - /** @description Validation Error */ - 422: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["HTTPValidationError"]; - }; - }; - }; - }; alerting_settings_alerting_settings_get: { parameters: { query?: never; @@ -55422,6 +55323,105 @@ export interface operations { }; }; }; + get_deprecation_alert_state_alerts_model_deprecations_state_get: { + parameters: { + query: { + model: string; + deprecation_date: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeprecationAlertState"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + update_deprecation_alert_state_alerts_model_deprecations_state_put: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DeprecationAlertUpdate"]; + }; + }; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeprecationAlertState"]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; + get_deprecation_usage_tags_alerts_model_deprecations_tags_get: { + parameters: { + query: { + model: string; + api_keys: string[]; + start_date: string; + end_date: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeprecationTagUsage"][]; + }; + }; + /** @description Validation Error */ + 422: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["HTTPValidationError"]; + }; + }; + }; + }; list_alert_models_alerts_models_get: { parameters: { query?: {