From cadc72eddf1f0b9c141d19158bf24353055fa5a2 Mon Sep 17 00:00:00 2001 From: jesus Date: Fri, 18 Sep 2026 01:28:35 +0000 Subject: [PATCH] fix(proxy): return budget_limits from user info v2 and lower update params complexity Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/_types.py | 1 + .../internal_user_endpoints.py | 14 ++++++++++---- .../test_internal_user_endpoints.py | 1 + ui/litellm-dashboard/src/components/networking.tsx | 2 ++ ui/litellm-dashboard/src/lib/http/schema.d.ts | 2 ++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/litellm/proxy/_types.py b/litellm/proxy/_types.py index 2c883e833e2..8404b9d2c37 100644 --- a/litellm/proxy/_types.py +++ b/litellm/proxy/_types.py @@ -3317,6 +3317,7 @@ class UserInfoV2Response(LiteLLMPydanticObjectBase): object_permission: LiteLLM_ObjectPermissionTable | None = None model_max_budget: Mapping[str, object] | None = None model_max_budget_usage: Mapping[str, Mapping[str, object]] | None = None + budget_limits: list[BudgetLimitEntry] | None = None from litellm.models.config import LiteLLM_Config as LiteLLM_Config # noqa: E402 diff --git a/litellm/proxy/management_endpoints/internal_user_endpoints.py b/litellm/proxy/management_endpoints/internal_user_endpoints.py index 440a1a0fb57..7bd95f9a417 100644 --- a/litellm/proxy/management_endpoints/internal_user_endpoints.py +++ b/litellm/proxy/management_endpoints/internal_user_endpoints.py @@ -15,7 +15,7 @@ These are members of a Team on LiteLLM import asyncio import json import traceback -from collections.abc import Awaitable, Mapping, Sequence +from collections.abc import Awaitable, Mapping, Sequence, Set from datetime import datetime, timezone from types import MappingProxyType from typing import Any, Final, Literal, Protocol, cast, overload @@ -1131,6 +1131,7 @@ async def user_info_v2( model_max_budget=user_data.get("model_max_budget"), cache=model_max_budget_limiter.dual_cache, ), + budget_limits=user_data.get("budget_limits"), ) except Exception as e: verbose_proxy_logger.exception("litellm.proxy.proxy_server.user_info_v2(): Exception occured - %s", e) @@ -1263,6 +1264,13 @@ def _prepare_user_budget_limits(value: object) -> str: return json.dumps(initialized_windows) +def _set_user_budget_limits_update(fields_set: Set[str], value: object, non_default_values: dict) -> None: + if "budget_limits" not in fields_set: + return + validate_budget_limits(value) + non_default_values["budget_limits"] = _prepare_user_budget_limits(value) + + def _update_internal_user_params(data_json: dict, data: UpdateUserRequest | UpdateUserRequestNoUserIDorEmail) -> dict: non_default_values: Final = {} fields_set: Final = data.fields_set() if hasattr(data, "fields_set") else set() @@ -1272,9 +1280,7 @@ def _update_internal_user_params(data_json: dict, data: UpdateUserRequest | Upda if k in fields_set: non_default_values[k] = v elif k == "budget_limits": - if k in fields_set: - validate_budget_limits(v) - non_default_values[k] = _prepare_user_budget_limits(v) + _set_user_budget_limits_update(fields_set=fields_set, value=v, non_default_values=non_default_values) elif k == "model_max_budget": if k in fields_set: try: diff --git a/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py index df911223d50..40605f29c6b 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_internal_user_endpoints.py @@ -3225,6 +3225,7 @@ async def test_user_info_v2_response_shape(mocker): "object_permission", "model_max_budget", "model_max_budget_usage", + "budget_limits", } assert set(response_dict.keys()) == expected_fields diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index e77c8ba7e41..f2faf75b649 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -94,6 +94,7 @@ import { Team } from "./key_team_helpers/key_list"; import { EmailEventSettingsResponse, EmailEventSettingsUpdateRequest } from "./email_events/types"; import type { SkillRegisterRequest } from "./claude_code_plugins/types"; import type { ModelBudgetUsage, ModelMaxBudget } from "./key_team_helpers/ModelMaxBudgetEditor"; +import type { BudgetWindowEntry } from "./key_team_helpers/BudgetWindowsEditor"; import type { ObjectPermission } from "./object_permission_types"; import type { components } from "@/lib/http/schema"; import { jsonFields } from "./common_components/check_openapi_schema"; @@ -1097,6 +1098,7 @@ export interface UserInfoV2Response { object_permission?: ObjectPermission | null; model_max_budget?: ModelMaxBudget | null; model_max_budget_usage?: Record | null; + budget_limits?: BudgetWindowEntry[] | null; } /** diff --git a/ui/litellm-dashboard/src/lib/http/schema.d.ts b/ui/litellm-dashboard/src/lib/http/schema.d.ts index ba34aa6b0d9..85f8975c432 100644 --- a/ui/litellm-dashboard/src/lib/http/schema.d.ts +++ b/ui/litellm-dashboard/src/lib/http/schema.d.ts @@ -40453,6 +40453,8 @@ export interface components { UserInfoV2Response: { /** Budget Duration */ budget_duration?: string | null; + /** Budget Limits */ + budget_limits?: components["schemas"]["BudgetLimitEntry"][] | null; /** Budget Reset At */ budget_reset_at?: string | null; /** Created At */