This commit is contained in:
eeshsaxena 2026-08-27 18:35:57 -05:00 • committed by GitHub
commit 6e61898f71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 88 additions and 11 deletions

View file

@ -52,6 +52,14 @@ def normalize_json_schema_types(
for key, value in schema.items():
if key == "type" and isinstance(value, str) and value in type_mapping:
normalized_schema[key] = type_mapping[value]
elif key == "type" and isinstance(value, list):
# JSON Schema also allows a list of types, which is the usual way
# to mark a field nullable (e.g. ["STRING", "NULL"]). Without this
# branch those entries fall through to the generic list recursion,
# which leaves the bare strings uppercase.
normalized_schema[key] = [
type_mapping.get(entry, entry) for entry in value
]
elif key == "properties" and isinstance(value, dict):
# Recursively normalize properties
normalized_schema[key] = {

View file

@ -2056,8 +2056,8 @@ async def get_users(
- internal_user_viewer
user_ids: Optional[str]
Get list of users by user_ids. Comma separated list of user_ids.
sso_ids: Optional[str]
Get list of users by sso_ids. Comma separated list of sso_ids.
sso_user_ids: Optional[str]
Get list of users by sso_user_ids. Comma separated list of sso_user_ids.
user_email: Optional[str]
Filter users by partial email match
team: Optional[str]

View file

@ -4179,7 +4179,9 @@ async def delete_verification_tokens(
Args:
tokens: List of tokens to delete
user_id: Optional user_id to filter by
user_api_key_cache: In-memory key cache to invalidate deleted tokens from
user_api_key_dict: User authentication information
litellm_changed_by: Optional username of the admin performing the change, for audit logs
Returns:
Tuple[Optional[Dict], List[LiteLLM_VerificationToken]]:

View file

@ -5416,14 +5416,14 @@ async def ui_view_teams(
[PROXY-ADMIN ONLY] Filter teams based on partial match of team_id or team_alias with pagination.
Args:
user_id (Optional[str]): Partial user ID to search for
user_email (Optional[str]): Partial email to search for
team_id (Optional[str]): Partial team ID to search for
team_alias (Optional[str]): Partial team alias to search for
page (int): Page number for pagination (starts at 1)
page_size (int): Number of items per page (max 100)
user_api_key_dict (UserAPIKeyAuth): User authentication information
Returns:
List[LiteLLM_SpendLogs]: Paginated list of matching user records
List[LiteLLM_TeamTable]: Paginated list of matching team records
"""
from litellm.proxy.proxy_server import prisma_client

View file

@ -0,0 +1,67 @@
from litellm.litellm_core_utils.json_validation_rule import (
normalize_json_schema_types,
normalize_tool_schema,
)
def test_normalizes_a_plain_string_type():
assert normalize_json_schema_types({"type": "STRING"}) == {"type": "string"}
def test_normalizes_a_list_of_types():
"""A list of types is how a nullable field is expressed.
Regression: these entries fell through to the generic list recursion, which
returns bare strings untouched, so they stayed uppercase.
"""
assert normalize_json_schema_types({"type": ["STRING", "NULL"]}) == {
"type": ["string", "null"]
}
def test_normalizes_a_list_of_types_when_nested():
schema = {"properties": {"a": {"type": ["INTEGER", "NULL"]}}}
assert normalize_json_schema_types(schema) == {
"properties": {"a": {"type": ["integer", "null"]}}
}
def test_leaves_unknown_type_entries_alone():
assert normalize_json_schema_types({"type": ["STRING", "custom"]}) == {
"type": ["string", "custom"]
}
def test_still_normalizes_properties_items_and_anyof():
schema = {
"type": "OBJECT",
"properties": {"xs": {"type": "ARRAY", "items": {"type": "INTEGER"}}},
"anyOf": [{"type": "STRING"}],
}
assert normalize_json_schema_types(schema) == {
"type": "object",
"properties": {"xs": {"type": "array", "items": {"type": "integer"}}},
"anyOf": [{"type": "string"}],
}
def test_tool_schema_normalizes_a_nullable_parameter():
tool = {
"function": {
"parameters": {
"type": "OBJECT",
"properties": {"x": {"type": ["STRING", "NULL"]}},
}
}
}
assert normalize_tool_schema(tool) == {
"function": {
"parameters": {
"type": "object",
"properties": {"x": {"type": ["string", "null"]}},
}
}
}

View file

@ -14659,14 +14659,14 @@ export interface paths {
* @description [PROXY-ADMIN ONLY] Filter teams based on partial match of team_id or team_alias with pagination.
*
* Args:
* user_id (Optional[str]): Partial user ID to search for
* user_email (Optional[str]): Partial email to search for
* team_id (Optional[str]): Partial team ID to search for
* team_alias (Optional[str]): Partial team alias to search for
* page (int): Page number for pagination (starts at 1)
* page_size (int): Number of items per page (max 100)
* user_api_key_dict (UserAPIKeyAuth): User authentication information
*
* Returns:
* List[LiteLLM_SpendLogs]: Paginated list of matching user records
* List[LiteLLM_TeamTable]: Paginated list of matching team records
*/
get: operations["ui_view_teams_team_filter_ui_get"];
put?: never;
@ -16154,8 +16154,8 @@ export interface paths {
* - internal_user_viewer
* user_ids: Optional[str]
* Get list of users by user_ids. Comma separated list of user_ids.
* sso_ids: Optional[str]
* Get list of users by sso_ids. Comma separated list of sso_ids.
* sso_user_ids: Optional[str]
* Get list of users by sso_user_ids. Comma separated list of sso_user_ids.
* user_email: Optional[str]
* Filter users by partial email match
* team: Optional[str]