mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix: tags on projects
This commit is contained in:
parent
4419c7a5f9
commit
2c00311599
4 changed files with 51 additions and 5 deletions
|
|
@ -2257,6 +2257,7 @@ class LiteLLM_VerificationTokenView(LiteLLM_VerificationToken):
|
|||
team_member: Optional[Member] = None
|
||||
team_metadata: Optional[Dict] = None
|
||||
team_object_permission_id: Optional[str] = None
|
||||
project_metadata: Optional[Dict] = None
|
||||
|
||||
# Team Member Specific Params
|
||||
team_member_spend: Optional[float] = None
|
||||
|
|
@ -2581,11 +2582,15 @@ class NewProjectRequest(LiteLLM_BudgetTable):
|
|||
model_tpm_limit: Optional[dict] = None
|
||||
blocked: bool = False
|
||||
object_permission: Optional[LiteLLM_ObjectPermissionBase] = None
|
||||
tags: Optional[List[str]] = None
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def set_model_info(cls, values):
|
||||
for field in LiteLLM_ManagementEndpoint_MetadataFields:
|
||||
for field in (
|
||||
LiteLLM_ManagementEndpoint_MetadataFields
|
||||
+ LiteLLM_ManagementEndpoint_MetadataFields_Premium
|
||||
):
|
||||
if values.get(field) is not None:
|
||||
if values.get("metadata") is None:
|
||||
values.update({"metadata": {}})
|
||||
|
|
@ -2608,11 +2613,15 @@ class UpdateProjectRequest(LiteLLM_BudgetTable):
|
|||
blocked: Optional[bool] = None
|
||||
budget_id: Optional[str] = None
|
||||
object_permission: Optional[LiteLLM_ObjectPermissionBase] = None
|
||||
tags: Optional[List[str]] = None
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def set_model_info(cls, values):
|
||||
for field in LiteLLM_ManagementEndpoint_MetadataFields:
|
||||
for field in (
|
||||
LiteLLM_ManagementEndpoint_MetadataFields
|
||||
+ LiteLLM_ManagementEndpoint_MetadataFields_Premium
|
||||
):
|
||||
if values.get(field) is not None:
|
||||
if values.get("metadata") is None:
|
||||
values.update({"metadata": {}})
|
||||
|
|
|
|||
|
|
@ -692,6 +692,10 @@ async def _user_api_key_auth_builder( # noqa: PLR0915
|
|||
project_object=_jwt_project_obj,
|
||||
)
|
||||
|
||||
# Add project metadata for tag-based routing when key belongs to a project
|
||||
if _jwt_project_obj is not None:
|
||||
valid_token.project_metadata = _jwt_project_obj.metadata
|
||||
|
||||
# return UserAPIKeyAuth object
|
||||
return cast(UserAPIKeyAuth, valid_token)
|
||||
|
||||
|
|
@ -1311,6 +1315,10 @@ async def _user_api_key_auth_builder( # noqa: PLR0915
|
|||
valid_token_dict = valid_token.model_dump(exclude_none=True)
|
||||
valid_token_dict.pop("token", None)
|
||||
|
||||
# Add project metadata when key belongs to a project (for tag-based routing)
|
||||
if _project_obj is not None:
|
||||
valid_token_dict["project_metadata"] = _project_obj.metadata
|
||||
|
||||
if _end_user_object is not None:
|
||||
valid_token_dict.update(end_user_params)
|
||||
valid_token_dict[
|
||||
|
|
|
|||
|
|
@ -990,6 +990,15 @@ async def add_litellm_data_to_request( # noqa: PLR0915
|
|||
data=data,
|
||||
_metadata_variable_name=_metadata_variable_name,
|
||||
)
|
||||
## PROJECT-LEVEL TAGS (project sits between key and team in hierarchy)
|
||||
project_metadata = getattr(
|
||||
user_api_key_dict, "project_metadata", None
|
||||
) or {}
|
||||
if "tags" in project_metadata and project_metadata["tags"] is not None:
|
||||
data[_metadata_variable_name]["tags"] = LiteLLMProxyRequestSetup._merge_tags(
|
||||
request_tags=data[_metadata_variable_name].get("tags"),
|
||||
tags_to_add=project_metadata["tags"],
|
||||
)
|
||||
## TEAM-LEVEL SPEND LOGS/TAGS
|
||||
team_metadata = user_api_key_dict.team_metadata or {}
|
||||
if "tags" in team_metadata and team_metadata["tags"] is not None:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request
|
|||
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm._uuid import uuid
|
||||
from litellm.proxy._types import *
|
||||
from litellm.proxy._types import * # noqa: F403
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
from litellm.proxy.management_endpoints.common_utils import _set_object_metadata_field
|
||||
from litellm.proxy.management_helpers.utils import (
|
||||
|
|
@ -284,6 +284,7 @@ async def new_project(
|
|||
- model_tpm_limit: *Optional[dict]* - TPM limits per model. Example: {"gpt-4": 50000, "gpt-3.5-turbo": 100000}
|
||||
- budget_duration: *Optional[str]* - Frequency of reseting project budget
|
||||
- metadata: *Optional[dict]* - Metadata for project, store information for project. Example metadata - {"use_case_id": "SNOW-12345", "responsible_ai_id": "RAI-67890"}
|
||||
- tags: *Optional[List[str]]* - Tags for tracking spend and/or tag-based routing. Keys belonging to this project inherit these tags.
|
||||
- blocked: *bool* - Flag indicating if the project is blocked or not - will stop all calls from keys with this project_id.
|
||||
- object_permission: Optional[LiteLLM_ObjectPermissionBase] - project-specific object permission. Example - {"vector_stores": ["vector_store_1", "vector_store_2"]}. IF null or {} then no object permission.
|
||||
|
||||
|
|
@ -421,6 +422,13 @@ async def new_project(
|
|||
updated_by=user_api_key_dict.user_id or litellm_proxy_admin_name,
|
||||
)
|
||||
|
||||
for field in LiteLLM_ManagementEndpoint_MetadataFields_Premium:
|
||||
if getattr(data, field, None) is not None:
|
||||
_set_object_metadata_field(
|
||||
object_data=project_row,
|
||||
field_name=field,
|
||||
value=getattr(data, field),
|
||||
)
|
||||
for field in LiteLLM_ManagementEndpoint_MetadataFields:
|
||||
if getattr(data, field, None) is not None:
|
||||
_set_object_metadata_field(
|
||||
|
|
@ -478,6 +486,7 @@ async def update_project(
|
|||
- team_id: *Optional[str]* - Updated team_id for the project
|
||||
- metadata: *Optional[dict]* - Updated metadata for project
|
||||
- models: *Optional[list]* - Updated list of models for the project
|
||||
- tags: *Optional[List[str]]* - Tags for tracking spend and/or tag-based routing
|
||||
- blocked: *Optional[bool]* - Updated blocked status
|
||||
- max_budget: *Optional[float]* - Updated max budget
|
||||
- tpm_limit: *Optional[int]* - Updated tpm limit
|
||||
|
|
@ -626,13 +635,24 @@ async def update_project(
|
|||
"object_permission_id"
|
||||
] = created_permission.object_permission_id
|
||||
|
||||
# Handle metadata fields
|
||||
for field in LiteLLM_ManagementEndpoint_MetadataFields:
|
||||
# Handle metadata fields (Premium + standard)
|
||||
for field in (
|
||||
LiteLLM_ManagementEndpoint_MetadataFields_Premium
|
||||
+ LiteLLM_ManagementEndpoint_MetadataFields
|
||||
):
|
||||
if field in update_data:
|
||||
if update_data.get("metadata") is None:
|
||||
update_data["metadata"] = {}
|
||||
update_data["metadata"][field] = update_data.pop(field)
|
||||
|
||||
# Merge metadata with existing (avoid wiping metadata on partial updates like tags)
|
||||
if "metadata" in update_data:
|
||||
existing_metadata = (existing_project.metadata or {}) if isinstance(
|
||||
existing_project.metadata, dict
|
||||
) else {}
|
||||
new_metadata = update_data.get("metadata") or {}
|
||||
update_data["metadata"] = {**existing_metadata, **new_metadata}
|
||||
|
||||
# Remove budget fields (following organization_endpoints.py pattern)
|
||||
update_data = _remove_budget_fields_from_project_data(update_data)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue