Ë
    tPêjøZ ã                   ó #  — U d Z ddlZddlZddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZ ddlmZmZmZmZmZmZmZ ddlmZmZmZ ddlmZ ddlmZmZ ddlZdd	lm Z  dd
l!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZM ddlNmOZOmPZP ddlQmRZR ddlSmTZT ddlUmVZVmWZW ddlXmYZY ddlZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZambZbmcZcmdZdmeZemfZfmgZgmhZhmiZi ddljmkZk ddllmmZmmnZn ddlompZp ddlqmrZr ddlsmtZtmuZumvZv ddlwmxZx ddlymzZz ddl{m|Z| ddl}m~Z~ ddlm€Z€ dd l�m‚Z‚mƒZƒm„Z„m…Z…m†Z†m‡Z‡mˆZˆ dd!l‰mŠZŠ dd"l‹mŒZŒ dd#l�mŽZŽ dd$l�m�Z� dd%l‘m’Z’ d&d'l“m”Z”m•Z• d&d(l–m—Z—m˜Z˜ er	dd)l™mšZ› e›ZšneZš G d*„ d+e«      Zœ G d,„ d-e«      Z� G d.„ d/e«      Zž G d0„ d1e«      ZŸ G d2„ d3e«      Z  G d4„ d5e«      Z¡ G d6„ d7ee~   «      Z¢ G d8„ d9ee~   «      Z£d:e£eœ   d;e¢eœ   fd<„Z¤d:e£e�   d;e¢e�   fd=„Z¥d:e£ež   d;e¢ež   fd>„Z¦d:e£eŸ   d;e¢eŸ   fd?„Z§d:e£e    d;e¢e    fd@„Z¨d:e£e¡   d;e¢e¡   fdA„Z© G dB„ dCe«      Zªd:e£eª   d;e¢eª   fdD„Z« G dE„ dFe«      Z¬d:e£e¬   d;e¢e¬   fdG„Z­ G dH„ dIe«      Z®d:e£e®   d;e¢e®   fdJ„Z¯ G dK„ dLe«      Z° G dM„ dNe«      Z±d:e£e±   d;e¢e±   fdO„Z² G dP„ dQe«      Z³ G dR„ dSe«      Z´dTe´d;e
eµ   fdU„Z¶ G dV„ dWe«      Z·dXe·d;e·fdY„Z¸dZe¹d;e	eµeºf   fd[„Z» G d\„ d]e«      Z¼d^e¼d;e¼fd_„Z½ e½e3«      Z¾ee¿d`<    e"da¬b«      ZÀee¿dc<   e'ZÁee¿dd<   eF�j„                  �j†                  eF�jˆ                  �j†                  z   ZÅee¿de<   dfeµdgeÆd;dfdh„ZÇdieŽd;e¹eµeÈf   dz  fdj„ZÉdkeµeÊeµ   z  dz  dieŽdz  d;eÈfdl„ZË ei «      ZÌee	eµeºf      e¿dm<   dkeµdidnd;eÈfdo„ZÍdkeµdidnd;eÈfdp„ZÎ ei «      ZÏee	eµeºf      e¿dq<   dreºd;eÈfds„ZÐdte	eµeºf   d;eÈfdu„ZÑdte	eµeºf   d;eÈfdv„ZÒdkeµdidnd;eÈfdw„ZÓdkeµdidnd;eÈfdx„ZÔdkeµdz  dieŽdz  d;eÈfdy„ZÕdkeµeÊeµ   z  dz  dieŽdz  d;eÖeµdzf   fd{„Z×d|eÖeµdzf   d;eµfd}„ZØd~e@dz  deµeÊeµ   z  dz  dieŽdz  d€eÈd�eMdz  d‚eud;dfdƒ„ZÙd„e¹d…edZe¹d†eµd;df
d‡„ZÚd„e¹dZe¹d†eµd;dfdˆ„ZÛd‰eÜdz  d€eÈd†eµd;dfdŠ„ZÝd‹ZÞeeÖ   e¿dŒ<   dZe	eµeºf   d�eCdz  d;dfdŽ„ZßdZe¹d�eMdz  d�eCdz  d†eµd;df
d�„Zà eáh d�£«      Zâee¿d‘<    eáh d’£«      Zãee¿d“<   	 	 �d~dZe¹d�eCdz  d”eEdz  d•e9dz  d‰eÜdz  d„e¹d†eµdieŽdz  d‚eud�eMdz  d…ed€eÈd~e@dz  d;eÈfd–„Zäd—eEdz  d;eGdz  fd˜„Zå	 �dd†eµd…ed™e¹d�eMdz  d—eEdz  d;eÈfdš„Zæd—eEdz  fd›„Zçdœeµd�eÊd;eÈfdž„ZèdŸeGdœeµd e;d;eÈfd¡„Zéd¢eMd£eµdz  d;eÈfd¤„Zêd�eÊd;eÊfd¥„Zë	 �dd¦etdz  d§e^d¨ešdz  d;e8dz  fd©„Zìevdªeµd¦etdz  d§e^d;e8dz  fd«„«       Zí	 �dd¬e9d¦etd§e^d¨ešdz  d;e9f
d­„Zîd¬e9d†eµd;dfd®„Zïd¯Zðee¿d°<   d±eµd;e	eµeºf   fd²„Zñd;e	eµeºf   fd³„Zò G d´„ dµ«      Zó eó«       Zôee¿d¶<    e�jê                  «       Zöee¿d·<    e�jê                  «       Z÷ee¿d¸<    e�jê                  «       Zøee¿d¹<   dºeµd»eµd§e^d;eáeµ   dz  eóz  fd¼„ZùdºeµdreÖeµdzf   eµz  d½eÜd§e^d;df
d¾„Zúdºeµd»eµd¿eûdÀeg eeÖeµdzf      f   d§e^d;eáeµ   dz  fdÁ„Züdºeµd»eµd¿eûdÂe�jê                  dÀeg eeÖeµdzf      f   d§e^d;eáeµ   dz  fdÃ„Zýd¦etd§e^d;eáeµ   dz  fdÄ„ZþdÅeµd¦etd§e^dÆeÜdz  d;eÈf
dÇ„Zÿev	 	 	 	 �d€dÅeµdz  d¦etdz  d§e^d†eµdz  d¨ešdz  d‚eudz  dÆeÜdz  d;e9dz  fdÈ„«       �Z dÉ�Zee¿dÊ<   dË�Zee¿dÌ<   	 	 	 �d�dÍeµdz  d¦etdz  d§e^d¨ešdz  d‚eudz  d†eµd;eµdz  fdÎ„�Z	 	 	 �d�dÅeµd¦etd§e^d¨ešdz  d‚eudz  d†eµd;eÈfdÏ„�Zd¦etd§e^d;eáeµ   dz  fdÐ„�Zd¦etd§e^d;eáeµ   dz  fdÑ„�ZdÒe
eµ   d¦etd§e^d;eÖeÖeµe�f   dzf   fdÓ„�ZdÔe±d;e�fdÕ„�ZevdÖe
eµ   d¦etdz  d§e^d;e¹eµe�f   fd×„«       �Z	dØe
eµ   d¦etd§e^d;eÖeÖeµeAf   dzf   fdÙ„�Z
ev	 	 �d‚dÚeÊeµ   d¦etdz  d§e^d¨ešdz  d‚eudz  d;e¹eµeAf   fdÛ„«       �Zev	 	 �d‚dÜeµdz  d¦etdz  d§e^d¨ešdz  d‚eudz  d;eAdz  fdÝ„«       �Zev	 	 �d‚dÞeµdßeµd¦etdz  d§e^d¨ešdz  d‚eudz  d;edà   fdá„«       �ZdkeµdâeÊeµ   dz  dieŽdz  d;eÈfdã„�Zdäeµdce"ddeûd;eÈfdå„�Zdäeµdreºdz  dce"fdæ„�Zdçe5d„e¹däedè   d;eÊeµ   dz  fdé„�Zdçe5d„e¹d;eÊeµ   dz  fdê„�Zdçe5d„e¹d;eÊeµ   dz  fdë„�Z	 	 �d‚d¦etdìeµdz  díeµdz  d;dîfdï„�Zd¦etdz  d§e^dðeEdíeµdz  d;eEf
dñ„�Zev	 	 	 	 	 �dƒdÞeµdz  d¦etdz  d§e^dòeÈd¨ešdz  d‚eudz  dìeµdz  díeµdz  dóeÈdz  d;eEdz  fdô„«       �Zdäeµdree	eµeºf   z  d§e^d‚eudz  dõ�ee   f
dö„�Zdßeµd÷eDd§e^d‚eudz  fdø„�Z	 �ddÞeµdßeµd§e^dùeÜdz  d;df
dú„�Zdßeµdûeµdz  d§e^d‚eudz  d;df
dü„�ZdýeµdþeMd§e^d‚eudz  fdÿ„�Zdýeµd§e^d‚eudz  f�d „�Z�de
eµ   d§e^d‚eudz  d;df�d„�Z G �d„ �de«      �Z G �d„ �de«      �Z ev	 �ddßeµd¦et�deÈdz  d;�df�d	„«       �Z!dßeµd¦etd;�df�d
„�Z"	 �ddßeµd¦etd§e^dce"ddeûd‚eudz  däeµ�deÈdz  d;eDf�d„�Z#däeµd§e^d¨ešdz  d;eDdz  f�d„�Z$	 	 	 	 	 �dƒdßeµd¦etdz  d§e^d¨ešdz  d‚eudz  �deÈdz  dóeÈdz  �deÈdz  d;eDf�d„�Z%	 �d�deµ�de7d§e^d‚eudz  f�d„�Z&	 �d�deµd§e^d‚eudz  f�d„�Z'ev	 �d�deµd¦etdz  d§e^d‚eudz  d;e7f
�d„«       �Z(ev	 	 �d‚dûeµd¦etdz  d§e^d¨e�d   d‚eudz  d;eDf�d„«       �Z)ev	 	 �d‚�deµd¦etdz  d§e^d¨e�d   d‚eudz  d;e?dz  f�d„«       �Z*�d�Z+ee¿�d<    G �d„ �d«      �Z,dýeµd¦etd¨ešdz  d‚eudz  d;edz  f
�d„�Z-ev�deµ�deµd¦etd;eµdz  f�d„«       �Z.ev	 	 	 �d„dýeµd¦etdz  d§e^d¨ešdz  d‚eudz  �deÈdz  d;eMf�d „«       �Z/dþeMd;eMf�d!„�Z0ev	 	 �d‚�d"eµd¦etdz  d§e^d¨ešdz  d‚eudz  d;e=dz  f�d#„«       �Z1ev	 	 �d‚�d$eÊeµ   d¦etdz  d§e^d¨ešdz  d‚eudz  d;eÊe<   f�d%„«       �Z2 G �d&„ �d'eÆ«      �Z3ev	 	 	 �d…�d(eµd¦etdz  d§e^d¨ešdz  d‚eudz  �d)eÈd;e?dz  f�d*„«       �Z4	 	 	 �d„�d+e
eµ   �d,e�d-   d¦etdz  d§e^dz  d‚eudz  d;eÊeµ   f�d.„�Z5	 	 	 �d„�d+e
eµ   d¦etdz  d§e^dz  d‚eudz  d;eÊeµ   f
�d/„�Z6	 	 	 �d„�d+eÊeµ   d¦etdz  d§e^dz  d‚eudz  d;eÊeµ   f
�d0„�Z7	 	 	 �d„�d+eÊeµ   d¦etdz  d§e^dz  d‚eudz  d;eÊeµ   f
�d1„�Z8d|eÊeµ   dieŽdz  dßeµdz  d;eÊeµ   f�d2„�Z9	 	 �d‚dkeµdieŽdz  d|eÊeµ   �d3e¹eµeµf   dz  dßeµdz  d;eÈf�d4„�Z:	 	 	 	 �d†dkeµeÊeµ   z  dieŽdz  d|eÊeµ   �d3e¹eµeµf   dz  dßeµdz  �d5e�d6   �d7eûd;e�d8   f�d9„�Z;�ddkeµ�d3e¹eµeµf   dz  d;eÈf�d:„�Z<d�eMd;eÊeµ   f�d;„�Z=dkeµe
eµ   z  dieŽdßeµdz  d;eáeµ   f�d<„�Z>d�eMd�eCdz  d¦etd§e^d‚eud;e
eµ   f�d=„�Z?d�eMd�eCdz  d¦etd§e^d‚eud;e
eµ   f�d>„�Z@d�eMd�eCdz  d~e@dz  d¦etd§e^d‚eud;eÖe
eµ   dzf   f�d?„�ZAdkeµe
eµ   z  dz  d�eMdz  d�eCdz  d~e@dz  dieŽdz  d¦etdz  d§e^d‚eud;eÖeµdzf   f�d@„�ZBdkeµe
eµ   z  dz  d�eMdz  d�eCdz  d~e@dz  dieŽdz  d¦etdz  d§e^d‚eud;eÖeµdzf   f�dA„�ZCdkeµeÊeµ   z  �dBeÊdz  d�eMdie�j                  dz  d;e�d8   f
�dC„�ZDdkeµ�dBeÊdz  d�eMdie�j                  dz  d;df
�dD„�ZE	 �ddkeµ�dEe?dz  dieŽdz  �d3e¹eµeµf   dz  d;e�d8   f
�dF„�ZF	 �ddkeµeÊeµ   z  d�eCdz  dieŽdz  �d3e¹eµeµf   dz  d;e�d8   f
�dG„�ZGd�eMdz  d�eCdz  �d,e�d-   d;eÊeµ   f�dH„�ZHdkeµeÊeµ   z  d�eMdz  d�eCdz  dieŽdz  d;eÈf
�dI„�ZIdkeµeÊeµ   z  d~e@dieŽdz  d;e�d8   f�dJ„�ZJdkeµeÊeµ   z  dieŽdz  d”eEdz  d;e�d8   f�dK„�ZK�dLe=dz  d;eÊeµ   f�dM„�ZL�dNeµ�dOeÊeµ   �d5e�dP   d;e�d8   f�dQ„�ZM�dNeµd�eMd;e�d8   f�dR„�ZN�dNeµd�eCdz  d;e�d8   f�dS„�ZO�dNeµd�eMd�eCdz  d;eÈf�dT„�ZPdkeµdieŽdz  �dUeµdz  d;e�d8   f�dV„�ZQd�eMd;eÈf�dW„�ZR	 �dd�eMd‚eud—eEdz  f�dX„�ZSd�eMf�dY„�ZT	 �dd�eMd‚eud—eEdz  f�dZ„�ZU�d[eµe
eº   z  dz  d;eÊeµ   f�d\„�ZV�d]e	eµeµe
eº   z  dz  f   dz  d;e¹eµeÊeµ   f   f�d^„�ZW�d_e	eµeµe
eº   z  dz  f   dz  �d`e	eµeµe
eº   z  dz  f   dz  d;e¹eµeÊeµ   f   dz  f�da„�ZX	 �dd�eMd‚eud—eEdz  f�db„�ZYd�eCdz  d”eEdz  d�eMdz  d¦etdz  d§e^d‚euf�dc„�ZZdkeµeÊeµ   z  d�eCd�eMdieŽdz  d¦e�dd   d§e^d‚eud;df�de„�Z[d�eCdz  d�eMdz  d‚euf�df„�Z\d�eCdz  f�dg„�Z]d�eCdz  d�eMdz  d‚euf�dh„�Z^d~e@dz  d�eMdz  d‚euf�di„�Z_d~e@dz  d�eMdz  d‚euf�dj„�Z`�dkeµd;eµf�dl„�Za	 �d�dkeµd¦etdz  d§e^d‚eudz  d;e@dz  f
�dm„�Zb�dkeµd§e^d;df�dn„�Zcd�eMdz  d�eCdz  d¦etdz  d§e^d‚euf
�do„�ZddZe¹d¦etdz  d§e^d‚eud�eMdz  f
�dp„�Ze�dqe
eµ   d¦etdz  d§e^d;df�dr„�Zfdkeµ�dseµd;eÈf�dt„�Zgdkeµ�dueÊd;eÈf�dv„�Zhdkeµ�dseµd;eÈf�dw„�Zi�dseµd;eÈf�dx„�ZjdZe¹d�eCdz  d�eMdz  f�dy„�Zk�d5e�dz   �d{eÊeµ   �d|eªdz  f�d}„�Zly(‡  zº
Got Valid Token from Cache, DB
Run checks for:

1. If user can call model
2. If user is in budget
3. If end_user ('user' passed to /chat/completions, /embeddings endpoint) is in budget
é    N)Ú	AwaitableÚCallableÚIteratorÚMappingÚSequence)ÚMappingProxyType)ÚTYPE_CHECKINGÚAnyÚFinalÚLiteralÚOptionalÚProtocolÚcast)ÚHTTPExceptionÚRequestÚstatus)Ú	BaseModel)ÚReadOnlyÚ	TypedDict)Úverbose_proxy_logger)ÚLimitedSizeOrderedDict)
ÚCLI_JWT_EXPIRATION_HOURSÚCLI_SESSION_KEY_PREFIXÚDEFAULT_ACCESS_GROUP_CACHE_TTLÚDEFAULT_IN_MEMORY_TTLÚDEFAULT_MAX_RECURSE_DEPTHÚ-EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGEÚ%END_USER_RESTRICTED_REGISTRY_MAX_SIZEÚ$MODEL_ACCESS_GROUP_REGISTRY_MAX_SIZEÚ!REGISTRY_ERROR_NEGATIVE_CACHE_TTLÚTAG_REGISTRY_MAX_SIZE)Útracer)Úget_llm_provider)Úsafe_json_loads)Ú
RBAC_ROLESÚCallInfoÚLiteLLM_AccessGroupTableÚLiteLLM_BudgetTableÚLiteLLM_EndUserTableÚLitellm_EntityTypeÚLiteLLM_JWTAuthÚ LiteLLM_ManagedVectorStoresTableÚLiteLLM_ObjectPermissionTableÚ#LiteLLM_OrganizationMembershipTableÚLiteLLM_OrganizationTableÚLiteLLM_ProjectTableCachedObjÚLiteLLM_TagTableÚLiteLLM_TeamMembershipÚLiteLLM_TeamTableÚLiteLLM_TeamTableCachedObjÚLiteLLM_UserTableÚLiteLLMRoutesÚLitellmUserRolesÚNewTeamRequestÚProxyErrorTypesÚProxyExceptionÚRoleBasedPermissionsÚSpecialModelNamesÚUserAPIKeyAuth)Úbudget_throttle_percentageÚshould_throttle_budget_exceeded)ÚRouteChecks)Úpublish_auth_cache_invalidation)Ú_safe_get_request_headersÚ_safe_get_request_query_params)Úget_budget_reset_time)Ú.END_USER_RESTRICTED_REGISTRY_OVERFLOW_SENTINELÚ-MODEL_ACCESS_GROUP_REGISTRY_OVERFLOW_SENTINELÚTAG_REGISTRY_OVERFLOW_SENTINELÚUserApiKeyCacheÚend_user_cache_keyÚ&end_user_restricted_registry_cache_keyÚget_management_object_ttlÚmodel_access_group_cache_keyÚ%model_access_group_registry_cache_keyÚ$model_access_group_spend_counter_keyÚobject_permission_cache_keyÚtag_cache_keyÚtag_registry_cache_keyÚteam_membership_auth_cache_keyÚ%team_membership_reservation_cache_key)ÚPrismaDBExceptionHandler)ÚTOOL_CAPABLE_CALL_TYPESÚextract_request_tool_names©Úroute_request)Úget_budget_window_start)ÚPrismaClientÚProxyLoggingÚlog_db_metrics)ÚBudgetRepository)ÚObjectPermissionRepository)ÚOrganizationRepository)ÚRowT_co)ÚProjectRepository)ÚAccessGroupRepositoryÚEndUserRepositoryÚJWTKeyMappingRepositoryÚManagedVectorStoresRepositoryÚ ModelAccessGroupBudgetRepositoryÚTagRepositoryÚTeamMembershipRepository)ÚTeamRepository)ÚUserRepository)ÚRouter)ÚModelAccessGroupBudget)Úget_utc_datetimeé   )Ú$add_team_org_context_to_request_bodyÚ$organization_role_based_access_check)Úget_model_from_requestÚget_request_route_template)ÚSpanc                   ó"   — e Zd Zdeeef   fd„Zy)Ú_PrismaDictableRowÚreturnc                  ó   — y ©N© ©Úselfs    úc/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/auth/auth_checks.pyÚdictz_PrismaDictableRow.dictŒ   ó   � ó    N)Ú__name__Ú
__module__Ú__qualname__r   ÚstrÚobjectr}   ry   r   r|   ru   ru   ‹   s   „ Ø/�g˜c 6˜kÑ*Ô/r   ru   c                   ó   — e Zd ZU eed<   y)Ú_PrismaJWTKeyMappingRowÚtokenN)r€   r�   r‚   rƒ   Ú__annotations__ry   r   r|   r†   r†   �   s   … Ø„Jr   r†   c                   ó"   — e Zd Zdeeef   fd„Zy)Ú_PrismaModelDumpRowrv   c                  ó   — y rx   ry   rz   s    r|   Ú
model_dumpz_PrismaModelDumpRow.model_dump”   r~   r   N)r€   r�   r‚   r   rƒ   r„   rŒ   ry   r   r|   rŠ   rŠ   “   s   „ Ø5˜G C¨ KÑ0Ô5r   rŠ   c                   ó8   — e Zd Zdeeef   fd„Zdeeef   fd„Zy)Ú_PrismaTeamRowrv   c                  ó   — y rx   ry   rz   s    r|   r}   z_PrismaTeamRow.dict˜   r~   r   c                  ó   — y rx   ry   rz   s    r|   rŒ   z_PrismaTeamRow.model_dumpš   r~   r   N)r€   r�   r‚   r   rƒ   r„   r}   rŒ   ry   r   r|   rŽ   rŽ   —   s$   „ Ø/�g˜c 6˜kÑ*Ó/à5˜G C¨ KÑ0Ô5r   rŽ   c                   óT   — e Zd Zdeeef   fd„Zdeeef   fd„Zdee	eef      fd„Z
y)Ú_PrismaVectorStoreRowrv   c                  ó   — y rx   ry   rz   s    r|   r}   z_PrismaVectorStoreRow.dictž   r~   r   c                  ó   — y rx   ry   rz   s    r|   rŒ   z _PrismaVectorStoreRow.model_dump    r~   r   c                  ó   — y rx   ry   rz   s    r|   Ú__iter__z_PrismaVectorStoreRow.__iter__¢   r~   r   N)r€   r�   r‚   r   rƒ   r„   r}   rŒ   r   Útupler–   ry   r   r|   r’   r’   �   s:   „ Ø/�g˜c 6˜kÑ*Ó/à5˜G C¨ KÑ0Ó5à;˜( 5¨¨f¨Ñ#5Ñ6Ô;r   r’   c                   ó–   — e Zd ZU eed<   edeedz     dz  fd„«       Zej                  dee   dz  ddfd„«       Zde
eeef      fd„Zy)Ú_PrismaUserRowÚuser_idrv   Nc                  ó   — y rx   ry   rz   s    r|   Úorganization_membershipsz'_PrismaUserRow.organization_memberships¨   s   € ØWZr   Úvaluec                  ó   — y rx   ry   )r{   r�   s     r|   rœ   z'_PrismaUserRow.organization_memberships«   s   € Ø]`r   c                  ó   — y rx   ry   rz   s    r|   r–   z_PrismaUserRow.__iter__®   r~   r   )r€   r�   r‚   rƒ   rˆ   Úpropertyr   rŠ   rœ   Úsetterr   r—   r„   r–   ry   r   r|   r™   r™   ¥   sk   … ØƒLàØZ¨(Ð3FÈÑ3MÑ*NÐQUÑ*UÒZó ØZà×$Ñ$Ø`¨hÐ7JÑ.KÈdÑ.RÐ`ÐW[Ò`ó %Ø`à;˜( 5¨¨f¨Ñ#5Ñ6Ô;r   r™   c            
       ó0  — e Zd Zddœdeeef   deeef   dz  dedz  fd„Zddœdeeef   deeef   dz  dedz  fd„Zddddœdeeef   dz  deeef   dz  d	e	dz  de
e   fd
„Zdeeef   deeef   dedz  fd„Zddœdeeef   deeef   dz  defd„Zy)Ú_PrismaAuthTableN)ÚincludeÚwherer¤   rv   c             ƒ   ó   K  — y ­wrx   ry   ©r{   r¥   r¤   s      r|   Úfind_uniquez_PrismaAuthTable.find_unique²   ó	   è ø€ àùó   ‚c             ƒ   ó   K  — y ­wrx   ry   r§   s      r|   Ú
find_firstz_PrismaAuthTable.find_first¶   r©   rª   )r¥   r¤   Útaker­   c             ƒ   ó   K  — y ­wrx   ry   )r{   r¥   r¤   r­   s       r|   Ú	find_manyz_PrismaAuthTable.find_manyº   s   è ø€ ð  ùrª   Údatac             ƒ   ó   K  — y ­wrx   ry   )r{   r¥   r°   s      r|   Úupdatez_PrismaAuthTable.updateÂ   ó   è ø� ùrª   c             ƒ   ó   K  — y ­wrx   ry   )r{   r°   r¤   s      r|   Úcreatez_PrismaAuthTable.createÄ   r³   rª   )r€   r�   r‚   r   rƒ   r„   r`   r¨   r¬   Úintr   r¯   r²   rµ   ry   r   r|   r£   r£   ±   s6  „ àUYòØ  V Ñ,ðØ7>¸sÀF¸{Ñ7KÈdÑ7Rðà	�4‰óð
 VZòØ  V Ñ,ðØ7>¸sÀF¸{Ñ7KÈdÑ7Rðà	�4‰óð .2Ø/3Øò ð �s˜F�{Ñ# dÑ*ð ð ˜˜f˜Ñ%¨Ñ,ð	 ð
 �D‰jð ð 
�'Ñ	ó ð n W¨S°&¨[Ñ%9ÐmÀÈÈfÈÑAUÐmÐZaÐdhÑZhÓmàaeÒv G¨C°¨KÑ$8ÐvÀ7È3ÐPVÈ;ÑCWÐZ^ÑC^ÐvÐjqÔvr   r£   c                   ó(   — e Zd Zedee   fd„«       Zy)Ú_PrismaTableHolderrv   c                  ó   — y rx   ry   rz   s    r|   Útablez_PrismaTableHolder.tableÈ   s   € Ø25r   N)r€   r�   r‚   r    r£   r`   rº   ry   r   r|   r¸   r¸   Ç   s   „ ØØ5Ð'¨Ñ0Ò5ó Ù5r   r¸   Úreporv   c                 ó   — | j                   S rx   ©rº   ©r»   s    r|   Ú_dictable_tabler¿   Ì   ó   € Ø�:‰:Ðr   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_jwt_key_mapping_tablerÂ   Ð   ó   € ð �:‰:Ðr   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_model_dump_tablerÅ   Ö   rÀ   r   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_team_tablerÇ   Ú   rÀ   r   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_vector_store_tablerÉ   Þ   rÀ   r   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_user_tablerË   â   rÀ   r   c                   ó.   — e Zd Zedee   dz  fd„«       Zy)Ú_VectorStorePermissionsRowrv   Nc                  ó   — y rx   ry   rz   s    r|   Úvector_storesz(_VectorStorePermissionsRow.vector_storesç   s   € Ø58r   )r€   r�   r‚   r    r   rƒ   rÏ   ry   r   r|   rÍ   rÍ   æ   s   „ ØØ8˜x¨™}¨tÑ3Ò8ó Ù8r   rÍ   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_object_permission_tablerÑ   ë   rÃ   r   c                   ó.   — e Zd ZU eed<   deeef   fd„Zy)Ú_PrismaTagRowÚtag_namerv   c                  ó   — y rx   ry   rz   s    r|   r}   z_PrismaTagRow.dictô   r~   r   N©r€   r�   r‚   rƒ   rˆ   r   r„   r}   ry   r   r|   rÓ   rÓ   ñ   s   … ØƒMà/�g˜c 6˜kÑ*Ô/r   rÓ   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú
_tag_tablerØ   ÷   rÀ   r   c                   ó.   — e Zd ZU eed<   deeef   fd„Zy)Ú_PrismaEndUserRowrš   rv   c                  ó   — y rx   ry   rz   s    r|   r}   z_PrismaEndUserRow.dictþ   r~   r   NrÖ   ry   r   r|   rÚ   rÚ   û   s   … ØƒLà/�g˜c 6˜kÑ*Ô/r   rÚ   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú_end_user_tablerÝ     rÀ   r   c                   ó(   — e Zd Zededz  fd„«       Zy)Ú_PrismaMaxBudgetRowrv   Nc                  ó   — y rx   ry   rz   s    r|   Ú
max_budgetz_PrismaMaxBudgetRow.max_budget  s   € Ø*-r   )r€   r�   r‚   r    Úfloatrá   ry   r   r|   rß   rß     s   „ ØØ-˜E D™LÒ-ó Ù-r   rß   c                   óP   — e Zd ZU eed<   ededz  fd„«       Zededz  fd„«       Z	y)Ú _PrismaModelAccessGroupBudgetRowÚaccess_group_namerv   Nc                  ó   — y rx   ry   rz   s    r|   Úspendz&_PrismaModelAccessGroupBudgetRow.spend  s   € Ø%(r   c                  ó   — y rx   ry   rz   s    r|   Úlitellm_budget_tablez5_PrismaModelAccessGroupBudgetRow.litellm_budget_table  s   € ØBEr   )
r€   r�   r‚   rƒ   rˆ   r    râ   rç   rß   ré   ry   r   r|   rä   rä   
  s8   … ØÓàØ(�u˜t‘|Ò(ó Ø(àØEÐ&9¸DÑ&@ÒEó ÙEr   rä   c                 ó   — | j                   S rx   r½   r¾   s    r|   Ú _model_access_group_budget_tablerë     rÃ   r   c                   ó.   — e Zd Zedee   dz  fd„«       Zy)Ú_MemberModelScoperv   Nc                  ó   — y rx   ry   rz   s    r|   Úallowed_modelsz _MemberModelScope.allowed_models  s   € Ø69r   )r€   r�   r‚   r    r   rƒ   rï   ry   r   r|   rí   rí     s   „ ØØ9 ¨¡°Ñ 4Ò9ó Ù9r   rí   c                   ó(   — e Zd Zededz  fd„«       Zy)Ú_TeamMembershipModelScoperv   Nc                  ó   — y rx   ry   rz   s    r|   ré   z._TeamMembershipModelScope.litellm_budget_table   s   € Ø@Cr   )r€   r�   r‚   r    rí   ré   ry   r   r|   rñ   rñ     s   „ ØØCÐ&7¸$Ñ&>ÒCó ÙCr   rñ   Ú
membershipc                 óB   — | j                   }|€dS |j                  xs dS )zQThe member's own model scope, read through a narrowed view of the membership row.ry   )ré   rï   )ró   Úbudget_tables     r|   Ú_member_allowed_modelsrö   $  s(   € à$×9Ñ9€LØÐ%ˆ2ÐN¨L×,GÑ,GÒ,MÈ2ÐNr   c                   ó   — e Zd Zdedefd„Zy)Ú_RawCacheReadÚkeyrv   c             ƒ   ó   K  — y ­wrx   ry   )r{   rù   s     r|   Úasync_get_cachez_RawCacheRead.async_get_cache+  r³   rª   N)r€   r�   r‚   rƒ   r„   rû   ry   r   r|   rø   rø   *  s   „ Ø?¨CÐ?°FÔ?r   rø   Úcachec                 ó   — | S rx   ry   )rü   s    r|   Ú
_raw_cacherþ   .  s   € Ø€Lr   Úrequest_bodyc                 ó   — | S rx   ry   ©rÿ   s    r|   Ú_typed_request_bodyr  2  s   € ØÐr   c                   ó   — e Zd Zdedefd„Zy)Ú_JsonLoadsObjr°   rv   c                  ó   — y rx   ry   )r{   r°   s     r|   Ú__call__z_JsonLoadsObj.__call__7  r~   r   N)r€   r�   r‚   rƒ   r„   r  ry   r   r|   r  r  6  s   „ Ø0˜SÐ0 VÔ0r   r  Úfnc                 ó   — | S rx   ry   )r  s    r|   Ú_typed_json_loadsr	  :  s   € Ø€Ir   Ú_safe_json_loads_objéd   )Úmax_sizeÚlast_db_access_timeÚdb_cache_expiryÚ
all_routesÚentityÚerrorc                 óæ   ‡— t        |«      dk(  rt        |«      j                  dk(  ryt        |«      j                  «       Šd}t	        ˆfd„dD «       «      rd}t        j                  d| ||«       y)a  
    Log a warning when budget lookup fails; cache will not be populated.

    Skips logging for expected "user not found" cases (bare Exception from
    get_user_object when user_id_upsert=False). Adds a schema migration hint
    when the error appears schema-related.
    Ú Ú	ExceptionNc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wrx   ry   )Ú.0ÚxÚerr_strs     €r|   ú	<genexpr>z-_log_budget_lookup_failure.<locals>.<genexpr>T  s   øè ø€ Ò
]˜Aˆ1�Œ<Ñ
]ùó   ƒ)ÚcolumnÚschemazdoes not existÚprismaÚmigratezJ Run `prisma db push` or `prisma migrate deploy` to fix schema mismatches.zjBudget lookup failed for %s; cache will not be populated. Each request will hit the database. Error: %s.%s)rƒ   Útyper€   ÚlowerÚanyr   r  )r  r  Úhintr  s      @r|   Ú_log_budget_lookup_failurer#  G  sj   ø€ ô ˆ5ƒz�RÒœD ›K×0Ñ0°KÒ?ØÜ˜“Z×%Ñ%Ó'€GØ€DÜ
Ó
]Ð!\Ô
]Ô]Ø[ˆÜ×ÑØtØØØõ	r   Ú
llm_routerc                 óD   — t        | dd«      }t        |t        «      r|S dS )uA  
    Return the router's per-instance zero-cost cache, or ``None`` for objects
    that don't expose one (e.g. ``MagicMock`` stand-ins in unit tests).

    The cache lives on the ``Router`` instance so it:
        * is invalidated by ``Router._invalidate_model_group_info_cache`` on
          any model add/remove/upsert (including in-place pricing changes via
          ``/model/update``, which go through ``upsert_deployment``);
        * dies with the router itself â€” no risk of CPython reusing the
          previous router's ``id()`` and serving its cached entries.
    Ú_zero_cost_cacheN)ÚgetattrÚ
isinstancer}   )r$  rü   s     r|   Ú_get_router_zero_cost_cacher)  ^  s'   € ô ˜:Ð'9¸4Ó@€EÜ˜u¤dÔ+ˆ5Ð5°Ð5r   Úmodelc                 ól  — | �|€yt        | t        «      r| gn| }t        |«      }|D �][  }|�|j                  |«      }|�|du r yŒ 	 |j	                  |¬«      }|€t        j                  d|«       |�d||<    y|j                  }|j                  }|�|€!t        j                  d|||«       |�d||<    y|dkD  s|dkD  r!t        j                  d|||«       |�d||<    yt        |«      j                  dd	«      j                  d
d	«      }	t        ||«      st        j                  d|	«       |�d||<    yt        ||«      rt        j                  d|	«       |�d||<    yt        j                  d|	||«       |�d||<   �Œ^ y# t        $ r"}
t        j                  d||
«       Y d}
~
 yd}
~
ww xY w)aV  
    Check if a model has zero cost (no configured pricing).

    Uses the router's get_model_group_info method to get pricing information.

    Args:
        model: The model name or list of model names
        llm_router: The LiteLLM router instance

    Returns:
        bool: True if all costs for the model are zero, False otherwise
    NF©Úmodel_groupz6No model group info found for %s, assuming it has costzIModel %s has undefined cost (input: %s, output: %s), assuming it has costr   z2Model %s has non-zero cost (input: %s, output: %s)ú
r  úu{   Model %s has zero cost but no explicit cost configuration in model_cost entry â€” treating as unknown cost (enforce budget)zuModel %s prices reserved PTU capacity as a flat cost, so its zero per-token rate is not a free model (enforce budget)zDModel %s has zero cost explicitly configured (input: %s, output: %s)Tz:Error checking cost for model %s: %s, assuming it has cost)r(  rƒ   r)  ÚgetÚget_model_group_infor   ÚdebugÚinput_cost_per_tokenÚoutput_cost_per_tokenÚreplaceÚ_is_cost_explicitly_configuredÚ_has_ptu_flat_costr  )r*  r$  Ú
model_listÚzero_cost_cacheÚ
model_nameÚcachedÚmodel_group_infoÚ
input_costÚoutput_costÚ	safe_nameÚes              r|   Ú_is_model_cost_zerorA  n  s1  € ð €}˜
Ð*Øô $.¨e´SÔ#9˜™¸u€Jä8¸ÓD€Oà ó Rˆ
ØÐ&Ø$×(Ñ(¨Ó4ˆFØÐ!Ø˜U‘?Ù ØðK	à)×>Ñ>È:Ð>ÓVÐàÐ'ô %×*Ñ*Ð+cÐeoÔpØ"Ð.Ø27�O JÑ/Ùð *×>Ñ>ˆJØ*×@Ñ@ˆKð Ð! [Ð%8Ü$×*Ñ*Ø_ØØØô	ð #Ð.Ø27�O JÑ/Ùð ˜AŠ~ ¨q¢Ü$×*Ñ*ØHÈ*ÐV`Ðbmôð #Ð.Ø27�O JÑ/Ùô
 ˜J›×/Ñ/°°bÓ9×AÑAÀ$ÈÓKˆIÜ1°*¸jÔIÜ$×*Ñ*ð,ð ô	ð #Ð.Ø27�O JÑ/Ùä! *¨jÔ9Ü$×*Ñ*ð@àôð
 #Ð.Ø27�O JÑ/Ùä ×&Ñ&ØVØØØô	ð Ð*Ø.2� 
Ñ+ùð[Rðj øô ò 	ä ×&Ñ&Ð'cÐeoÐqrÔsÝûð	ús7   Á	1FÁ<;FÂ9)FÃ$AFÄ:)FÅ%FÆ	F3ÆF.Æ.F3Ú_NO_MODEL_INFOrk   c                 óÌ   — |j                   D ]U  }|j                  d«      | k7  rŒ|j                  d«      xs t        }|j                  d«      €ŒC|j                  d«      €ŒU y y)a  Whether any deployment in the model group bills reserved PTU capacity as a flat cost.

    Such a deployment carries an explicit zero per-token price so the flat cost is not charged
    twice, which otherwise reads here as a free model and waives every budget check for it.
    r:  Ú
model_infoÚ	ptu_countÚcost_per_ptu_per_hourTF)r8  r0  rB  )r*  r$  Ú
deploymentrD  s       r|   r7  r7  Þ  sf   € ð !×+Ñ+ò ˆ
Ø�>‰>˜,Ó'¨5Ò0ØØ—^‘^ LÓ1ÒC´^ˆ
Ø�>‰>˜+Ó&Ñ2°z·~±~ÐF]Ó7^Ñ7jÙðð r   c                 óì   — |j                   D ]e  }|j                  d«      | k7  rŒ|j                  di «      j                  d«      }|€Œ<t        j                  j                  |i «      }d|v sd|v sŒe y y)a¢  
    Check if any deployment in the model group has cost fields explicitly
    set in its litellm.model_cost entry.

    When Router._create_deployment() registers a model not in the global
    cost map, it creates a sparse entry like {"id": "<hash>"} with no cost
    fields. _get_model_info_helper() then defaults missing costs to 0.
    This function detects that scenario by checking the raw model_cost entry.
    r:  rD  Úidr3  r4  TF)r8  r0  ÚlitellmÚ
model_cost©r*  r$  rG  Úmodel_idÚ	raw_entrys        r|   r6  r6  í  s�   € ð !×+Ñ+ò ˆ
Ø�>‰>˜,Ó'¨5Ò0ØØ—>‘> ,°Ó3×7Ñ7¸Ó=ˆØÐØÜ×&Ñ&×*Ñ*¨8°RÓ8ˆ	Ø! YÑ.Ð2IÈYÒ2VÙðð r   Ú_EMPTY_COST_ENTRYr�   c                 ób   — t        | t        t        f«      xr t        | t        «       xr | dkD  S )Nr   )r(  r¶   râ   Úbool)r�   s    r|   Ú_is_positive_costrR    s,   € Ü�eœc¤5˜\Ó*ÒX´:¸eÄTÓ3JÐ/JÒXÈuÐWXÉyÐXr   Úentryc                 óâ   — | j                  d«      �y| j                  «       D ]J  \  }}d|vrŒt        |«      r yt        |t        «      sŒ)t        d„ |j                  «       D «       «      sŒJ y y)NÚtiered_pricingTÚcost_perc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wrx   )rR  )r  Únesteds     r|   r  z+_entry_has_priced_metric.<locals>.<genexpr>  s   è ø€ Ò*bÈÔ+<¸V×+DÑ*bùó   ‚F)r0  ÚitemsrR  r(  r}   r!  Úvalues)rS  rù   r�   s      r|   Ú_entry_has_priced_metricr\  
  sm   € Ø‡y�yÐ!Ó"Ð.ØØ—k‘k“mò ‰
ˆˆUØ˜SÑ ØÜ˜UÔ#ÙÜ�eœTÕ"¤sÑ*bÐSX×S_ÑS_ÓSaÔ*bÕ'bÙðð r   c                 ó&   — t        d„ | D «       «      S )Nc              3   ó2   K  — | ]  }d |v xs |dk(  –— Œ y­w)rV  rU  Nry   )r  rù   s     r|   r  z(_entry_declares_price.<locals>.<genexpr>  s#   è ø€ ÒMÀˆz˜SÐ Ò; CÐ+;Ñ$;Ó;ÑMùrY  ©r!  )rS  s    r|   Ú_entry_declares_pricer`    s   € ÜÑMÀuÔMÓMÐMr   c                 óH  — |j                  | ¬«      xs dD ]‰  }|j                  d«      xs t        }t        |«      r y|j                  d«      xs t        j                  d«      }|€ŒT|j	                  ||j                  d«      xs d¬	«      }|€Œ}t        |«      sŒ‰ y y
)a|  
    A model group counts as priced when a deployment overrides any *cost_per* field or
    tiered_pricing in its litellm_params, even at zero, or when its resolved model info carries
    tiered_pricing or a positive price on any billed metric (tokens, characters, seconds, pages,
    images, queries, ...), so models billed by a non-token metric are not treated as unpriced.
    ©r:  ry   Úlitellm_paramsTrD  rI  r*  r  )rM  r:  F)Úget_model_listr0  rO  r`  Úget_deployment_model_infor\  )r*  r$  rG  rc  rM  rD  s         r|   Ú_model_group_has_pricingrf    s°   € ð !×/Ñ/¸5Ð/ÓAÒGÀRò ˆ
Ø#Ÿ™Ð(8Ó9ÒNÔ=NˆÜ  Ô0Ùà—N‘N <Ó0ÒEÔ4E×JÑJÈ4ÓPˆØÐØà×9Ñ9Ø¨.×*<Ñ*<¸WÓ*EÒ*KÈð :ó 
ˆ
ð Ñ!Ô&>¸zÕ&JÙðð r   c                 óì   — |j                  | ¬«      xs dD ][  }|j                  d«      xs t        j                  d«      }|€Œ.t        j                  j                  |t        «      }d|v sd|v sŒ[ y y)	aº  
    Alias-aware counterpart to ``_is_cost_explicitly_configured``, which resolves the model group
    the same way ``_model_group_has_pricing`` does. A deployment that prices itself through its
    ``model_info`` block lands in the cost map under its deployment id rather than in its
    litellm_params, and reaching that entry through the router's own resolution keeps an alias
    pointing at such a group from being read as unpriced.
    rb  ry   rD  rI  r3  r4  TF)rd  r0  rO  rJ  rK  rL  s        r|   Ú_group_declares_explicit_costrh  4  s   € ð !×/Ñ/¸5Ð/ÓAÒGÀRò ˆ
Ø—N‘N <Ó0ÒEÔ4E×JÑJÈ4ÓPˆØÐØÜ×&Ñ&×*Ñ*¨8Ô5FÓGˆ	Ø! YÑ.Ð2IÈYÒ2VÙðð r   c                 ój   — | r|€y|j                  | ¬«      €yt        | |¬«      ryt        | |¬«       S )NFr,  ©r*  r$  )r1  rf  rh  rj  s     r|   Úmodel_has_no_cost_mappingrk  F  sA   € Ù�JÐ&Øà×&Ñ&°5Ð&Ó9ÐAØä e¸
ÕCØä,°5ÀZÔPÐPÐPr   .c                 óp   ‡— t        | t        «      r| fnt        | xs d«      }t        ˆfd„|D «       «      S )Nry   c              3   ó>   •K  — | ]  }t        |‰¬ «      sŒ|–— Œ y­w)rj  N)rk  )r  Ú	candidater$  s     €r|   r  z._unpriced_models_in_request.<locals>.<genexpr>U  s"   øè ø€ ò ØÔ1JÐQZÐgqÖ1rŒ	ñùs   ƒ–)r(  rƒ   r—   )r*  r$  Ú
candidatess    ` r|   Ú_unpriced_models_in_requestrp  S  s8   ø€ Ü$.¨u´cÔ$:˜™ÄÀeÂkÈrÓ@R€JÜó Ø#-ôó ð r   Úmodelsc                 óp   — dj                  d„ | D «       «      }t        | «      dk(  rd|› d�nd|› d�}|› d�S )	Nz, c              3   ó(   K  — | ]
  }d |› d �–— Œ y­w)ú'Nry   )r  r*  s     r|   r  z1_unpriced_models_block_message.<locals>.<genexpr>[  s   è ø€ Ò>¨e˜q   qœ\Ñ>ùs   ‚rn   zModel z haszModels z havezù no pricing in the cost map, so litellm cannot price the request. Requests for unpriced models are blocked because 'block_requests_for_models_without_pricing' is enabled. Add pricing (input_cost_per_token/output_cost_per_token) to allow the request.)ÚjoinÚlen)rq  ÚnamesÚsubjects      r|   Ú_unpriced_models_block_messagery  Z  sQ   € Ø—9‘9Ñ>°vÔ>Ó>€EÜ-0°«[¸AÒ-=�v˜e˜W DÑ)ÀWÈUÈGÐSXÐCY€Gàˆ)ð eð 	eðr   Úproject_objectÚ_modelÚskip_budget_checksÚvalid_tokenÚproxy_logging_objc              ƒ   ó  K  — | €y| j                   du rt        d| j                  › d�«      ‚|r&t        | j                  «      dkD  rt        || |¬«       |s-t        | ||¬«      ƒ d{  –—†  t        | ||¬«      ƒ d{  –—†  yy7 Œ7 Œ­w)zš
    Run all project-level checks: blocked, model access, budget, soft budget.
    Extracted from common_checks() to keep statement count manageable.
    NTzProject=z= is blocked. Update via `/project/update` if you're an admin.r   ©r*  rz  r$  )rz  r}  r~  )Úblockedr  Ú
project_idrv  rq  Úcan_project_access_modelÚ_project_max_budget_checkÚ_project_soft_budget_check©rz  r{  r$  r|  r}  r~  s         r|   Ú_run_project_checksr‡  d  s·   è ø€ ð ÐØð ×Ñ Ñ%ÜØ�~×0Ñ0Ð1Ð1nÐoó
ð 	
ñ
 ”#�n×+Ñ+Ó,¨qÒ0Ü ØØ)Ø!õ	
ñ ä'Ø)Ø#Ø/ô
÷ 	
ð 	
ô )Ø)Ø#Ø/ô
÷ 	
ñ 	
ð ð	
øð	
ús$   ‚A&B	Á(BÁ)B	Á>BÁ?B	ÂB	Úgeneral_settingsÚrequestÚroutec                 óŽ  — | j                  dd«      sy t        |d«      r|j                  nd }|xr |j                  «       dk(  }t	        j
                  |¬«      }|t        j                  j                  v xs/ t	        j                  |t        j                  j                  ¬«      }|r|r|sd|vrt        d| d   › �«      ‚y y y y )	NÚenforce_user_paramFÚmethodÚPOST©rŠ  )rŠ  Úallowed_routesÚuserz1'user' param not passed in. 'enforce_user_param'=)r0  Úhasattrr�  Úupperr@   Úis_llm_api_router6   Ú
mcp_routesr�   Úcheck_route_accessr  )rˆ  r‰  rÿ   rŠ  Úhttp_methodÚis_post_methodÚis_openai_routeÚis_mcp_routes           r|   Ú_enforce_user_param_checkr›  ‘  sÅ   € Ø×ÑÐ 4°eÔ<Øä+2°7¸HÔ+E˜ŸšÈ4€KØ'ÒI¨K×,=Ñ,=Ó,?À6Ñ,I€NÜ(×9Ñ9ÀÔF€OØ¤=×#;Ñ#;×#AÑ#AÐAò Ä[×EcÑEcØ¤M×$<Ñ$<×$BÑ$BôF€Lñ ™/±,À6ÐQ]ÑC]ÜÐKÐL\Ð]qÑLrÐKsÐtÓuÐuð D^°,˜/€~r   c                 óü   — | j                  dd«      sy t        j                  |¬«      rSd|v rNt        |d   t        «      r:d|d   v r2t        d| d   › d�t        j                  dt        j                  ¬	«      ‚y y y y )
NÚreject_clientside_metadata_tagsFr�  ÚmetadataÚtagszVClient-side 'metadata.tags' not allowed in request. 'reject_clientside_metadata_tags'=z,. Tags can only be set via API key metadata.zmetadata.tags©Úmessager  ÚparamÚcode)
r0  r@   r”  r(  r}   r:   r9   Úbad_request_errorr   ÚHTTP_400_BAD_REQUEST)rˆ  rÿ   rŠ  s      r|   Ú&_reject_clientside_metadata_tags_checkr¦     s¨   € Ø×ÑÐ AÀ5ÔIØô 	×$Ñ$¨5Õ1Ø˜,Ñ&Ü�| JÑ/´Ô6Ø�l :Ñ.Ñ.äØlÐm}ð  `ñ  nað  mbð  bNð  OÜ ×2Ñ2Ø!Ü×,Ñ,ô	
ð 	
ð /ð 7ð 'ð 	2r   Úglobal_proxy_spendc                 óh  — t         j                  dkD  rŸ|sœ| �™t        j                  |¬«      r‚|dk7  r||dk7  rvt	        j
                  t         j                  «      rR| t         j                  kD  r>t        j                  | t         j                  t        j                  j                  ¬«      ‚y y y y y y y y )Nr   r�  ú
/v1/modelsú/models)Úcurrent_costrá   Úentity_type)
rJ  rá   r@   r”  ÚmathÚisfiniteÚBudgetExceededErrorr*   ÚPROXYr�   )r§  r|  rŠ  s      r|   Ú_global_proxy_budget_checkr±  ²  s¬   € ä×Ñ˜QÒÙ"ØÐ*Ü×(Ñ(¨uÕ5Ø�\Ò!Ø�YÒä�=‰=œ×+Ñ+Ô,Ð1CÄg×FXÑFXÒ1XÜ×-Ñ-Ø/Ü"×-Ñ-Ü.×4Ñ4×:Ñ:ôð ð 2YÐ,ð ð "ð 6ð +ð #ð 	r   )Ú
guardrailsÚdisable_global_guardrailsÚdisable_global_guardrailÚopted_out_global_guardrailsÚ_GUARDRAIL_MODIFICATION_KEYSÚteam_objectc                 ó  ‡— ddl m} dt        dt        dz  fd„Šdt        dt        fˆfd„} || j                  d«      «      xs!  || j                  d	«      «      xs  || «      }|sy ||«      st        d
ddi¬«      ‚y)a†  
    Reject user-supplied metadata flags that would modify guardrail behavior
    unless the team has explicit permission. Checked keys include the plural
    ``guardrails`` list plus the per-request toggles that influence whether
    default-on guardrails run (``disable_global_guardrails``,
    ``disable_global_guardrail`` singular, and ``opted_out_global_guardrails``).

    User-supplied values for the bypass toggles are also silently ignored by
    ``_get_admin_metadata`` at read time; this check adds defense in depth by
    failing loudly at the auth layer so operators see an explicit 403 instead
    of a confusing silent-ignore.
    r   )Úcan_modify_guardrailsÚ	containerrv   Nc                 ó†   — t        | t        «      r| S t        | t        «      rt        | «      }t        |t        «      r|S dS y)u¤  Accept dict or JSON-string (from multipart/form-data or extra_body).

        Without this, an attacker can smuggle guardrail keys past the check by
        sending ``{"metadata": "{\"disable_global_guardrails\": true}"}`` â€”
        ``isinstance(dict)`` on the string returns False, the check returns
        no-modification, and ``add_litellm_data_to_request`` parses the string
        to a dict downstream.
        N)r(  r}   rƒ   r
  )rº  Úparseds     r|   Ú_coerce_to_dictz6_guardrail_modification_check.<locals>._coerce_to_dictÚ  s?   € ô �i¤Ô&ØÐÜ�i¤Ô%Ü0°Ó;ˆFÜ'¨´Ô5�6Ð?¸4Ð?Ør   c                 óL   •‡—  ‰| «      Š‰€yt        ˆfd„t        D «       «      S )NFc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wrx   ry   )r  rù   Úcoerceds     €r|   r  zV_guardrail_modification_check.<locals>._user_requested_modification.<locals>.<genexpr>î  s   øè ø€ ÒJ c�3˜'”>ÑJùr  )r!  r¶  )rº  rÀ  r½  s    @€r|   Ú_user_requested_modificationzC_guardrail_modification_check.<locals>._user_requested_modificationê  s'   ù€ Ù(¨Ó3ˆØˆ?ØÜÓJÔ-IÔJÓJÐJr   rž  Úlitellm_metadatai“  r  z8Your team does not have permission to modify guardrails.©Ústatus_codeÚdetail)Ú*litellm.proxy.guardrails.guardrail_helpersr¹  r„   r}   rQ  r0  r   )rÿ   r·  r¹  rÁ  Úmodifiesr½  s        @r|   Ú_guardrail_modification_checkrÈ  Ë  s¤   ø€ õ Qð¤6ð ¬d°T©kó ð K´ð K¼4õ Kñ 	% \×%5Ñ%5°jÓ%AÓBò 	6Ù'¨×(8Ñ(8Ð9KÓ(LÓMò	6á'¨Ó5ð ñ
 Øá  Ô-ÜØØÐWÐXô
ð 	
ð .r   c              ƒ   óº  K  — ddl m} |€y ||«      }|rt        d„ |D «       «      syt        || «      }|syt	        |j
                  t        «      r|j
                  xs i ni }t	        |j                  t        «      r|j                  xs i ni }|j                  d«      }	|j                  d«      }
t	        |	t        «      rt        |	«      dkD  r|	n|
}t	        |t        «      rt        |«      dk(  ry|D �ch c]  }t        |«      ’Œ }}|D �cg c]	  }||vsŒ|‘Œ }}|r/t        d|› d�t        j                  dt        j                   ¬	«      ‚yc c}w c c}w ­w)
uþ   
    Enforce key/team tool allowlist (metadata.allowed_tools). No DB in hot path â€”
    effective allowlist is read from valid_token.metadata and valid_token.team_metadata.
    Raises ProxyException with tool_access_denied if a tool is not allowed.
    r   )Úget_call_types_for_routeNc              3   ó@   K  — | ]  }|j                   t        v –— Œ y ­wrx   )r�   rU   )r  Úcts     r|   r  z(check_tools_allowlist.<locals>.<genexpr>  s   è ø€ Ò ZÈ §¡Ô-DÔ!DÑ Zùs   ‚Úallowed_toolszTool(s) z5 are not in the allowed tools list for this key/team.Útoolsr   )Ú2litellm.litellm_core_utils.api_route_to_call_typesrÊ  r!  rV   r(  rž  r}   Úteam_metadatar0  Úlistrv  rƒ   r:   r9   Útool_access_deniedr   ÚHTTP_403_FORBIDDEN)rÿ   r}  r·  rŠ  rÊ  Ú
call_typesÚ
tool_namesÚkey_metaÚ	team_metaÚkey_allowedÚteam_allowedÚ	effectiveÚtÚallowed_setÚnÚ
disalloweds                   r|   Úcheck_tools_allowlistrß    sM  è ø€ õð ÐØÙ0°Ó7€JÙœSÑ ZÈzÔ ZÔZØÜ2°5¸,ÓG€JÙØÜ6@À×AUÑAUÔW[Ô6\�{×+Ñ+Ò1©rÐbd€HÜ<FÀ{×G`ÑG`ÔbfÔ<g˜×1Ñ1Ò7±RÐmo€IØ!Ÿ™ oÓ6€KØ#Ÿ-™-¨Ó8€LÜ'1°+¼tÔ'DÌÈ[ÓIYÐ\]ÒI]‘{Ðdp€IÜ�i¤Ô&¬#¨i«.¸AÒ*=ØØ*3Ö4 Qœ#˜a�&Ð4€KÐ4Ø$.ÖG˜q°!¸;Ò2FšÐG€JÐGÙÜØ˜z˜lÐ*_Ð`Ü ×3Ñ3ØÜ×*Ñ*ô	
ð 	
ð ùò 5ùÚGùs$   ‚C5EÃ7EÄ	EÄ	EÄEÄ>E>   ú/model/infoú/v1/model/infoú/v2/model/infoú/model_group/inforª  r©  ÚMODEL_DISCOVERY_ROUTES>   ú/healthú/health/servicesú/health/test_connectionÚ"BUDGET_ENFORCED_SIDE_EFFECT_ROUTESÚuser_objectÚend_user_objectc              ƒ   óT  ‡‡‡‡‡ ‡!K  — ddl mŠ mŠ! t        | |t	        |
¬«      t        |
¬«      ||
¬«      }|xs+ |t        vxr! |t        v xs t        j                  |¬«       }t        j                  r#t        j                  |¬«      rt        ||¬«      nd}|r4t        t        |«      t        j                   dt"        j$                  ¬	«      ‚‰�'‰j&                  du rt)        d‰j*                  › d�«      ‚|rF‰rDt-        j.                  d«      5  	 t1        |‰||	r|	j2                  nd
¬«      ƒ d
{  –—†  d
d
d
«       |rH‰rF|	rD|	j:                  r8t-        j.                  d«      5  t=        |‰|	|‰ ‰!‰¬«      ƒ d
{  –—†  d
d
d
«       |	�¡|	j>                  r•ddl m!} ddl"m#} |jI                  |	j>                  ¬«      }|�k|jJ                  xs i jM                  d«      }|rJtO        |
jP                  «      } ||«      }|s+t        dt        jR                  d
t"        jT                  ¬	«      ‚|r8‰€6‰�4t-        j.                  d«      5  tW        ||‰¬«      ƒ d
{  –—†  d
d
d
«       t-        j.                  d«      5  tY        |||||	‰¬«      ƒ d
{  –—†  d
d
d
«       t[        ||	‰||‰ ‰!‰¬«      ƒ d
{  –—† }t]        ‰| |«       |�s/|	�,ddl"m/} |ja                  | |¬«       |jc                  | |	¬«       d7ˆˆˆfd!„}te        d"„ tg        ‰‰|	¬#«      ti        ‰¬$«      |	�tk        |	¬%«      nd
tm        ‰‰|	¬#«      to        |	‰‰ ‰!‰¬&«      tq        | ‰ ‰!‰|	¬'«      |rts        |‰ ‰!¬(«      nd
 |«       tu        ‰‰|	‰ ‰!‰¬)«      |�|jv                  �ty        ||¬*«      nd
f
D «       «      }t-        j.                  d+«      5  t{        j|                  |d,diŽƒ d
{  –—† }d
d
d
«       t        d-„ D «       d
«      }|�|‚t�        ‰|
| |«       tƒ        |||«       t…        t‡        | «      ‰«       t‰        ‰|| ¬.«       d/tŠ        d tŠ        d
z  fˆ ˆˆ!fd0„}t�        || |t�        |
«      ¬1«      ƒ d
{  –—† }t‘        ||
||	‰¬2«      }t-        j.                  d3«      5  t“        | ‰|	¬4«      ƒ d
{  –—†  d
d
d
«       t-        j.                  d5«      5  t•        | |	‰|¬6«      ƒ d
{  –—†  d
d
d
«       y7 �Œ´# t        $ rB}|j4                  t        j6                  k7  r‚ t9        ||	‰|¬«      ƒ d
{  –—†7  s‚ Y d
}~�Œød
}~ww xY w# 1 sw Y   �ŒxY w7 �ŒÈ# 1 sw Y   �ŒÈxY w7 �Œû# 1 sw Y   �ŒûxY w7 �ŒÔ# 1 sw Y   �ŒÔxY w7 �ŒÁ7 �Œ¤# 1 sw Y   �Œ¤xY w7 �Œ 7 Œæ# 1 sw Y   ŒåxY w7 Œ¿# 1 sw Y   yxY w­w)8aì  
    Common checks across jwt + key-based auth.

    1. If team is blocked
    1.1. If project is blocked
    2. If team can call model
    2.2 If project can call model
    2.3 Which model access groups authorized this request
    3. If team is in budget
    3.0.2. If project is in budget
    3.0.3. If project is over soft budget (alert only)
    4. If user passed in (JWT or key.user_id) - is in budget
    5. If end_user (either via JWT or 'user' passed to /chat/completions, /embeddings endpoint) is in budget
    6. [OPTIONAL] If 'enforce_end_user' enabled - did developer pass in 'user' param for openai endpoints
    7. [OPTIONAL] If 'litellm.max_budget' is set (>0), is proxy under budget
    8. [OPTIONAL] If guardrails modified - is request allowed to change this
    9. Check if request body is safe
    10. [OPTIONAL] Organization checks - is user_object.organization_id is set, run these checks
    11. [OPTIONAL] Vector store checks - is the object allowed to access the vector store
    r   ©Úprisma_clientÚuser_api_key_cache)r‰  )Úrequest_datarŠ  Úrequest_headersÚrequest_query_paramsr$  r‰  r�  rj  ry   r*  r   NTzTeam=z; is blocked. Update via `/team/unblock` if you're an admin.z6litellm.proxy.auth.common_checks.can_team_access_model©r*  r·  r$  Úteam_model_aliases©r*  r}  r·  r$  z?litellm.proxy.auth.common_checks.check_team_member_model_access©r*  r·  r}  r$  rí  rî  r~  )Úglobal_agent_registry)Úget_chain_id_from_headers)Úagent_idÚ"require_trace_id_on_calls_by_agentzORequests made with this agent's key must include the x-litellm-trace-id header.z4litellm.proxy.auth.common_checks.can_user_call_model©r*  r$  ré  z3litellm.proxy.auth.common_checks.run_project_checksr†  ©r*  r}  r·  rz  r$  rí  rî  r~  )ÚLiteLLMProxyRequestSetup)rï  rŠ  )rï  Úuser_api_key_dictrv   c            
   “   óØ  •K  — ‰�‰j                   €y ‰d uxr ‰j                  d u} | r‰j                  d«      dury ddlm} ‰j                   } |d‰j
                  › �‰j                  xs d|¬«      ƒ d {  –—† }t        j                  |«      rU||k\  rOt        j                  ||d‰j
                  › d	|› d
|› �t        j                  j                  ‰j
                  ¬«      ‚y y 7 Œo­w)NÚapply_user_budget_to_team_keysTr   ©Úget_current_spendzspend:user:ç        ©Úcounter_keyÚfallback_spendrá   zExceededBudget: User=ú over budget. Spend=ú	, Budget=©r«  rá   r¡  r¬  Ú	entity_id)rá   Úteam_idr0  Úlitellm.proxy.proxy_serverr  rš   rç   r­  r®  rJ  r¯  r*   ÚUSERr�   )Úis_team_keyr  Úuser_budgetÚ
user_spendrˆ  r·  ré  s       €€€r|   Ú_user_max_budget_checkz-common_checks.<locals>._user_max_budget_checkí  s  øè ø€ àÐ" k×&<Ñ&<Ð&DØØ!,°DÐ!8Ò!\¸[×=PÑ=PÐX\Ð=\ˆKÙÐ/×3Ñ3Ð4TÓUÐ]aÑaØåDà!,×!7Ñ!7ˆKÙ&7Ø)¨+×*=Ñ*=Ð)>Ð?Ø*×0Ñ0Ò7°CØ&ô'÷ !ˆJô
 �}‰}˜[Ô)¨j¸KÒ.GÜ×1Ñ1Ø!+Ø*Ø3°K×4GÑ4GÐ3HÐH\Ð]gÐ\hÐhqÐr}Ðq~ÐÜ 2× 7Ñ 7× =Ñ =Ø)×1Ñ1ôð ð /HÐ)ð!ús   ƒA5C*Á8C(Á9A0C*c              3   ó$   K  — | ]  }|�|–— Œ
 y ­wrx   ry   )r  Úcoros     r|   r  z common_checks.<locals>.<genexpr>  s"   è ø€ ò 2*
àð^ Ðôa ñ2*
ùs   ‚)r·  r~  r}  )r·  ©r}  ©r}  r·  rí  rî  r~  )rÿ   rí  rî  r~  r}  )Úmatched_model_access_groupsrí  rî  )r·  ré  r}  rí  rî  r~  )Úend_user_objrŠ  z.litellm.proxy.auth.common_checks.budget_checksÚreturn_exceptionsc              3   óB   K  — | ]  }t        |t        «      sŒ|–— Œ y ­wrx   )r(  ÚBaseException)r  Úrs     r|   r  z common_checks.<locals>.<genexpr>A  s   è ø€ Ò#^¨!ÄÈAÌ}ÕA]¤AÑ#^ùó   ‚˜)ré  rŠ  rÿ   r
  c              “   óv   •K  — 	 t        | ‰‰‰¬«      ƒ d {  –—† }|j                  S 7 Œ# t        $ r Y y w xY w­w)N)r
  rí  rî  r~  )Úget_team_objectr   Úorganization_id)r
  Úteamrí  r~  rî  s     €€€r|   Ú_fetch_team_org_idz)common_checks.<locals>._fetch_team_org_idL  sM   øè ø€ ð	Ü /ØØ+Ø#5Ø"3ô	!÷ ˆDð ×#Ñ#Ð#ðùô ò 	Ùð	üs(   ƒ9…* —(˜* œ9¨* ª	6³9µ6¶9)rŠ  rÿ   Úfetch_team_org_idÚroute_template)rŠ  r‰  rï  r}  Úuser_objz:litellm.proxy.auth.common_checks.vector_store_access_check)rÿ   r·  r}  z6litellm.proxy.auth.common_checks.check_tools_allowlist)rÿ   r}  r·  rŠ  )rv   N)Kr  rí  rî  rq   rB   rC   rè  rä  r@   r”  rJ  Ú)block_requests_for_models_without_pricingrp  r:   ry  r9   Úmodel_cost_map_missingr   rÓ  r�  r  r
  r"   ÚtraceÚcan_team_access_modelró  r  Úteam_model_access_deniedÚ_key_access_group_grants_modelrš   Ú_check_team_member_model_accessrø  Ú,litellm.proxy.agent_endpoints.agent_registryrö  Ú$litellm.proxy.litellm_pre_call_utilsr÷  Úget_agent_by_idrc  r0  r}   Úheadersr¤  r¥  Úcan_user_call_modelr‡  Ú!stamp_matched_model_access_groupsr¦  rü  Ú#pre_seed_litellm_metadata_for_routeÚapply_key_tags_pre_authr—   Ú_team_max_budget_checkÚ_team_multi_budget_checkÚ_virtual_key_multi_budget_checkÚ_team_soft_budget_checkÚ_organization_max_budget_checkÚ_tag_max_budget_checkÚ$_model_access_group_max_budget_checkÚ_check_team_member_budgetré   Ú_check_end_user_budgetÚasyncioÚgatherÚnextr›  r±  rÈ  r  rp   rƒ   ro   rr   Ú_is_api_route_allowedÚvector_store_access_checkrß  )"rÿ   r·  ré  rê  r§  rˆ  rŠ  r$  r~  r}  r‰  r|  rz  r{  Úskip_all_budget_checksÚunpriced_modelsÚteam_denialrö  r÷  ÚagentÚrequire_trace_idÚheaders_dictÚtrace_idr  rü  r  Úbudget_check_corosÚbudget_resultsÚbudget_errorr   Úrequest_body_for_route_checkÚ_is_route_allowedrí  rî  s"    ``  `  `                       @@r|   Úcommon_checksrM  @  sI  ýè ø€ ÷F Mä,BØ!ØÜ1¸'ÔBÜ;ÀGÔLØØô-€Fð %7ò %ØÔ7Ð7ò 	_ØÔ,Ð,Ò]´K×4PÑ4PÐW\Ô4]Ð0]ð ô ×<Ò<Ä×A]ÑA]ÐdiÕAjô 	$¨&¸ZÕHàð ñ
 ÜÜ2°?ÓCÜ ×7Ñ7ØÜ×*Ñ*ô	
ð 	
ð Ð ;×#6Ñ#6¸$Ñ#>Ü˜% × 3Ñ 3Ð4Ð4oÐpÓqÐqñ ‘+Ü�\‰\ÐRÓSñ 	ðÜ+Ø Ø +Ø)ÙJU¨×(FÒ(FÐ[_ô	÷ ð ÷	ñ( ‘+¡+°+×2EÒ2EÜ�\‰\Ð[Ó\ñ 		Ü1ØØ'Ø'Ø%Ø+Ø#5Ø"3ô÷ ð ÷		ð Ð ;×#7Ò#7ÝVÝRà,×<Ñ<Àk×FZÑFZÐ<Ó[ˆØÐØ',×';Ñ';Ò'A¸r×&FÑ&FÐGkÓ&lÐÙÜ&*¨7¯?©?Ó&;�Ù";¸LÓ"I�ÙÜ(Ø qÜ,×>Ñ>Ø"Ü#×8Ñ8ô	ð ñ �+Ð%¨+Ð*AÜ�\‰\ÐPÓQñ 	Ü%ØØ%Ø'ô÷ ð ÷	ô 
�‰ÐKÓ	Lñ 
Ü!Ø)ØØ!Ø5Ø#Ø/ô
÷ 	
ð 	
÷
ô 0QØØØØ%ØØ#Ø-Ø+ô	0÷ 	*Ðô +Ð+;¸\È5ÔQò "ð Ð"ÝUà$×HÑHØ)Øð Iô ð
 %×<Ñ<Ø)Ø"-ð =ô ÷
	ô< %*ñ 2*
ô 'Ø +Ø&7Ø +ôô
 )°[ÔAØLWÐLcÔ/¸KÕHÐimÜ'Ø +Ø&7Ø +ôô
 /Ø +Ø +Ø"/Ø'9Ø&7ôô &Ø!-Ø"/Ø'9Ø&7Ø +ôñ /ô 5Ø0KØ"/Ø'9õð Ù&Ó(Ü)Ø +Ø +Ø +Ø"/Ø'9Ø&7ôð #Ð.°?×3WÑ3WÐ3cô '°OÈ5ÕQàð[.ô2*
ó 2%
Ðôh �\‰\ÐJÓKñ 	fÜ*1¯.©.Ð:LÐ*eÐ`dÑ*e×$eˆN÷	fä"Ñ#^¨~Ô#^Ð`dÓeˆØÐ#ØÐäÐ.°¸ÀuÔMÜÐ1Ð3IÈ5ÔQÜ!Ô"5°lÓ"CÀ[ÔQô )°[ÈÐ\hÕið
$¬#ð 
$´#¸±*÷ 
$ô 1UØØ!Ø,Ü1°'Ó:ô	1÷ +Ð ô  5ØØØ1ØØô Ðô 
�‰ÐRÓ	Sñ 
Ü'Ø%Ø#Ø#ô
÷ 	
ð 	
÷
ô 
�‰ÐNÓ	Oñ 
Ü#Ø%Ø#Ø#Øô	
÷ 	
ð 	
÷
ð ðaúô "ò 	Ø×#Ñ#¤×'OÑ'OÒOØÜ;Ø Ø +Ø +Ø)ô	÷ ñ ð õûð	ú÷	ñ 	úð,ù÷		ñ 		úðBù÷	ñ 	úð	
ù÷
ñ 
úð	*ùðd %fù÷	fñ 	fúð2+ùð"	
ø÷
ð 
úð	
ø÷
ð üsw  ˆD
V(ÄT9Ä S+Ä4S(Ä5S+Ä9/V(Å(U	Å>UÅ?U	ÆCV(É	UÉUÉUÉ V(É=U)ÊU&ÊU)ÊV(Ê5U6Ê6DV(Î<U<ÏU9ÏU<ÏBV(Ñ)V	Ñ*)V(ÒVÒ%VÒ&VÒ*V(ÓVÓVÓVÓ	V(Ó(S+Ó+	T6Ó40T1Ô$T'Ô%T1Ô+T9Ô1T6Ô6T9Ô9UÔ>V(ÕU	Õ	UÕV(ÕUÕU#ÕV(Õ&U)Õ)U3Õ.	V(Õ9U<Õ<VÖ	V(ÖVÖVÖV(ÖVÖV%Ö!V(r#  c                 ó~   — | €y | }|j                   }	 t        |«      }|S # t        $ r t        j                  cY S w xY wrx   )Ú	user_roler7   Ú
ValueErrorÚINTERNAL_USER)r#  Ú_userÚ
_user_roleÚroles       r|   Ú_get_user_rolerU  {  sN   € ð ÐØà€EàŸ™€Jð.Ü& zÓ2ˆð €Køô ò .Ü×-Ñ-Ò-ð.ús   “   <»<rï  c                 ó„   — t        |¬«      }|€t        d«      ‚t        |¬«      st        j                  ||| |||¬«       y)z<
    - Route b/w api token check and normal token check
    ©r#  z4Invalid proxy server token passed. valid_token=None.)r#  rS  rŠ  r‰  rï  r}  T)rU  r  Ú_is_user_proxy_adminr@   Ú$non_proxy_admin_allowed_routes_check)rŠ  r‰  rï  r}  r#  rS  s         r|   r?  r?  Œ  sM   € ô '°Ô9€JàÐÜÐNÓOÐOä¨Õ2Ü×8Ñ8ØØ!ØØØ%Ø#õ	
ð r   c                 ór   — | €y| j                   �(| j                   t        j                  j                  k(  ryy)NFT)rO  r7   ÚPROXY_ADMINr�   rW  s    r|   rX  rX  §  s7   € ØÐØà×ÑÐ%¨(×*<Ñ*<Ô@P×@\Ñ@\×@bÑ@bÒ*bØàr   Ú
user_router�  c                 óæ   — ddl m} |D ]f  }|t        j                  v r9t        |   j                  D ]"  } ||«      \  }}}|j                  | «      sŒ!  y ŒNt        j                  | |¬«      sŒf y y)a‘  
    Return if a user is allowed to access route. Helper function for `allowed_routes_check`.

    Parameters:
    - user_route: str - the route the user is trying to call
    - allowed_routes: List[str|LiteLLMRoutes] - the list of allowed routes for the user. Entries are a route group name
      (e.g. "openai_routes"), an exact route, or a trailing-wildcard prefix (e.g. "/internal-models/*").
    r   )Úcompile_pathT)rŠ  ÚpatternF)Ústarlette.routingr^  r6   Ú__members__r�   Úmatchr@   Úroute_matches_wildcard_pattern)r\  r�  r^  Úallowed_routeÚtemplateÚregexÚ_s          r|   Ú_allowed_routes_checkrh  ±  sx   € õ /à'ò ˆØœM×5Ñ5Ñ5Ü)¨-Ñ8×>Ñ>ò  �Ù*¨8Ó4‘��q˜!Ø—;‘;˜zÕ*Úñ ô ×7Ñ7¸jÐR_Ö`Ùðð r   rO  Úlitellm_proxy_rolesc                 ó  — | t         j                  k(  rt        ||j                  ¬«      }|S | t         j                  k(  rC|j
                  €	 t        |ddg¬«      }|S |j
                  �t        ||j
                  ¬«      }|S y)zE
    Check if user -> not admin - allowed to access these routes
    )r\  r�  Úopenai_routesÚinfo_routesF)r7   r[  rh  Úadmin_allowed_routesÚTEAMÚteam_allowed_routes)rO  r\  ri  Ú
is_alloweds       r|   Úallowed_routes_checkrq  Ç  s™   € ð Ô$×0Ñ0Ò0Ü*Ø!Ø.×CÑCô
ˆ
ð Ðà	Ô&×+Ñ+Ò	+Ø×2Ñ2Ð:ðô /¸*ÐVeÐgtÐUuÔvˆJØÐØ ×4Ñ4Ð@Ü.Ø%Ø2×FÑFôˆJð ÐØr   rý  Úrequested_user_idc                 óÀ   — d}| j                   t        j                  k7  r| j                   t        j                  k7  rd}|�| j                  �| j                  |k(  rd}|S )NTF)rO  r7   r[  ÚPROXY_ADMIN_VIEW_ONLYrš   )rý  rr  Úret_vals      r|   Ú allowed_route_check_inside_routerv  ç  sc   € ð €Gà×#Ñ#Ô'7×'CÑ'CÒCØ×'Ñ'Ô+;×+QÑ+QÒQàˆØÐ$Ð):×)BÑ)BÐ)NØ×$Ñ$Ð(9Ò9ØˆGØ€Nr   c                 óø   — g }| D ]R  }	 t         |   j                  }t        |t        «      r|j	                  t        |«      «       n|j	                  |«       ŒT |S # t        $ r |j                  |«       Y Œsw xY wrx   )r6   r�   r(  ÚsetÚextendrÑ  ÚKeyErrorÚappend)r�  Úactual_routesÚ
route_nameÚroute_values       r|   Úget_actual_routesr  ÷  s~   € Ø!#€MØ$ò 	-ˆ
ð	-Ü'¨
Ñ3×9Ñ9ˆKÜ˜+¤sÔ+Ø×$Ñ$¤T¨+Ó%6Õ7à×$Ñ$ [Ô1øð	-ð Ðøô ò 	-Ø× Ñ  Ö,ð	-ús   ‰AAÁA9Á8A9rí  rî  Úparent_otel_spanc              ƒ   óf  K  — | �t         j                  €ydt         j                  › �}|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 t	        t        | «      «      j                  dt         j                  i¬«      ƒ d{  –—† }|€%t        j                  dt         j                  «       yt        j                  |j                  «       «      }|j                  ||t        t        |«      ¬«      ƒ d{  –—†  |S 7 Œ»7 Œ|7 Œ
# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)	aÿ  
    Fetches the default end user budget from the database if litellm.max_end_user_budget_id is configured.

    This budget is applied to end users who don't have an explicit budget_id set.
    Results are cached for performance.

    Args:
        prisma_client: Database client instance
        user_api_key_cache: Cache for storing/retrieving budget data
        parent_otel_span: Optional OpenTelemetry span for tracing

    Returns:
        LiteLLM_BudgetTable if configured and found, None otherwise
    Nzdefault_end_user_budget:©rù   Ú
model_typeÚ	budget_id©r¥   z1Default end user budget not found in database: %s©rù   r�   rƒ  Úttlz*Error fetching default end user budget: %s)rJ  Úmax_end_user_budget_idrû   r(   r¿   r]   r¨   r   ÚwarningÚmodel_validater}   Úasync_set_cacherK   r  r  )rí  rî  r€  Ú	cache_keyÚcached_budgetÚbudget_recordÚ_budget_objr@  s           r|   Úget_default_end_user_budgetr�    sF  è ø€ ð& Ð¤× >Ñ >Ð FØà1´'×2PÑ2PÐ1QÐR€Ið "4×!CÑ!CØÜ&ð "Dó "÷ €Mð Ð ØÐðÜ%4Ô5EÀmÓ5TÓ%U×%aÑ%aØ¤× >Ñ >Ð?ð &bó &
÷  
ˆð Ð Ü ×(Ñ(ØCÄW×EcÑEcôð ä0×?Ñ?À×@RÑ@RÓ@TÓUˆà ×0Ñ0ØØÜ*Ü)Ð*<Ó=ð	 1ó 
÷ 	
ð 	
ð Ðð9øð 
øð	
ùô ò Ü×"Ñ"Ð#OÐQRÔSÜûðüsm   ‚AD1ÁC?ÁD1Á7D ÂDÂ*D Â/D1Â0AD Ã8DÃ9D Ã>D1ÄD ÄD Ä	D.ÄD)Ä$D1Ä)D.Ä.D1r„  c              ƒ   óä  K  — |€yd| › �}|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 t        t        |«      «      j	                  d| i¬«      ƒ d{  –—† }|€t        j                  d| «       yt        j                  |j                  «       «      }|j                  ||t        t        |«      ¬«      ƒ d{  –—†  |S 7 ŒŸ7 Œn# t
        $ r t        j                  d| «       Y yw xY w7 Œ/­w)	a:  
    Fetches the team-level default per-member budget referenced by team.metadata["team_member_budget_id"].

    This budget is applied to team members whose TeamMembership row has no
    linked budget, or whose linked budget has max_budget=NULL. Results are
    cached for performance.

    Args:
        budget_id: The budget_id pulled from team.metadata["team_member_budget_id"]
        prisma_client: Database client instance
        user_api_key_cache: Cache for storing/retrieving budget data

    Returns:
        LiteLLM_BudgetTable if found, None otherwise
    Nzteam_member_default_budget:r‚  r„  r…  z,Error fetching team-default member budget %sz4Team-default member budget not found in database: %sr†  )rû   r(   r¿   r]   r¨   r  r   Ú	exceptionr‰  rŠ  r}   r‹  rK   )r„  rí  rî  rŒ  r�  rŽ  Úbudgets          r|   Úget_team_member_default_budgetr”  B  s!  è ø€ ð* ÐØà4°Y°KÐ@€Ià!3×!CÑ!CØÜ&ð "Dó "÷ €Mð Ð ØÐðÜ%4Ô5EÀmÓ5TÓ%U×%aÑ%aØ 	Ð*ð &bó &
÷  
ˆð ÐÜ×$Ñ$Ð%[Ð]fÔgØä'×6Ñ6°}×7IÑ7IÓ7KÓL€FØ
×
,Ñ
,ØØÜ&Ü%Ð&8Ó9ð	 -ó ÷ ð ð €Mð7øð 
ùô ò Ü×&Ñ&Ð'UÐW`ÔaÙðúðúsQ   ‚#C0¥C¦C0¯)C	 ÁCÁC	 ÁA!C0Â>C.Â?C0ÃC	 Ã	C+Ã(C0Ã*C+Ã+C0r  c              ƒ   óî   K  — | j                   �| S t        j                  €| S t        |||¬«      ƒ d{  –—† }|�6|| _         t	        j
                  dt        j                  | j                  «       | S 7 Œ>­w)aÇ  
    Helper function to apply default budget to end user if they don't have a budget assigned.

    Args:
        end_user_obj: The end user object to potentially apply default budget to
        prisma_client: Database client instance
        user_api_key_cache: Cache for storing/retrieving data
        parent_otel_span: Optional OpenTelemetry span for tracing

    Returns:
        Updated end user object with default budget applied if applicable
    N)rí  rî  r€  z(Applied default budget %s to end user %s)ré   rJ  rˆ  r�  r   r2  rš   )r  rí  rî  r€  Údefault_budgets        r|   Ú!_apply_default_budget_to_end_userr—  z  s‡   è ø€ ð& ×(Ñ(Ð4ØÐô ×%Ñ%Ð-ØÐô #>Ø#Ø-Ø)ô#÷ €Nð Ð!à,:ˆÔ)Ü×"Ñ"Ø6¼×8VÑ8VÐXd×XlÑXlô	
ð Ððús   ‚2A5´A3µ?A5c           
   ƒ   óš  K  — t        j                  |«      ry| j                  €y| j                  j                  }|€yddlm}  |d| j                  › �| j                  xs d|d¬«      ƒ d{  –—† }||kD  rOt        j                  ||d| j                  › d	|› d
|› �t        j                  j                  | j                  ¬«      ‚y7 ŒY­w)zð
    Check if end user is within their budget limit.

    Args:
        end_user_obj: The end user object to check
        route: The request route

    Raises:
        litellm.BudgetExceededError: If end user has exceeded their budget
    Nr   r   zspend:end_user:r  T©r  r  rá   Úfallback_authoritativezExceededBudget: End User=r  r  r  )r@   Úis_info_routeré   rá   r  r  rš   rç   rJ  r¯  r*   ÚEND_USERr�   )r  rŠ  Úend_user_budgetr  Úend_user_spends        r|   r;  r;  ¥  sì   è ø€ ô × Ñ  Ô'Øà×(Ñ(Ð0Øà)×>Ñ>×IÑI€OØÐØå<á"3Ø% l×&:Ñ&:Ð%;Ð<Ø#×)Ñ)Ò0¨SØ"Ø#ô	#÷ €Nð ˜Ò'Ü×)Ñ)Ø'Ø&Ø/°×0DÑ0DÐ/EÐEYÐZhÐYiÐirð  tCð  sDð  EÜ*×3Ñ3×9Ñ9Ø"×*Ñ*ô
ð 	
ð (ðús   ‚A-CÁ/C	Á0AC)r„  Úallowed_model_regionÚdefault_modelÚobject_permission_idÚ_RESTRICTED_COLUMNSr  c                 ó   — | ddiiS )zY``column IS NOT NULL`` as a plain dict, which is the only shape prisma's builder accepts.ÚnotNry   )r  s    r|   Ú_column_is_setr¥  Ô  s   € à�U˜D�MÐ"Ð"r   c                  ó8   — dddigt        t        t        «      ¢iS )zTPrisma filter selecting every end-user row that carries a restriction auth enforces.ÚORr�  T)Úmapr¥  r¢  ry   r   r|   Ú_restricted_end_user_wherer©  Ù  s"   € à�I˜tÐ$ÐP¤s¬>Ô;NÓ'OÐPÐQÐQr   c                   ó   — e Zd ZdZy)Ú_RegistryNotCachedz[No cached registry answer, as distinct from the cached answer ``None`` (registry unusable).N©r€   r�   r‚   Ú__doc__ry   r   r|   r«  r«  Þ  s   „ Úer   r«  Ú_REGISTRY_NOT_CACHEDÚ_TAG_REGISTRY_LOAD_LOCKÚ_END_USER_REGISTRY_LOAD_LOCKÚ&_MODEL_ACCESS_GROUP_REGISTRY_LOAD_LOCKrŒ  Úoverflow_sentinelc              ƒ   ó¼   K  — t        |«      j                  | ¬«      ƒ d{  –—† }||k(  ryt        |t        t        f«      rt        d„ |D «       «      S t        S 7 Œ8­w)zUThe cached registry answer, or ``_REGISTRY_NOT_CACHED`` when the caller has to query.©rù   Nc              3   óB   K  — | ]  }t        |t        «      sŒ|–— Œ y ­wrx   )r(  rƒ   )r  rS  s     r|   r  z#_cached_registry.<locals>.<genexpr>õ  s   è ø€ ÒM 5´jÀÌÕ6LœÑMùr  )rþ   rû   r(  rÑ  r—   Ú	frozensetr®  )rŒ  r²  rî  r;  s       r|   Ú_cached_registryr·  ê  s[   è ø€ ô %Ð%7Ó8×HÑHÈYÐHÓW×W€FØÐ"Ò"Øä�&œ4¤˜-Ô(ÜÑM¨FÔMÓMÐMÜÐð Xús   ‚A¡A¢9Ar‡  c              ƒ   ó¤   K  — 	 |j                  | ||¬«      ƒ d{  –—†  y7 Œ# t        $ r!}t        j                  d| |«       Y d}~yd}~ww xY w­w)zYBest-effort: a cache backend failure must not turn a registry load into a failed request.©rù   r�   r‡  NzFailed to cache registry %s: %s)r‹  r  r   r‰  )rŒ  r�   r‡  rî  r@  s        r|   Ú_cache_registry_answerrº  ù  sP   è ø€ ðVØ ×0Ñ0°YÀeÐQTÐ0ÓU×UÒUùÜò VÜ×$Ñ$Ð%FÈ	ÐST×UÑUûðVüs6   ‚A„# ›!œ#  A¡# £	A¬AÁAÁAÁAr  Ú	fetch_idsc              ƒ   ó†  K  — 	  |«       ƒ d{  –—† }t        |«      |kD  r!t	        | |t        |«      |¬«      ƒ d{  –—†  yt	        | |t        |«      |¬«      ƒ d{  –—†  t        |«      S 7 Œ^# t         $ rB}t        j                  d| t        |«       t	        | |t        |¬«      ƒ d{  –—†7   Y d}~yd}~ww xY w7 Œ€7 Œa­w)zSThe registry as the database has it, cached whole, or ``None`` when it is unusable.Nz~Registry %s could not be loaded from the database, so per-id lookups will run and the registry query is suppressed for %ss: %s)rŒ  r�   r‡  rî  )r  r   r‰  r    rº  rv  rK   r¶  )rŒ  r²  r  r»  rî  Úregistry_idsr@  s          r|   Ú_fetch_and_cache_registryr¾    sà   è ø€ ðÙ$-£K×/ˆô" ˆ<Ó˜8Ò#Ü$ØØ#Ü)Ð*<Ó=Ø1ô	
÷ 	
ð 	
ð ä
 ØØÜ%Ð&8Ó9Ø-ô	÷ ð ô �\Ó"Ð"ðA 0ùÜò Ü×$Ñ$ð7àÜ-Øô	
ô %ØØ#Ü1Ø1ô	
÷ 	
ñ 	
ô ûðúð"	
øðúse   ‚C„
A/ ŽA-�A/ “)C¼B=½ CÁB?ÁCÁ-A/ Á/	B:Á82B5Â*B-Â+B5Â0CÂ5B:Â:CÂ?CÚ	load_lockc              ƒ   ór  K  — t        | ||«      ƒ d{  –—† }t        |t        «      s|S |4 ƒd{  –—†  t        | ||«      ƒ d{  –—† }t        |t        «      s|cddd«      ƒd{  –—†  S t        | ||||¬«      ƒ d{  –—† cddd«      ƒd{  –—†  S 7 Œ‚7 Œg7 ŒT7 Œ47 Œ7 Œ# 1 ƒd{  –—†7  sw Y   yxY w­w)a  
    A bounded id set under one cache key, so an id outside it costs no DB read.

    ``None`` = unusable (overflow or recent DB error): fall back to per-id lookups. An empty
    frozenset is a real, cacheable answer. Loads are single-flighted to stop TTL-expiry stampedes.
    N)rŒ  r²  r  r»  rî  )r·  r(  r«  r¾  )rŒ  r²  r  r¿  r»  rî  r;  Úcached_after_waits           r|   Ú_load_bounded_registryrÂ  2  sÉ   è ø€ ô +¨9Ð6GÐI[Ó\×\€FÜ�fÔ0Ô1Øˆà÷ 
ñ 
ä)9¸)ÐEVÐXjÓ)k×#kÐÜÐ+Ô-?Ô@Ø$÷	
÷ 
ñ 
ô /ØØ/ØØØ1ô
÷ 
÷
÷ 
ñ 
ð	 ]øð
øà#køð
øð
øð
ø÷ 
÷ 
ñ 
üs–   ‚B7“B”B7°B±B7´B"ÁBÁB"ÁB7Á'BÁ(B7Á-B"Â BÂB"ÂB7ÂB ÂB7ÂB7ÂB"ÂB7ÂB"Â B7Â"B4Â(B+Â)B4Â0B7c              ƒ   ó”   ‡ K  — dt         t        df   fˆ fd„}t        t        «       t        t
        t        ||¬«      ƒ d{  –—† S 7 Œ­w)zQThe set of end-user ids whose ``LiteLLM_EndUserTable`` row carries a restriction.rv   .c               “   ó¬   •K  — t        t        ‰«      «      j                  t        «       t        dz   ¬«      ƒ d {  –—† } t        d„ | D «       «      S 7 Œ­w)Nrn   ©r¥   r­   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrx   )rš   ©r  Úrows     r|   r  zH_load_end_user_restricted_registry.<locals>.fetch_ids.<locals>.<genexpr>^  s   è ø€ Ò< S�S—[•[Ñ<ùó   ‚)rÝ   rc   r¯   r©  r   r—   )Úrestricted_rowsrí  s    €r|   r»  z5_load_end_user_restricted_registry.<locals>.fetch_idsY  sS   øè ø€ Ü'6Ô7HÈÓ7WÓ'X×'bÑ'bÜ,Ó.Ü6¸Ñ:ð (có (
÷ "
ˆô Ñ<¨OÔ<Ó<Ð<ð	"
ús   ƒ8A»A¼A©rŒ  r²  r  r¿  r»  rî  N)r—   rƒ   rÂ  rJ   rE   r   r°  ©rí  rî  r»  s   `  r|   Ú"_load_end_user_restricted_registryrÍ  S  sI   øè ø€ ð=œU¤3¨ 8™_õ =ô (Ü8Ó:ÜHÜ6Ü.ØØ-ô÷ ð ð úó   ƒ>AÁAÁAÚend_user_idÚtoken_end_user_max_budgetc              ƒ   ó’   K  — t         j                  €t         j                  s|�yt        ||¬«      ƒ d{  –—† }|duxr | |vS 7 Œ­w)aõ  
    True when the cached registry proves the id restricts nothing, so its row need not be read.

    Every field ``get_end_user_object`` callers consume (budget, spend under that budget, region,
    default model, object permission, blocked) is part of the registry predicate, so an id outside
    it is indistinguishable from one with no row at all. The skip is off whenever mere existence of
    the row is meaningful: ``max_end_user_budget_id`` grafts a default budget onto any row that
    exists, ``validate_end_user_id_in_db`` rejects ids that resolve to no row, and a token-supplied
    ``end_user_max_budget`` (a ``user_custom_auth`` callable can set one against an otherwise
    unrestricted row) is enforced against the row's recorded spend.
    NFrì  )rJ  rˆ  Úvalidate_end_user_id_in_dbrÍ  )rÏ  rí  rî  rÐ  Úregistrys        r|   Ú_end_user_is_known_unrestrictedrÔ  j  sW   è ø€ ô$ 	×&Ñ&Ð2Ü×-Ò-Ø$Ð0àä>Ø#Ø-ô÷ €Hð ˜4ÐÒ? K°xÐ$?Ð?ð	ús   ‚4A¶A·Ac              ƒ   ó`  K  — |€t        d«      ‚| €yt        | «      }|j                  |t        ¬«      ƒ d{  –—† }|�|}	t	        |	|||¬«      ƒ d{  –—† }	|	S t        | |||¬«      ƒ d{  –—† ry	 t        t        |«      «      j                  d| idddœ¬	«      ƒ d{  –—† }
|
€t         ‚t        j                  |
j                  «       «      }t	        ||||¬«      ƒ d{  –—† }|j                  ||t        t        |«      ¬
«      ƒ d{  –—†  |S 7 ŒÚ7 ŒÁ7 Œª7 Œx7 Œ87 Œ# t         $ r Y yw xY w­w)aP  
    Returns end user object from database or cache.

    If end user exists but has no budget_id, applies the default budget
    (if configured via litellm.max_end_user_budget_id).

    Args:
        end_user_id: The ID of the end user
        prisma_client: Database client instance
        user_api_key_cache: Cache for storing/retrieving data
        route: The request route
        parent_otel_span: Optional OpenTelemetry span for tracing
        proxy_logging_obj: Optional proxy logging object
        token_end_user_max_budget: ``valid_token.end_user_max_budget``, when the caller holds a
            token. Budget enforcement reads the row's spend, so a row that restricts nothing on
            its own must still be loaded when the token carries a budget for it.

    Returns:
        LiteLLM_EndUserTable if found, None otherwise
    NúNo db connectedr‚  )r  rí  rî  r€  )rÏ  rí  rî  rÐ  rš   T)ré   Úobject_permission©r¥   r¤   r†  )r  rI   rû   r)   r—  rÔ  r¿   rc   r¨   rŠ  r}   r‹  rK   )rÏ  rí  rî  rŠ  r€  r~  rÐ  Ú_keyÚcached_user_objÚ
return_objÚresponseÚ	_responses               r|   Úget_end_user_objectrÞ  ‰  s�  è ø€ ð< ÐÜÐ)Ó*Ð*àÐØä$ [Ó1€Dð $6×#EÑ#EØÜ'ð $Fó $÷ €Oð Ð"Ø$ˆ
ä<Ø#Ø'Ø1Ø-ô	
÷ 
ˆ
ð Ðä,ØØ#Ø-Ø";ô	÷ ð ð ðÜ /Ô0AÀ-Ó0PÓ Q× ]Ñ ]Ø˜kÐ*Ø-1ÈÑMð !^ó !
÷ 
ˆð
 ÐÜˆOô )×7Ñ7¸¿¹»ÓHˆ	ô <Ø"Ø'Ø1Ø-ô	
÷ 
ˆ	ð !×0Ñ0ØØÜ+Ü)Ð*<Ó=ð	 1ó 
÷ 	
ð 	
ð Ððkøð
øðøð
øð
øð	
ùô ò ÙðüsŽ   ‚6D.¸D¹D.ÁDÁD.Á,DÁ-D.Á3-D Â DÂ!AD Ã"DÃ#)D ÄDÄD ÄD.ÄD.ÄD.ÄD ÄD ÄD Ä	D+Ä(D.Ä*D+Ä+D.é<   Ú!_END_USER_VALIDATION_NEGATIVE_TTLi,  Ú!_END_USER_VALIDATION_POSITIVE_TTLÚraw_end_user_idc              ƒ   ó�  K  — | €yt         j                  s| S |€| S d| › �}t        |«      j                  |¬«      ƒ d{  –—† }|dk(  r| S |dk(  rt         j                  r| S dS t        | |||||¬«      ƒ d{  –—† }|j                  ||rdnd|rt        nt        ¬«      ƒ d{  –—†  |r| S t         j                  r| S y7 Œ€7 ŒI7 Œ­w)ah  Optionally drop end-user ids that don't resolve to a known DB row.

    Default: pass-through. LiteLLM's documented pattern is that the `user`
    field is an arbitrary caller-supplied identifier, so validation is
    opt-in behind ``litellm.validate_end_user_id_in_db`` to preserve
    backwards compatibility.

    When the flag is set: accept the id when it matches any of
      - LiteLLM_EndUserTable.user_id
      - LiteLLM_UserTable.user_id
      - LiteLLM_UserTable.user_email (case-insensitive)

    If the id doesn't match but ``litellm.max_end_user_budget_id`` is set,
    we still preserve the id so the default end-user budget is applied
    downstream; otherwise we return None.

    DB lookups reuse ``get_end_user_object`` / ``get_user_object`` so they
    share the same cache as the rest of the auth path instead of adding new
    raw Prisma queries.
    Nzend_user_validation:r´  ÚvalidÚinvalid©rÏ  rí  rî  r€  r~  rŠ  r¹  )	rJ  rÒ  rþ   rû   rˆ  Ú_end_user_id_exists_in_dbr‹  rá  rà  )	râ  rí  rî  r€  r~  rŠ  rŒ  r;  Úis_valids	            r|   Ú resolve_and_validate_end_user_idré  ï  s   è ø€ ð8 ÐØÜ×-Ò-ØÐØÐØÐà-¨oÐ->Ð?€IÜ$Ð%7Ó8×HÑHÈYÐHÓW×W€FØ�ÒØÐØ�ÒÜ")×"@Ò"@ˆÐJÀdÐJä5Ø#Ø#Ø-Ø)Ø+Øô÷ €Hð ×
,Ñ
,ØÙ!‰g yÙ2:Õ.Ô@að -ó ÷ ð ñ ØÐä×%Ò%ØÐØð5 Xøðøðús4   ‚=C¿C Á 8CÁ8CÁ9+CÂ$CÂ%CÃCÃCc              ƒ   óL  K  — 	 t        | |||||¬«      ƒ d{  –—† }|�y	 	 t	        | ||d||dd| v r| nd¬«      ƒ d{  –—† }|�y	 y7 Œ/# t        $ r }t        j                  d|«       Y d}~ŒMd}~ww xY w7 Œ7# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)	z=True when the id matches an EndUser, User, or user_email row.ræ  NTz:end_user validation: get_end_user_object lookup failed: %sFú@)rš   rí  rî  Úuser_id_upsertr€  r~  Úcheck_db_onlyÚ
user_emailz6end_user validation: get_user_object lookup failed: %s)rÞ  r  r   r2  Úget_user_object)	rÏ  rí  rî  r€  r~  rŠ  r  r@  r#  s	            r|   rç  rç  0  sæ   è ø€ ðdÜ$7Ø#Ø'Ø1Ø-Ø/Øô%
÷ 
ˆð Ð#Øð $ð
`Ü /ØØ'Ø1Ø Ø-Ø/ØØ&)¨[Ñ&8‘{¸dô	!
÷ 	
ˆð ÐØð  ð
 ð;
ùô ò dÜ×"Ñ"Ð#_Ðab×cÑcûðdúð	
ùô ò `Ü×"Ñ"Ð#[Ð]^×_Ð_àûð`üs|   ‚B$„A
 ˜A™A
 ŸB$¢A8 ¾A6¿A8 ÁB$ÁB$ÁA
 Á
	A3ÁA.Á)B$Á.A3Á3B$Á6A8 Á8	B!ÂBÂB$ÂB!Â!B$c              ƒ   ó”   ‡ K  — dt         t        df   fˆ fd„}t        t        «       t        t
        t        ||¬«      ƒ d{  –—† S 7 Œ­w)z=The set of tag names that have a row in ``LiteLLM_TagTable``.rv   .c               “   óš   •K  — t        t        ‰«      «      j                  t        dz   ¬«      ƒ d {  –—† } t	        d„ | D «       «      S 7 Œ­w)Nrn   ©r­   c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrx   )rÔ   rÇ  s     r|   r  z8_load_tag_registry.<locals>.fetch_ids.<locals>.<genexpr>d  s   è ø€ Ò; c�S—\•\Ñ;ùrÉ  )rØ   rg   r¯   r!   r—   ©Úregistry_rowsrí  s    €r|   r»  z%_load_tag_registry.<locals>.fetch_ids`  sL   øè ø€ Ü%/´¸mÓ0LÓ%M×%WÑ%WÜ&¨Ñ*ð &Xó &
÷  
ˆô Ñ;¨]Ô;Ó;Ð;ð 
úó   ƒ/A²A	³ArË  N)r—   rƒ   rÂ  rQ   rG   r!   r¯  rÌ  s   `  r|   Ú_load_tag_registryr÷  Z  sI   øè ø€ ð<œU¤3¨ 8™_õ <ô (Ü(Ó*Ü8Ü&Ü)ØØ-ô÷ ð ð úrÎ  c              ƒ   ó”   ‡ K  — dt         t        df   fˆ fd„}t        t        «       t        t
        t        ||¬«      ƒ d{  –—† S 7 Œ­w)z_The set of model access group names that have a row in ``LiteLLM_ModelAccessGroupBudgetTable``.rv   .c               “   óš   •K  — t        t        ‰«      «      j                  t        dz   ¬«      ƒ d {  –—† } t	        d„ | D «       «      S 7 Œ­w)Nrn   rò  c              3   ó4   K  — | ]  }|j                   –— Œ y ­wrx   )rå   rÇ  s     r|   r  zG_load_model_access_group_registry.<locals>.fetch_ids.<locals>.<genexpr>z  s   è ø€ ÒD¨s�S×*Õ*ÑDùrÉ  )rë   rf   r¯   r   r—   rô  s    €r|   r»  z4_load_model_access_group_registry.<locals>.fetch_idsv  sJ   øè ø€ Ü%EÜ,¨]Ó;ó&
ç
‰)Ô=ÀÑAˆ)Ó
B÷ Cˆô ÑD°mÔDÓDÐDð Cúrö  rË  N)r—   rƒ   rÂ  rM   rF   r   r±  rÌ  s   `  r|   Ú!_load_model_access_group_registryrû  p  sK   øè ø€ ðEœU¤3¨ 8™_õ Eô (Ü7Ó9ÜGÜ5Ü8ØØ-ô÷ ð ð úrÎ  Úuncached_groupsc           	   ƒ   óŽ  K  — | sy	 t        t        |«      «      j                  ddt        | «      iiddi¬«      ƒ d{  –—† }t	        d„ |D «       «      }|D ]8  \  }}|j                  t        |«      |t        t        |«      ¬	«      ƒ d{  –—†  Œ: 	 |S 7 ŒV7 Œ# t        $ r }t        j                  d
|«       Y d}~yd}~ww xY w­w)a3  Budget rows for the groups a cache probe missed.

    No registry gate here, unlike the tag path: the names only ever come from
    ``matched_model_access_groups``, which :func:`collect_matched_model_access_groups` already
    intersected with the registry, so a name that has no row cannot reach this.
    ry   rå   Úinré   TrØ  Nc              3   óJ   K  — | ]  }|j                   t        |«      f–— Œ y ­wrx   )rå   Ú_model_access_group_budgetrÇ  s     r|   r  z=_fetch_uncached_model_access_group_budgets.<locals>.<genexpr>›  s#   è ø€ ÒkÐ\_ × 5Ñ 5Ô7QÐRUÓ7VÔWÑkùs   ‚!#r†  zAError batch fetching model access group budgets from database: %s)rë   rf   r¯   rÑ  r—   r‹  rL   rl   rK   r  r   r2  )rü  rí  rî  Údb_rowsÚfetchedÚfetched_nameÚfetched_objr@  s           r|   Ú*_fetch_uncached_model_access_group_budgetsr  †  sæ   è ø€ ñ ØðÜ?Ü,¨]Ó;ó 
ç
‰)Ø&¨¬t°OÓ/DÐ(EÐFØ+¨TÐ2ð ó 
÷
ˆô ÑkÐcjÔkÓkˆØ)0ò 	Ñ%ˆL˜+Ø$×4Ñ4Ü0°Ó>Ø!Ü1Ü-Ð.@ÓAð	 5ó ÷ ñ ñ	ð ˆð%
øðùô ò Ü×"Ñ"Ð#fÐhiÔjÜûðüsQ   ‚C‡7B ¾B¿AB ÂBÂB ÂCÂB ÂB Â	CÂ"B=Â8CÂ=CÃCrÈ  c                 óŒ   — | j                   }t        | j                  | j                  xs d|€d ¬«      S |j                  ¬«      S )Nr  )rå   rç   rá   )ré   rl   rå   rç   rá   )rÈ  rõ   s     r|   r   r   ª  sM   € Ø×2Ñ2€LÜ!Ø×/Ñ/Ø�i‰iÒ˜3Ø'Ð/�4ôð ð 6B×5LÑ5Lôð r   Úaccess_group_namesc           	   ƒ   ó*  K  — |�| si S | D �cg c],  }||j                  t        |«      t        ¬«      ƒ d{  –—† f‘Œ. }}t        t	        d„ |D «       «      ||¬«      ƒ d{  –—† }g |¢|¢­D ��ci c]  \  }}|€Œ	||“Œ c}}S 7 ŒMc c}w 7 Œ)c c}}w ­w)aJ  Budget rows for the given model access groups, served from cache where possible.

    Shared by the two enforcement paths so they read one row per group per request: the
    reservation counters when reservations are on, and :func:`_model_access_group_max_budget_check`
    when ``disable_budget_reservation`` turns them off.
    Nr‚  c              3   ó,   K  — | ]  \  }}|�Œ	|–— Œ y ­wrx   ry   )r  Úgroupr“  s      r|   r  z7get_model_access_group_budgets_batch.<locals>.<genexpr>Ì  s   è ø€ ÒR©¨¨vÀ6Á>œeÑRùó   ‚
�)rü  rí  rî  )rû   rL   rl   r  r—   )r  rí  rî  r
  Úprobedr  r“  s          r|   Ú$get_model_access_group_budgets_batchr  ³  sÅ   è ø€ ð ÐÑ$6Øˆ	ð (öð ð Ø$×4Ñ4Ü0°Ó7ÔDZð 5ó ÷ ò	
ð€Fð ô FÜÑR¸ÔRÓRØ#Ø-ô÷ €Gð
 0C°Ð/B¸'Ñ/B×Y™m˜e VÀfÑFXˆE�6‰MÓYÐYðúòðúó
 ZùóI   ‚B�)B¶B·B¾#BÁ!BÁ"BÁ0
BÁ;BÂ BÂBÂBÂBÚuncached_tagsc           	   ƒ   ó  ‡	K  — | syt        ||¬«      ƒ d{  –—† Š	‰	€t        | «      nt        ˆ	fd„| D «       «      }|sy	 t        t        |«      «      j	                  ddt        |«      iiddi¬	«      ƒ d{  –—† }t        d
„ |D «       «      }|D ]8  \  }}|j                  t        |«      |t        t        |«      ¬«      ƒ d{  –—†  Œ: 	 |S 7 Œ·7 ŒX7 Œ# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)zZRows for the tags a cache probe missed; names absent from the registry never reach the DB.ry   rì  Nc              3   ó,   •K  — | ]  }|‰v sŒ|–— Œ y ­wrx   ry   )r  ÚtagrÓ  s     €r|   r  z'_fetch_uncached_tags.<locals>.<genexpr>á  s   øè ø€ Ò;lÀCÐ\_ÐckÒ\k¼CÑ;lùs   ƒ	�rÔ   rþ  ré   TrØ  c              3   óz   K  — | ]3  }|j                   t        j                  |j                  «       «      f–— Œ5 y ­wrx   )rÔ   r1   rŠ  r}   )r  Údb_tags     r|   r  z'_fetch_uncached_tags.<locals>.<genexpr>ë  s0   è ø€ ÒwÐek §¡Ô1A×1PÑ1PÐQW×Q\ÑQ\ÓQ^Ó1_Ô`Ñwùs   ‚9;r†  z+Error batch fetching tags from database: %s)r÷  r—   rØ   rg   r¯   rÑ  r‹  rP   r1   rK   r  r   r2  )
r  rí  rî  Útags_to_fetchÚdb_tagsr  r  r  r@  rÓ  s
            @r|   Ú_fetch_uncached_tagsr  Ó  s*  øè ø€ ñ Øä.Ø#Ø-ô÷ €Hð
 !)Ð 0ŒˆmÔ´eÓ;lÈ=Ô;lÓ6lð ñ ØðÜ)¬-¸Ó*FÓG×QÑQØ ¤d¨=Ó&9Ð:Ð;Ø+¨TÐ2ð  Ró  
÷ 
ˆô ÑwÐovÔwÓwˆØ)0ò 	Ñ%ˆL˜+Ø$×4Ñ4Ü! ,Ó/Ø!Ü+Ü-Ð.@ÓAð	 5ó ÷ ñ ñ	ð ˆð7øð
øðùô ò Ü×"Ñ"Ð#PÐRSÔTÜûðüs^   ƒD—C˜(DÁ7C Á8CÁ9AC ÃCÃC ÃDÃC ÃC Ã	C>ÃC9Ã4DÃ9C>Ã>DÚ	tag_namesc           	   ƒ   ó*  K  — |�| si S | D �cg c],  }||j                  t        |«      t        ¬«      ƒ d{  –—† f‘Œ. }}t        t	        d„ |D «       «      ||¬«      ƒ d{  –—† }g |¢|¢­D ��ci c]  \  }}|€Œ	||“Œ c}}S 7 ŒMc c}w 7 Œ)c c}}w ­w)a¡  
    Batch fetch multiple tag objects from cache and db.

    Optimizes for latency by:
    1. Serving already-cached tags without touching the DB
    2. Skipping tags that no ``LiteLLM_TagTable`` row exists for, via the cached name registry
    3. Batch fetching the remaining uncached tags in one DB query

    Args:
        tag_names: List of tag names to fetch
        prisma_client: Prisma database client
        user_api_key_cache: Cache for storing tag objects
        parent_otel_span: Optional OpenTelemetry span for tracing
        proxy_logging_obj: Optional proxy logging object

    Returns:
        Dictionary mapping tag_name to LiteLLM_TagTable object
    Nr‚  c              3   ó,   K  — | ]  \  }}|�Œ	|–— Œ y ­wrx   ry   )r  rÔ   Útag_objs      r|   r  z(get_tag_objects_batch.<locals>.<genexpr>  s   è ø€ ÒXÑ):¨°7ÈÉœHÑXùr  )r  rí  rî  )rû   rP   r1   r  r—   )	r  rí  rî  r€  r~  rÔ   r  r  r  s	            r|   Úget_tag_objects_batchr  ú  s¿   è ø€ ð4 Ð¡IØˆ	ð "öð
 ð Ø$×4Ñ4¼ÀxÓ9PÔ]mÐ4Ón×nò	
ð€Fð ô 0ÜÑX¸fÔXÓXØ#Ø-ô÷ €Gð
 8K¸Ð7JÀ'Ñ7J×bÑ"3 (¨GÈgÑNaˆH�gÑÓbÐbð oúòðúó
 cùr  rÔ   c              ƒ   ól   K  — |�| €yt        | g||||¬«      ƒ d{  –—† }|j                  | «      S 7 Œ­w)aÕ  
    Returns tag object from cache or db.

    Uses default cache TTL (same as end_user objects) to avoid drift.

    Args:
        tag_name: Name of the tag to fetch
        prisma_client: Prisma database client
        user_api_key_cache: Cache for storing tag objects
        parent_otel_span: Optional OpenTelemetry span for tracing
        proxy_logging_obj: Optional proxy logging object

    Returns:
        LiteLLM_TagTable object if found, None otherwise
    N)r  rí  rî  r€  r~  )r  r0  )rÔ   rí  rî  r€  r~  Útag_objectss         r|   Úget_tag_objectr  &  sN   è ø€ ð. Ð Ð 0Øô  5Ø�*Ø#Ø-Ø)Ø+ô ÷ €Kð �?‰?˜8Ó$Ð$ðús   ‚4œ2�4rš   r
  r2   c              ƒ   óÖ  K  — ddl m} |€t        d«      ‚| �|€yt        | |¬«      }|j	                  ||¬«      ƒ d{  –—† }|�|S 	 t        t        |«      «      j                  d| |dœidd	i¬
«      ƒ d{  –—† }	|	€y |j                  |	j                  «       «      }
|j                  ||
|¬«      ƒ d{  –—†  |
S 7 Œ~7 ŒG7 Œ
# t        $ r t        j                  d| |«       Y yw xY w­w)a‹  
    Returns team membership object if user is member of team.

    Do a isolated check for team membership vs. doing a combined key + team + user + team-membership check, as key might come in frequently for different users/teams. Larger call will slowdown query time. This way we get to cache the constant (key/team/user info) and only update based on the changing value (team membership).
    r   )r2   NrÖ  ©rš   r
  r‚  Úuser_id_team_idré   TrØ  )rù   r�   rƒ  z:Error getting team membership for user_id: %s, team_id: %s)Úlitellm.proxy._typesr2   r  rS   rû   r¿   rh   r¨   rŠ  r}   r‹  r   r’  )rš   r
  rí  rî  r€  r~  r2   rÙ  Úcached_membership_objrÜ  rÝ  s              r|   Úget_team_membershipr%  L  s7  è ø€ õ <àÐÜÐ)Ó*Ð*à€˜'˜/Øä7ÀÐQXÔY€Dð *<×)KÑ)KØØ)ð *Ló *÷ $Ðð Ð(Ø$Ð$ðÜ /Ô0HÈÓ0WÓ X× dÑ dØ$°'ÀgÑ&NÐOØ+¨TÐ2ð !eó !
÷ 
ˆð
 ÐØà@Ð1×@Ñ@ÀÇÁÃÓQˆ	Ø ×0Ñ0ØØØ-ð 1ó 
÷ 	
ð 	
ð Ðð1$øð
øð	
ùô ò Ü×&Ñ&ØHØØô	
ñ
 ðüsc   ‚<C)¾B=¿C)Á/C Á7B?Á8C Á>C)Á?7C Â6CÂ7C Â<C)Â?C ÃC Ã C&Ã#C)Ã%C&Ã&C)Úteam_modelsc                 óê   — ddl m} |€y| |v ry |t        «      }|r|j                  | ¬«      }t	        |«      dkD  rt        |«      D ]  \  }}||v sŒ y |D �cg c]	  }||vsŒ|‘Œ }}| |v ryyc c}w )Nr   ©ÚdefaultdictTrb  F)Úcollectionsr)  rÑ  Úget_model_access_groupsrv  Ú	enumerate)r*  r&  r$  r)  Úaccess_groupsÚidxÚmÚfiltered_modelss           r|   Úmodel_in_access_groupr1  ‡  sž   € Ý'àÐØØ�ÑØá*5´dÓ*;€MÙØ"×:Ñ:ÀeÐ:ÓLˆä
ˆ=Ó˜AÒÜØó
ò 	‰FˆC�ð �MÒ!Ùð		ð *5ÖO A¸ÀÒ8NšaÐO€OÐOà�ÑØàùò Ps   Á	A0Á$A0rù   c                 ót   — t        j                   «       }| |vs||    d   �y||    d   €|||    d   z
  |k\  ryy)zM
    Prevent calling db repeatedly for items that don't exist in the db.
    r   Trn   F©Útime)rù   r  r  Úcurrent_times       r|   Ú_should_check_dbr6  £  sY   € ô Ÿ)™)›+€Là
Ð%Ñ%Ð)<¸SÑ)AÀ!Ñ)DÐ)PØØ	˜SÑ	! !Ñ	$Ð	,ØÐ-¨cÑ2°1Ñ5Ñ5¸ÒHØØr   c                 ó6   — |t        j                   «       f|| <   y rx   r3  ©rù   r�   r  s      r|   Ú_update_last_db_access_timer9  ±  s   € Ø %¤t§y¡y£{Ð3Ð˜Òr   Ú	rbac_role)rq  Úroutesc                 óÌ   — t        t        t           dz  |j                  dg «      «      }|€y|D ]2  }|j                  | k(  sŒ|dk(  r|j
                  c S |j                  c S  y)zC
    Get the role based permissions from the general settings.
    NÚrole_permissionsrq  )r   rÑ  r;   r0  rT  rq  r;  )r:  rˆ  rù   Úrole_based_permissionsÚrole_based_permissions        r|   Ú_get_role_based_permissionsr@  µ  s}   € ô %)ÜÔ!Ñ" TÑ)Ø×ÑÐ/°Ó4ó%Ðð Ð%Øà!7ò eÐØ ×%Ñ%¨Ó2Ø36¸(²?Ð(×/Ñ/ÒdÐH]×HdÑHdÒdðeð r   c                 ó   — t        | |d¬«      S )zH
    Get the models allowed for a user role.

    Used by JWT Auth.
    rq  ©r:  rˆ  rù   ©r@  ©r:  rˆ  s     r|   Úget_role_based_modelsrE  Ë  s   € ô 'ØØ)Øôð r   c                 ó   — t        | |d¬«      S )z1
    Get the routes allowed for a user role.
    r;  rB  rC  rD  s     r|   Úget_role_based_routesrG  Ü  s   € ô 'ØØ)Øôð r   Ússo_user_idrî  z_PrismaUserRow | Nonec              ƒ   ó„  K  — d}|�1t        t        | «      «      j                  d|iddi¬«      ƒ d{  –—† }|€€|�~t        t        | «      «      j                  d|ddœiddi¬«      ƒ d{  –—† }|�H|�Ft	        j
                  t        t        | «      «      j                  d	|j                  id|i¬
«      «       |S 7 Œˆ7 ŒR­w)a<  
    Checks if sso user is in db.

    Called when user id match is not found in db.

    - Check if sso_user_id is user_id in db
    - Check if sso_user_id is sso_user_id in db
    - Check if user_email is user_email in db
    - If not, create new user with user_email and sso_user_id and user_id = sso_user_id
    NrH  rœ   TrØ  rî  Úinsensitive)ÚequalsÚmoderš   )r¥   r°   )rË   rj   r¨   r¬   r<  Úcreate_taskr²   rš   )rí  rH  rî  rÜ  s       r|   Ú_get_fuzzy_user_objectrN  ë  sò   è ø€ ð  €HØÐÜ$¤^°MÓ%BÓC×OÑOØ  +Ð.Ø/°Ð6ð Pó 
÷ 
ˆð
 Ð˜JÐ2ô %¤^°MÓ%BÓC×NÑNØ¨JÀÑ!NÐOØ/°Ð6ð Oó 
÷ 
ˆð
 Ð KÐ$;Ü×ÑÜœN¨=Ó9Ó:×AÑAØ$ h×&6Ñ&6Ð7Ø'¨Ð5ð Bó ôð €Oð+
øð
ús"   ‚1C ³B<´7C Á+B>Á,AC Â>C Úuser_rowc              ƒ   ó”  K  — |�|j                   €| €|S t        | «      }|j                  |j                  |¬«      ƒ d {  –—†  |j	                  |j                  «      ƒ d {  –—† }|€|S d|j                   i}|j                  |¬«      }|j                  |j                  |t        t        |«      ¬«      ƒ d {  –—†  |S 7 Œ�7 Œ`7 Œ
­w)N)rš   rî  rî  )r²   r†  )	rî  rj   Úbackfill_null_user_emailrš   Ú
find_by_idÚ
model_copyr‹  r5   rK   )rí  rî  rO  rî  Ú	user_repoÚdb_rowÚemail_updateÚupdated_rows           r|   Ú_backfill_null_user_emailrX  	  sí   è ø€ ð Ð˜X×0Ñ0Ð<ÀÐ@UØˆä% mÓ4€IØ
×
,Ñ
,Ø× Ñ Øð -ó ÷ ð ð $×.Ñ.¨x×/?Ñ/?Ó@×@€FØ€~ØˆØ'¨×):Ñ):Ð;€LØ!×,Ñ,°LÐ,ÓA€KØ
×
,Ñ
,Ø×ÑØÜ$Ü%Ð&8Ó9ð	 -ó ÷ ð ð Ððøð Aøð
ús6   ‚>CÁ CÁ"CÁ#CÁ$ACÂ;CÂ<CÃCÃCrì  rí  c	              ƒ   óú  K  — | €y|s8|j                  | t        ¬«      ƒ d{  –—† }	|	�t        |||	|¬«      ƒ d{  –—† S |€t        d«      ‚	 d| › �}
t	        |
t
        t        ¬«      }|rJt        t        |«      «      j                  d| idd	i¬
«      ƒ d{  –—† }|€t        |||¬«      ƒ d{  –—† }nd}|�€|rìddlm}m} t        j                  xs i }|j!                  «       D ��ci c]  \  }}|dvsŒ||“Œ }}}d| i|�d|ini ¥|¥}|j#                  d«      �#|j#                  d«      €t%        |d   ¬«      |d<   t        t        |«      «      j'                  |dd	i¬«      ƒ d{  –—† } |«       }|rH || |t)        t*        j,                  ¬«      ||¬«      ƒ d{  –—†  n|rt/        |
dt
        ¬«       t        ‚|j0                  �[t3        |j0                  «      dkD  rC|j0                  D �cg c]'  }|�#t5        j6                  |j9                  «       «      ‘Œ) }}||_        t        j6                  t;        |«      «      }t        ||||¬«      ƒ d{  –—† }|j9                  «       }|j=                  | |t        t?        |«      ¬«      ƒ d{  –—†  t/        |
|t
        ¬«       |S 7 �ŒŠ7 �Œt7 �Œ7 �Œc c}}w 7 �ŒR7 �Œc c}w 7 Œo7 Œ7# t        $ r"}tA        d|«       tC        d| › d|› �«      ‚d}~ww xY w­w)z–
    - Check if user id in proxy User Table
    - if valid, return LiteLLM_UserTable object with defined limits
    - if not, then raise an error
    Nr‚  )rí  rî  rO  rî  rÖ  zuser_id:©rù   r  r  rš   rœ   TrØ  )rí  rH  rî  r   )Úadd_new_user_to_default_teamÚcheck_if_default_team_set)ÚteamsÚavailable_teamsrî  Úbudget_durationÚbudget_reset_at)r_  )r°   r¤   ©rO  )rš   rî  rý  r]  rí  r8  r†  r‘  z$User doesn't exist in db. 'user_id'=z0. Create user via `/user/new` call. Got error - )"rû   r5   rX  r  r6  r  r  rË   rj   r¨   rN  Ú:litellm.proxy.management_endpoints.internal_user_endpointsr[  r\  rJ  Údefault_internal_user_paramsrZ  r0  rD   rµ   r=   r7   r[  r9  rœ   rv  r.   rŠ  rŒ   r}   r‹  rK   r#  rP  )rš   rí  rî  rì  r€  r~  rH  rî  rí  rÚ  Údb_access_time_keyÚshould_check_dbrÜ  r[  r\  Údefault_paramsrù   r�   Úscalar_default_paramsÚnew_user_paramsÚdefault_teamsró   Ú_dumped_membershipsrÝ  Úresponse_dictr@  s                             r|   rï  rï  1	  s«  è ø€ ð$ €Øñ Ø'9×'IÑ'IØÜ(ð (Jó (
÷ "
ˆð Ð&Ü2Ø+Ø#5Ø(Ø%ô	÷ ð ð ÐÜÐ)Ó*Ð*ðl
Ø&.¨w¨iÐ$8ÐÜ!1Ø"Ü 3Ü+ô"
ˆñ Ü(¬¸Ó)FÓG×SÑSØ  'Ð*Ð5OÐQUÐ4Vð Tó ÷ ˆHð ÐÜ!7Ø"/Ø +Ø)ô"÷ ‘ð ˆHàÑÙ÷ô
 )0×(LÑ(LÒ(RÐPR�à1?×1EÑ1EÓ1G÷0Ù#- 3¨È3ÐVrÒKr�C˜‘Jð0Ð%ñ 0ð ˜wð:à5?Ð5K˜ jÑ1ÐQSð:ð ,ð:�ð $×'Ñ'Ð(9Ó:ÐFØ'×+Ñ+Ð,=Ó>ÐFä9NØ(7Ð8IÑ(Jô:�OÐ$5Ñ6ô "-¬^¸MÓ-JÓ!K×!RÑ!RØ(Ø7¸Ð>ð "Só "÷ �ñ
 (AÓ'B�Ù Ù6Ø 'Ø#-Ü*8ÔCS×C_ÑC_Ô*`Ø+Ø&3ô÷ ñ ñ #Ü/Ø.Ø"Ü,?õô
  �à×,Ñ,Ð8¼SÀ×AbÑAbÓ=cÐfgÒ=gð #+×"CÑ"Cö*àØÐ)ô 4×BÑBÀ:×CXÑCXÓCZÕ[ð*Ðð *ð
 1DˆHÔ-ä%×4Ñ4´T¸(³^ÓDˆ	Ü3Ø'Ø1ØØ!ô	
÷ 
ˆ	ð  )×3Ñ3Ó5ˆð !×0Ñ0ØØÜ(Ü)Ð*<Ó=ð	 1ó 
÷ 	
ð 	
ô 	$Ø"ØÜ 3õ	
ð Ððk"
ùð
ùð$ùð
ûó"0ð ùðûò$*ð
øð	
ùô ò 
Ü" 6¨1Ô-ÜØ2°7°)Ð;kÐlmÐknÐoó
ð 	
ûð
üsÐ   ‚ K;¢J,£K;»J/¼K;ÁA	K ÂJ2ÂK Â/J5Â0;K Ã+J8Ã8J8Ã=A/K Å,J>Å-5K Æ"KÆ#AK Ç4,KÈ 9K ÉK	É9K ÊKÊK Ê+K;Ê/K;Ê2K Ê5K Ê8K ËK ËK ËK Ë	K8ËK3Ë3K8Ë8K;rƒ  c             ƒ   ó\   K  — |j                  | ||t        |«      ¬«      ƒ d{  –—†  y7 Œ­w)z·
    Persist management objects via ``UserApiKeyCache`` (in-memory + optional Redis).

    ``UserApiKeyCache`` serializes with ``model_type`` so Redis and in-memory stay aligned.
    r†  N)r‹  rK   ©rù   r�   rî  r~  rƒ  s        r|   Ú_cache_management_objectrn  Å	  s7   è ø€ ð ×
,Ñ
,ØØØÜ%Ð&8Ó9ð	 -ó ÷ ò ús   ‚",¤*¥,Ú
team_tablec              ƒ   ób  K  — t        j                   «       |_        d| › �}|�/	 |j                  j                  j	                  |¬«      ƒ d {  –—†  t        ||||t        ¬«      ƒ d {  –—†  |j                  rTd|j                  › �}	 |j                  |¬«       |�/|j                  j                  j	                  |¬«      ƒ d {  –—†  y y y 7 Œ�# t
        $ r!}t        j                  d||«       Y d }~Œ¤d }~ww xY w7 Œ”7 Œ8# t
        $ r!}t        j                  d||«       Y d }~y d }~ww xY w­w)Núteam_id:r´  zoFailed to invalidate internal usage cache entry %s; a stale team object may be served until its TTL expires: %srm  úteam_alias:zlFailed to invalidate cached team alias entry %s; a stale team object may be served until its TTL expires: %s)r4  Úlast_refreshed_atÚinternal_usage_cacheÚ
dual_cacheÚasync_delete_cacher  r   r‰  rn  r4   Ú
team_aliasÚdelete_cache)r
  ro  rî  r~  rù   r@  Ú	alias_keys          r|   Ú_cache_team_objectrz  Ú	  sK  è ø€ ô $(§9¡9£;€JÔ à˜G˜9Ð%€CàÐ$ð	Ø#×8Ñ8×CÑC×VÑVÐ[^ÐVÓ_×_Ð_ô #ØØØ-Ø+Ü-ô÷ ð ð* ×ÒØ(¨×)>Ñ)>Ð(?Ð@ˆ	ð
	Ø×+Ñ+°	Ð+Ô:Ø Ð,Ø'×<Ñ<×GÑG×ZÑZÐ_hÐZÓi×iÑið -ð	 ð? `ùÜò 	Ü ×(Ñ(ðNàØ÷	ñ ûð	úðøð4 jùÜò 	Ü ×(Ñ(ðNàØ÷	ñ ûð	üsˆ   ‚!D/¤)C ÁCÁC ÁD/Á)C>Á*D/Â
=D ÃD ÃD ÃD/ÃC Ã	C;ÃC6Ã1D/Ã6C;Ã;D/Ä D Ä	D,ÄD'Ä"D/Ä'D,Ä,D/Ú	new_spendc              ƒ   ó  K  — ddl m}m} |�ªddlm}m} d| › d|› �}d|› �}	|j                  j                  ||d¬	«       |j                  �'	 |j                  j                  ||d¬	«      ƒ d{  –—†  |j                  j                  |	||¬	«        |||d¬«      ƒ d{  –—†   ||	||¬«      ƒ d{  –—†   |t#        || ¬«      t%        | |¬«      f|¬«      ƒ d{  –—†  y7 Œs# t        $ rŒ}
t        j                  d
||
«       	 |j                  j                  |¬«      ƒ d{  –—†7   nC# t        $ r7 t        j                  d|d¬«       t        t        j                   ddi¬«      |
‚w xY wY d}
~
�Œd}
~
ww xY w7 ŒÜ7 ŒË7 Œ£­w)aB  
    Clear every cached read path for one team member's budget so a spend
    reset or a raised cap takes effect on the next request instead of
    waiting on the membership cache's TTL.

    Two independently-keyed cache entries hold the same LiteLLM_TeamMembership
    row: user_api_key_auth.py's admission check writes ``{team_id}_{user_id}``,
    while budget_reservation.py's pre-call reservation and auth_checks.py's own
    get_team_membership() (used by _check_team_member_budget) both write
    ``team_membership:{user_id}:{team_id}``. Both formats must be invalidated
    explicitly; writing one does not refresh the other. All keys are also
    broadcast (LIT-3803): each worker's own in-memory copy (membership object,
    spend counter, or the counter's own short-TTL DB-floor marker) survives
    eviction elsewhere until its TTL, so the handling worker alone clearing its
    copy leaves every other worker still enforcing the pre-reset budget.

    ``new_spend`` is only passed by reset_team_member_spend_fn, which knows the
    exact post-reset value: it is SET everywhere (matching /key/{key}/reset_spend's
    own precedent) rather than deleted, so a worker's next read reflects it
    directly instead of re-deriving it through a DB reseed. team_member_update
    only changes the budget cap, not the tracked spend, so it passes no
    new_spend; the live spend counter is untouched in that case (deleting it
    would force a reseed from the DB's own spend column, which lags the live
    counter via periodic batch writes, briefly under-enforcing the raised cap
    against a spend value lower than what was actually tracked) and only the
    membership caches carrying the new cap are invalidated.

    The floor marker (``spend_db_floor:``, proxy_server.py's
    _authoritative_floor_spend) caches the pre-reset DB spend for
    SPEND_DB_FLOOR_CACHE_TTL_SECONDS; left stale after a real reset, a request
    landing on the pod that cached it can read that higher floor and raise the
    counter right back above the just-reset spend. It is overwritten here with
    the post-reset floor (not merely deleted) and _authoritative_floor_spend
    re-checks the marker after its DB read, so a floor read already in flight
    on this pod when the reset commits cannot clobber it with the pre-reset
    value. Both keys are broadcast as SETs carrying new_spend, not deletes:
    every subscriber (remote pods AND this pod's own, which receives its own
    message) writes the post-reset value, so the self-delivered message cannot
    erase the guard just written here.

    Raises HTTPException(503) if Redis still holds the stale pre-reset counter
    after both the SET and the fallback DELETE fail: budget checks read Redis
    first, so returning success would leave the old value authoritative for
    every worker despite the DB write having committed.
    r   )Úevict_and_broadcastrA   N)Ú SPEND_DB_FLOOR_CACHE_TTL_SECONDSÚspend_counter_cacheúspend:team_member:ú:zspend_db_floor:rß  r¹  z­Failed to set spend counter %s in Redis after reset: %s; deleting it instead so the next read reseeds from the DB rather than keeping the stale pre-reset value authoritativer´  zKFailed to delete stale spend counter %s in Redis after a failed reset writeT)Úexc_infor  zSpend was reset in the database, but Redis is unreachable and still holds the pre-reset counter. Retry once Redis is reachable.rÃ  )rŒ  Ú	new_valuer‡  )r
  rš   r!  ©Ú
cache_keysrî  )Ú9litellm.proxy.common_utils.auth_cache_invalidation_pubsubr}  rA   r  r~  r  Úin_memory_cacheÚ	set_cacheÚredis_cacher‹  r  r   r‰  rv  r   r   ÚHTTP_503_SERVICE_UNAVAILABLErR   rS   )rš   r
  rî  r{  r}  rA   r~  r  Úspend_counter_keyÚspend_db_floor_keyr@  s              r|   Ú"invalidate_team_member_spend_stater�  
  sÑ  è ø€ ÷fð
 Ðßdà%7¸°yÀÀ'ÀÐ#KÐØ&5Ð6GÐ5HÐ$IÐà×+Ñ+×5Ñ5Ð:KÐS\ÐbdÐ5ÔeØ×*Ñ*Ð6ðØ)×5Ñ5×EÑEÐJ[ÐclÐrtÐEÓu×uÐuð0 	×+Ñ+×5Ñ5Ø"ØØ0ð 	6ô 	
ñ
 .Ð8IÐU^ÐdfÔg×gÐgÙ-Ø(ØØ0ô
÷ 	
ð 	
ñ ä*°7ÀGÔLÜ1¸'È7ÔSð
ð .ô÷ ñ ðI vùÜò Ü$×,Ñ,ðkà%Øô	ðØ-×9Ñ9×LÑLÐQbÐLÓc×cÒcøÜ ò Ü(×0Ñ0ØeØ)Ø!%õô
 (Ü$*×$GÑ$Gà#ð &Zð ôð ððúõ dûðúð8 	høð	
øðús—   ‚A
FÁ!C$ Á.C"Á/C$ Á3,FÂE<Â FÂ2E>Â3)FÃF ÃFÃ"C$ Ã$	E9Ã-E4ÄD+Ä$D'Ä%D+Ä*E4Ä+A E+Å+E4Å.FÅ4E9Å9FÅ>FÆ Frw  c              ƒ   óL  K  — d| › �g|rd|› �fnd¢­}|D ]Y  }	 |j                  |¬«       |�.|j                  j                  j                  |¬«      ƒ d{  –—†  t        |¬«      ƒ d{  –—†  Œ[ y7 Œ# t        $ r!}t        j                  d||«       Y d}~Œ>d}~ww xY w7 Œ6­w)a›  
    Evict both keys `_cache_team_object` writes.

    `get_team_object` reads the id key and the JWT `team_alias_jwt_field` path reads the alias key,
    so leaving either behind keeps a deleted team resolvable for auth until its TTL expires.

    Mirrors `delete_cached_project_object`: evicting locally only reaches the worker handling the
    delete, so every key is also broadcast to drop the other workers' in-memory copies.

    Eviction is best-effort, matching `_cache_team_object`. `delete_team` calls this after the team
    rows are already gone, so letting an unreachable cache backend raise here would fail a request
    whose delete has committed.
    rq  rr  ry   r´  NzkFailed to invalidate cached team entry %s on delete; a deleted team may be served until its TTL expires: %s©rŒ  ©rx  rt  ru  rv  r  r   r‰  rA   )r
  rw  rî  r~  Úkeysrù   r@  s          r|   Údelete_cache_team_objectr’  ƒ
  sÆ   è ø€ ð& ˜g˜YÐ'Ð`ÉJ¨k¸*¸Ð,FÑ+HÐ\^Ñ`€Dàò =ˆð	Ø×+Ñ+°Ð+Ô4ð !Ð,Ø'×<Ñ<×GÑG×ZÑZÐ_bÐZÓc×cÐcô .¸Ô<×<Ñ<ñ=ð dùÜò 	Ü ×(Ñ(ðIàØ÷	ñ ûð	úð 	=úsL   ‚B$š=A5ÁA3ÁA5ÁB$Á+B"Á,B$Á3A5Á5	BÁ>BÂB$ÂBÂB$Úhashed_tokenÚuser_api_key_objc              ƒ   ó–   K  — | }t        j                   «       |_        t        |¬«      }t        ||||t        ¬«      ƒ d {  –—†  y 7 Œ­w)N©r”  rm  )r4  rs  Ú!_copy_user_api_key_auth_for_cachern  r=   )r“  r”  rî  r~  rù   Úcached_key_objs         r|   Ú_cache_key_objectr™  ©
  sJ   è ø€ ð €Cô *.¯©«ÐÔ&ä=ÐO_Ô`€NÜ
"ØØØ-Ø+Ü!ô÷ ò ús   ‚?A	ÁAÁA	c              ƒ   ó   K  — | }	 |j                  |¬«       |�.|j                  j                  j                  |¬«      ƒ d{  –—†  t        |¬«      ƒ d{  –—†  y7 Œ# t        $ r!}t        j                  d||«       Y d}~Œ<d}~ww xY w7 Œ4­w)aó  
    Evict one key object, best-effort, matching `delete_cache_team_object` and
    `delete_cache_key_objects`.

    Every caller runs this after its own write has already committed, and the in-memory entry is
    dropped before the Redis round trip. Letting a cache-backend error raise here therefore reports
    failure for work that succeeded without making the cache any less stale; the leftover Redis
    entry expires at its TTL either way.

    Also broadcasts the eviction to every other worker (LIT-3803): auth serves this object
    cache-first with no freshness check, so a worker that never receives the broadcast keeps
    admitting requests against the pre-mutation object (e.g. a just-reset spend) until its own
    copy's TTL expires.
    r´  NzdFailed to invalidate cached key entry %s; a stale key object may be served until its TTL expires: %sr�  r�  )r“  rî  r~  rù   r@  s        r|   Ú_delete_cache_key_objectr›  ¾
  s–   è ø€ ð& €Cð
Ø×'Ñ'¨CÐ'Ô0ð Ð(Ø#×8Ñ8×CÑC×VÑVÐ[^ÐVÓ_×_Ð_ô *°CÔ
8×8Ñ8ð `ùÜò 
Ü×$Ñ$ØrØØ÷	
ñ 	
ûð
úð 9úsL   ‚B†=A ÁAÁA ÁBÁBÁBÁA Á	B	Á(BÁ?BÂB	Â	BÚhashed_tokensc              ƒ   óÚ   ‡‡K  — t        j                  ˆˆfd„| D «       ddiŽƒ d{  –—† }t        | |«      D ]-  \  }}t        |t        «      sŒt        j                  d||«       Œ/ y7 ŒA­w)a”  
    Evict a batch of key objects, for callers that delete keys in bulk rather than through
    `/key/delete`. Auth resolves a cached key object without re-reading its team, so a key left
    cached after its row is gone keeps buying access until its TTL expires.

    Evicting locally only reaches this worker; `_delete_cache_key_object` itself broadcasts each
    token, so a deleted key left in a peer worker's in-memory cache still authenticates there until
    its TTL expires.

    Best-effort per key: the rows are already deleted by the time this runs, so an unreachable
    cache backend must not abort the caller partway through its own cascade.
    c              3   ó:   •K  — | ]  }t        |‰‰¬ «      –— Œ y­w))r“  rî  r~  N)r›  )r  r“  r~  rî  s     €€r|   r  z+delete_cache_key_objects.<locals>.<genexpr>õ
  s.   øè ø€ ò 

ð ô %Ø)Ø#5Ø"3÷ð ñ

ùs   ƒr  TNzaFailed to evict cached key entry for %s; a deleted key may authenticate until its TTL expires: %s)r<  r=  Úzipr(  r  r   r‰  )rœ  rî  r~  Úresultsr“  Úresults    ``   r|   Údelete_cache_key_objectsr¢  ã
  sx   ùè ø€ ô" #Ÿ>™>ô

ð !.ô

ð
ð ñ
÷ 
€Gô !$ M°7Ó ;ò Ñˆ�fÜ�fœmÕ,Ü ×(Ñ(ØsØØõñð
ús   „#A+§A)¨&A+ÁA+c                   ó   — e Zd ZU ee   ed<   y)Ú_TeamNotFoundDetailr  N)r€   r�   r‚   r   rƒ   rˆ   ry   r   r|   r¤  r¤  	  s   … Ø�C‰=Ôr   r¤  c                   ó,   ‡ — e Zd ZdZdeddfˆ fd„Zˆ xZS )ÚTeamNotFoundErroraÑ  The team row is provably absent, as opposed to merely unreadable.

    ``get_team_object`` reports every failure as a 404, so a deleted team and a
    database that would not answer are indistinguishable to its callers. Callers
    that must not treat a degraded read as a definitive answer, such as the
    authorization fallback in ``user_api_key_auth``, key on this subclass. It
    stays a 404 carrying the same detail, so every other caller is unaffected.
    r
  rv   Nc                 ó8   •— dd|› d�i}t         ‰| �  d|¬«       y )Nr  úTeam doesn't exist in db. Team=ú#. Create team via `/team/new` call.é”  rÃ  )ÚsuperÚ__init__)r{   r
  rÅ  Ú	__class__s      €r|   r¬  zTeamNotFoundError.__init__  s.   ø€ àÐ6°w°iÐ?bÐcð.
ˆô 	‰Ñ S°ÐÕ8r   )r€   r�   r‚   r­  rƒ   r¬  Ú__classcell__)r­  s   @r|   r¦  r¦    s    ø„ ñð9 ð 9¨÷ 9ñ 9r   r¦  Úteam_id_upsertz_PrismaTeamRow | Nonec              ƒ   ó>  K  — t        t        |«      «      j                  d| i¬«      ƒ d {  –—† }|€d|rbddlm} t        | ¬«      }t        ddi¬«      }t        t        j                  ¬	«      } ||||¬
«      ƒ d {  –—† }t        j                  |«      }|S 7 Œl7 Œ­w)Nr
  r…  r   )Únew_team©r
  r  Úhttp)Úscopera  )r°   Úhttp_requestrý  )rÇ   ri   r¨   Ú1litellm.proxy.management_endpoints.team_endpointsr±  r8   r   r=   r7   r[  r3   rŠ  )	r
  rí  r¯  rÜ  r±  Únew_team_dataÚmock_requestÚsystem_admin_userÚcreated_team_dicts	            r|   Ú_get_team_db_checkr»    s¢   è ø€ ô !¤°Ó!>Ó?×KÑKÐS\Ð^eÐRfÐKÓg×g€HàÐ™NÝNä-°gÔ>ˆä%¨V°VÐ,<Ô=ˆÜ#1Ô<L×<XÑ<XÔ#YÐá)1ØØ%Ø/ô*
÷ $
Ðô
 %×3Ñ3Ð4EÓFˆØ€Oð! høð$
ús"   ‚*B¬B­ABÁ=BÁ>BÂBc              ƒ   ój   K  — t        t        |«      «      j                  d| i¬«      ƒ d {  –—† S 7 Œ­w)Nr
  r…  )rÇ   ri   r¨   )r
  rí  s     r|   Ú_get_team_object_from_dbr½  5  s0   è ø€ Üœ^¨MÓ:Ó;×GÑGÈyÐZaÐNbÐGÓc×cÐcÐcús   ‚*3¬1­3c              ƒ   ó  K  — |}t        |||¬«      }	|	r$t        | ||¬«      ƒ d {  –—† }
|
€t        | ¬«      ‚d }
|
€t        ‚t	        j
                  |
j                  «       «      }|j                  r4|j                  s(	 t        |j                  ||d |¬«      ƒ d {  –—† |_        t        | |||¬«      ƒ d {  –—†  t        |||¬«       |S 7 Œ¦7 Œ2# t        $ r,}t        j                  d| |j                  |«       Y d }~Œ[d }~ww xY w7 ŒP­w)NrZ  )r
  rí  r¯  r²  ©r¡  rí  rî  r€  r~  úMFailed to load object_permission for team %s with object_permission_id=%s: %s)r
  ro  rî  r~  r8  )r6  r»  r¦  r  r4   rŠ  r}   r¡  r×  Úget_object_permissionr   r2  rz  r9  )r
  rí  rî  r  r  r~  rù   r¯  rd  re  rÜ  rÝ  r@  s                r|   Ú(_get_team_object_from_user_api_key_cacherÂ  9  s4  è ø€ ð !$ÐÜ-ØØ/Ø'ô€Oñ
 Ü+°GÈ=ÐiwÔx×xˆð ÐÜ#¨GÔ4Ð4àˆàÐÜˆä1×@Ñ@ÀÇÁÃÓQ€Ið ×%Ò%¨i×.IÒ.Ið	Ü0EØ%.×%CÑ%CØ+Ø#5Ø!%Ø"3ô1÷ +ˆIÔ'ô  ØØØ-Ø+ô	÷ ð ô  ØØØ/õð Ðð] yøð +ùô ò 	Ü ×&Ñ&Ø_ØØ×.Ñ.Ø÷	ñ ûð	úðúsX   ‚$D¦C§ADÁ?C ÂCÂ	C Â&DÂ8D	Â9DÃC Ã	DÃ"DÃ<DÄDÄDc              ƒ   óR   K  — |j                  | |t        ¬«      ƒ d {  –—† }|S 7 Œ­w)N)rù   r€  rƒ  )rû   r4   )rù   rî  r€  Údecodeds       r|   Ú_get_team_object_from_cacherÅ  {  s7   è ø€ ð
 .×=Ñ=ØØ)Ü-ð >ó ÷ €Gð
 €Nðús   ‚'ž%Ÿ'Úcheck_cache_onlyc           
   ƒ   ó2  K  — |€t        d«      ‚d| › �}|s/t        |||¬«      ƒ d{  –—† }	|	�|	S |rt        ddd| › d�i¬	«      ‚	 t        | |||t        t
        ||¬
«      ƒ d{  –—† S 7 ŒA7 Œ# t        $ r ‚ t         $ r t        ddd| › d�i¬	«      ‚w xY w­w)zó
    - Check if team id in proxy Team Table
    - if valid, return LiteLLM_TeamTable object with defined limits
    - if not, then raise an error

    Raises:
        - HTTPException: If team doesn't exist in db or cache (status_code=404)
    NúFNo DB Connected. See - https://docs.litellm.ai/docs/proxy/virtual_keysrq  ©rù   rî  r€  rª  r  z:Team doesn't exist in cache + check_cache_only=True. Team=ú.rÃ  )r
  rí  rî  r~  r  r  rù   r¯  r¨  r©  )r  rÅ  r   rÂ  r  r  r¦  )
r
  rí  rî  r€  r~  rÆ  rí  r¯  rù   Úcached_team_objs
             r|   r  r  ˆ  sñ   è ø€ ð$ ÐÜÐ`ÓaÐað ˜G˜9Ð%€CáÜ'BØØ1Ø-ô(
÷ "
ˆð Ð&Ø"Ð"áÜØØÐ#]Ð^eÐ]fÐfgÐ!hÐiôð ð
Ü=ØØ'Ø1Ø/Ü 3Ü+ØØ)ô	
÷ 	
ð 		
ð#"
øð"	
ùô ò ØÜò 
ÜØØÐ>¸w¸iÐGjÐkÐlô
ð 	
ð
üs9   ‚&B¨A*©BÁA. Á%A,Á&A. Á)BÁ,A. Á.&BÂBÚaccess_group_idÚaccess_group_tablec              ƒ   ód   K  — d| › �}|j                  ||t        t        ¬«      ƒ d {  –—†  y 7 Œ­w)Núaccess_group_id:r†  )r‹  r'   r   )rÌ  rÍ  rî  r~  rù   s        r|   Ú_cache_access_objectrÐ  Å  s>   è ø€ ð $ OÐ#4Ð5€CØ
×
,Ñ
,ØØ Ü+Ü*ð	 -ó ÷ ò ús   ‚&0¨.©0c              ƒ   ó    K  — d| › �}|j                  |¬«       |�/|j                  j                  j                  |¬«      ƒ d {  –—†  y y 7 Œ­w)NrÏ  r´  )rx  rt  ru  rv  )rÌ  rî  r~  rù   s       r|   Ú_delete_cache_access_objectrÒ  Ô  sZ   è ø€ ð
 $ OÐ#4Ð5€Cà×#Ñ#¨Ð#Ô,ð Ð$Ø×4Ñ4×?Ñ?×RÑRÐWZÐRÓ[×[Ñ[ð %Ø[ús   ‚AAÁAÁAc           	   ƒ   ó
  K  — |€t        d«      ‚d| › �}|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 t        t	        |«      «      j                  d| i¬«      ƒ d{  –—† }|€t        ddd	| › d
�i¬«      ‚t        j                  |j                  «       «      }t        | |||¬«      ƒ d{  –—†  |S 7 Œˆ7 ŒW7 Œ
# t        $ r ‚ t         $ r0}t        j                  d| «       t        ddd	| › d|› �i¬«      ‚d}~ww xY w­w)aÉ  
    - Check if access_group_id in proxy AccessGroupTable
    - Always checks cache first, then DB only when not found in cache
    - if valid, return LiteLLM_AccessGroupTable object
    - if not, then raise an error

    Unlike get_team_object, this has no check_cache_only or check_db_only flags;
    it always follows cache-first-then-db semantics.

    Raises:
        - HTTPException: If access group doesn't exist in db or cache (status_code=404)
    NrÈ  rÏ  r‚  rÌ  r…  rª  r  z/Access group doesn't exist in db. Access group=rÊ  rÃ  )rÌ  rÍ  rî  r~  z2Error getting access group for access_group_id: %sú	. Error: )r  rû   r'   r¿   rb   r¨   r   rŠ  r}   rÐ  r   r’  )	rÌ  rí  rî  r~  rù   Úcached_access_objrÜ  rÝ  r@  s	            r|   Úget_access_objectrÖ  â  sd  è ø€ ð& ÐÜÐ`ÓaÐaà# OÐ#4Ð5€Cà%7×%GÑ%GØÜ+ð &Hó &÷  Ðð Ð$Ø Ð ð 
Ü /Ô0EÀmÓ0TÓ U× aÑ aØ$ oÐ6ð !bó !
÷ 
ˆð ÐÜØØÐ#RÐSbÐRcÐcdÐ!eÐfôð ô
 4×BÑBÀ8Ç=Á=Ã?ÓSˆ	ô #Ø+Ø(Ø1Ø/ô	
÷ 	
ð 	
ð Ðð; øð
øð	
ùô ò ØÜò 
Ü×&Ñ&Ø@Øô	
ô ØØÐNÈÐN_Ð_hÐijÐhkÐlÐmô
ð 	
ûð
üsW   ‚-D¯B8°D¹)B> Á"B:Á#AB> Â1B<Â2B> Â7DÂ:B> Â<B> Â>D Ã+C;Ã;D Ä Drs   c           	   ƒ   óØ  K  — |€t        d«      ‚d| › �}t        |||¬«      ƒ d{  –—† }|�|S 	 t        t        |«      «      j	                  d| i¬«      ƒ d{  –—† }|st        ddd	| › d
�i¬«      ‚t        |«      dkD  rt        ddd| › d�i¬«      ‚|d   }t        j                  |j                  «       «      }	|	j                  r4|	j                  s(	 t        |	j                  ||||¬«      ƒ d{  –—† |	_        |j!                  ||	t        t"        ¬«      ƒ d{  –—†  d|	j                  › �}|j!                  ||	t        t"        ¬«      ƒ d{  –—†  |	S 7 �Œ17 �Œ7 Œj# t         $ r6}
t        j                  d|	j                  |	j                  |
«       Y d}
~
Œ�d}
~
ww xY w7 Œ„7 ŒR# t
        $ r ‚ t         $ r0}
t        j$                  d| «       t        ddd| › d|
› �i¬«      ‚d}
~
ww xY w­w)a÷  
    Look up a team by its team_alias (name) in the database.

    Args:
        team_alias: The team name/alias to look up
        prisma_client: Database client
        user_api_key_cache: Cache for storing results
        parent_otel_span: Optional OpenTelemetry span
        proxy_logging_obj: Optional proxy logging object

    Returns:
        LiteLLM_TeamTableCachedObj: The team object if found

    Raises:
        HTTPException: If team doesn't exist or multiple teams have the same alias
    NrÈ  rr  rÉ  rw  r…  rª  r  zTeam with alias 'z8' doesn't exist in db. Create team via `/team/new` call.rÃ  rn   é�  z!Multiple teams found with alias 'zJ'. Please use team_id_jwt_field instead or ensure team aliases are unique.r   r¿  rÀ  r†  rq  z"Error looking up team by alias: %séô  z Error looking up team by alias 'ú': )r  rÅ  rÇ   ri   r¯   r   rv  r4   rŠ  rŒ   r¡  r×  rÁ  r   r2  r
  r‹  r   r’  )rw  rí  rî  r€  r~  rŒ  rË  r]  r  Úteam_objr@  Úteam_id_cache_keys               r|   Úget_team_object_by_aliasrÝ  %  s\  è ø€ ð0 ÐÜÐ`ÓaÐað % Z LÐ1€Iä#>ØØ-Ø)ô$÷ €Oð Ð"ØÐðA
Ü(¬¸Ó)FÓG×QÑQÐYeÐgqÐXrÐQÓs×sˆáÜØàÐ0°°Ð<tÐuðôð ô ˆu‹:˜Š>ÜØàÐ@ÀÀð  MWð  Xðôð ð ˜A‘hˆÜ4×CÑCÀDÇOÁOÓDUÓVˆð ×(Ò(°×1KÒ1KðÜ3HØ)1×)FÑ)FØ"/Ø'9Ø%5Ø&7ô4÷ .�Ô*ð  !×0Ñ0ØØÜ1Ü%ð	 1ó 
÷ 	
ð 	
ð &.¨h×.>Ñ.>Ð-?Ð#@ÐØ ×0Ñ0Ø!ØÜ1Ü%ð	 1ó 
÷ 	
ð 	
ð ˆðEùð tùð0.ùô ò Ü$×*Ñ*ØcØ×$Ñ$Ø×1Ñ1Ø÷	ñ ûðúð	
øð	
ùô ò ØÜò 
Ü×&Ñ&Ð'KÈZÔXÜØØÐ?À
¸|È3ÈqÈcÐRÐSô
ð 	
ûð
üsŸ   ‚$G*¦E§G*°)F% ÁEÁA:F% ÃE Ã2EÃ3	E Ã< F% ÄF!Ä3F% ÅF#ÅF% ÅG*ÅF% ÅE Å	FÅ(,FÆF% ÆFÆF% Æ#F% Æ%G'Æ7+G"Ç"G'Ç'G*Ú	org_aliasc           	   ƒ   óÚ  K  — |€t        d«      ‚d| › �}|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 t        t	        |«      «      j                  d| i¬«      ƒ d{  –—† }|st        ddd	| › d
�i¬«      ‚t        |«      dkD  rt        ddd| › d�i¬«      ‚|d   }t        j                  |j                  «       «      }	|j                  ||	t        t        ¬«      ƒ d{  –—†  |j                  d|	j                  › �|	t        t        ¬«      ƒ d{  –—†  |	S 7 Œî7 Œ½7 Œ<7 Œ# t        $ r ‚ t         $ r0}
t        j                  d| «       t        ddd| › d|
› �i¬«      ‚d}
~
ww xY w­w)a	  
    Look up an organization by its organization_alias in the database.

    Args:
        org_alias: The organization name/alias to look up
        prisma_client: Database client
        user_api_key_cache: Cache for storing results
        parent_otel_span: Optional OpenTelemetry span
        proxy_logging_obj: Optional proxy logging object

    Returns:
        LiteLLM_OrganizationTable if found, None otherwise

    Raises:
        HTTPException: If organization not found or multiple orgs have the same alias
    NrÈ  z
org_alias:r‚  Úorganization_aliasr…  rª  r  zOrganization with alias 'zH' doesn't exist in db. Create organization via `/organization/new` call.rÃ  rn   rØ  z)Multiple organizations found with alias 'zQ'. Please use org_id_jwt_field instead or ensure organization aliases are unique.r   r†  úorg_id:z*Error looking up organization by alias: %srÙ  z(Error looking up organization by alias 'rÚ  )r  rû   r/   rÅ   r_   r¯   r   rv  rŠ  rŒ   r‹  r   r  r   r’  )rÞ  rí  rî  r€  r~  rŒ  Úcached_org_objÚorgsÚorgÚorg_objr@  s              r|   Úget_org_object_by_aliasræ  ‘  sð  è ø€ ð0 ÐÜÐ`ÓaÐað $ I ;Ð/€IØ"4×"DÑ"DØÜ,ð #Eó #÷ €Nð Ð!ØÐð0
Ü&Ô'=¸mÓ'LÓM×WÑWØ'¨Ð3ð Xó 
÷ 
ˆñ ÜØàÐ8¸¸ð  DLð  Mðôð ô ˆt‹9�qŠ=ÜØàÐHÈÈð  Teð  fðôð ð ˜!‘WˆÜ2×AÑAÀ#Ç.Á.ÓBRÓSˆð !×0Ñ0ØØÜ0Ü%ð	 1ó 
÷ 	
ð 	
ð !×0Ñ0Ø˜'×1Ñ1Ð2Ð3ØÜ0Ü%ð	 1ó 
÷ 	
ð 	
ð ˆð_øð
øð0	
øð	
ùô ò ØÜò 
Ü×&Ñ&Ð'SÐU^Ô_ÜØØÐGÈ	À{ÐRUÐVWÐUXÐYÐZô
ð 	
ûð
üsi   ‚-E+¯D°E+¹)D& Á"D Á#BD& Ã%D"Ã&1D& ÄD$ÄD& ÄE+Ä D& Ä"D& Ä$D& Ä&E(Ä8+E#Å#E(Å(E+Úlitellm_login_ÚLITELLM_SESSION_TOKEN_PREFIXc                   ó®   — e Zd Zededefd„«       Ze	 	 	 	 	 ddededz  dedz  dee   dz  deeef   dz  d	e	dz  defd
„«       Z
edededz  fd„«       Zy)ÚExperimentalUIJWTTokenÚ	user_inforv   c                 óp  — ddl m} ddlm} | j                  €t        d«      ‚t        «        |d¬«      z   }|j                  d«      d d d	z   }t        d
d
d
t        j                  d|| j                  d| j                  d t        | j                  «      ¬«      } ||j                  d¬«      t        ¬«      S )Nr   ©Ú	timedelta©Úencrypt_bearer_tokenz/User role is required for experimental UI loginé
   )Úminutesú%Y-%m-%dT%H:%M:%S.%féýÿÿÿú+00:00zui-tokenr  zlitellm-dashboard)r‡   Úkey_nameÚ	key_aliasrá   Ú	rpm_limitÚexpiresrš   r
  rq  Úmax_parallel_requestsrO  T©Úexclude_none©Úprefix)Údatetimerî  Ú0litellm.proxy.common_utils.encrypt_decrypt_utilsrð  rO  r  rm   Ústrftimer=   rJ  Úmax_ui_session_budgetrš   rq  r7   Úmodel_dump_jsonrè  )rë  rî  rð  Úexpiration_timerù  r}  s         r|   Ú(get_experimental_ui_login_jwt_auth_tokenz?ExperimentalUIJWTToken.get_experimental_ui_login_jwt_auth_tokení  s¾   € å&õ	
ð ×ÑÐ&ÜÐMÓNÐNô "2Ó!3±iÈÔ6KÑ!Kˆð )×1Ñ1Ð2HÓIÈ#È2ÐNÐQYÑYˆä+ØØØ Ü×4Ñ4ØØØ×%Ñ%Ø'Ø×#Ñ#Ø"&Ü& y×':Ñ':Ó;ô
ˆñ $ K×$?Ñ$?ÈTÐ$?Ó$RÔ[wÔxÐxr   Nr
  rw  r&  ró  rá   c                 óŽ  — ddl }ddlm} ddlm} | j
                  €t        d«      ‚t        «        |t        ¬«      z   }	|	j                  d«      dd d	z   }
|}|€At        | d
«      r5| j                  r)t        | j                  «      dkD  r| j                  d   nd}t        › d|j                  d«      › �}t        › d| j                  › �}t!        ||||
|| j                  |||�t#        |«      ng |�t%        |«      nd|�g n| j&                  dt)        | j
                  «      d¬«      } ||j+                  d¬«      t,        ¬«      S )a”  
        Generate a JWT token for CLI authentication with configurable expiration.

        The expiration time can be controlled via the LITELLM_CLI_JWT_EXPIRATION_HOURS
        environment variable (defaults to 24 hours).

        Args:
            user_info: User information from the database
            team_id: Team ID for the user (optional, uses user's team if available)
            team_alias: Team alias for the selected team, if available
            team_models: Model allowlist granted by the selected team
            team_model_aliases: Team model aliases for the selected team

        Returns:
            Encrypted JWT token string
        r   Nrí  rï  z'User role is required for CLI JWT login)Úhoursró  rô  rõ  r]  ú-é   T)r‡   rö  r÷  rù  rá   rš   r
  rw  r&  ró  rq  rú  rO  Úis_session_tokenrû  rý  )Úsecretsrÿ  rî  r   rð  rO  r  rm   r   r  r’  r]  rv  r   Útoken_urlsaferš   r=   rÑ  r}   rq  r7   r  rè  )rë  r
  rw  r&  ró  rá   r  rî  rð  r  rù  Ú_team_idÚsession_tokenÚsession_aliasr}  s                  r|   Úget_cli_jwt_auth_tokenz-ExperimentalUIJWTToken.get_cli_jwt_auth_token  sZ  € ó2 	Ý&õ	
ð ×ÑÐ&ÜÐEÓFÐFô "2Ó!3±iÔF^Ô6_Ñ!_ˆð )×1Ñ1Ð2HÓIÈ#È2ÐNÐQYÑYˆð ˆØÐ¤¨	°7Ô ;À	ÇÂä-0°·±Ó-AÀAÒ-E�y—‘ qÒ)È4ˆHä"8Ð!9¸¸7×;PÑ;PÐQSÓ;TÐ:UÐVˆÜ"8Ð!9¸¸9×;LÑ;LÐ:MÐNˆä+ØØ"Ø#ØØ!Ø×%Ñ%ØØ!Ø-8Ð-Dœ˜[Ô)È"Ø;MÐ;YœtÐ$6Ô7Ð_cØ!Ð-‘2°9×3CÑ3CØ"&Ü& y×':Ñ':Ó;Ø!ô
ˆñ" $ K×$?Ñ$?ÈTÐ$?Ó$RÔ[wÔxÐxr   r“  c           	      óÒ   — dd l }ddlm} ddlm}  || t
        ¬«      }|€y 	  |j                  |j                  |«      «      S # t        $ r}t        d| › d|› d|› �«      ‚d }~ww xY w)Nr   )r=   )Údecrypt_bearer_tokenrý  zInvalid hash key. Hash key=z. Decrypted token=rÔ  )	ÚjsonÚ$litellm.proxy.auth.user_api_key_authr=   r   r  rè  rŠ  Úloadsr  )r“  r  r=   r  Údecrypted_tokenr@  s         r|   Úget_key_object_from_ui_hash_keyz6ExperimentalUIJWTToken.get_key_object_from_ui_hash_keyS  s€   € ó 	åGõ	
ñ "6°lÔKgÔ!hˆØÐ"Øð	yØ0�>×0Ñ0°·±¸OÓ1LÓMÐMøÜò 	yÜÐ9¸,¸ÐGYÐZiÐYjÐjsÐtuÐsvÐwÓxÐxûð	yús   £ A Á	A&ÁA!Á!A&©NNNNN)r€   r�   r‚   Ústaticmethodr5   rƒ   r  r   r   râ   r  r=   r  ry   r   r|   rê  rê  ì  só   „ ØðyÐ<Mð yÐRUò yó ðyð@ ð #Ø!%Ø,0Ø7;Ø#'ñByØ$ðByà�t‘ðByð ˜$‘JðByð ˜c‘] TÑ)ð	Byð
 $ C¨ HÑ-°Ñ4ðByð ˜D‘LðByð 
òByó ðByðH ðyØðyà	˜$Ñ	òyó ñyr   rê  c              ƒ   óÌ  K  — 	 |j                  | d||¬«      ƒ d{  –—† S 7 Œ# t        $ rµ}t        j                  |«      ršd}t	        |d«      rgt        |dd«      }t        |t        t        f«      sd}t        |dd	«      }t        |t        t        f«      sd	}|j                  d
||¬«      ƒ d{  –—†7  }|r#|j                  | d||¬«      ƒ d{  –—†7  cY d}~S ‚ d}~ww xY w­w)zY
    Fetch key object from DB and retry once if a DB connection error can be healed.
    Úcombined_view)r‡   Ú
table_namer€  r~  NFÚattempt_db_reconnectÚ"_db_auth_reconnect_timeout_secondsg       @Ú'_db_auth_reconnect_lock_timeout_secondsgš™™™™™¹?Ú"auth_get_key_object_lookup_failure)ÚreasonÚtimeout_secondsÚlock_timeout_seconds)
Úget_datar  rT   Úis_database_transport_errorr’  r'  r(  r¶   râ   r  )r“  rí  r€  r~  r@  Údid_reconnectÚauth_reconnect_timeoutÚauth_reconnect_lock_timeouts           r|   Ú(_fetch_key_object_from_db_with_reconnectr)  g  s  è ø€ ðØ"×+Ñ+ØØ&Ø-Ø/ð	 ,ó 
÷ 
ð 	
ð 
ùô ò Ü#×?Ñ?ÀÔBØ!ˆMÜ�}Ð&<Ô=Ü)0°Ð@dÐfiÓ)jÐ&Ü!Ð"8¼3Ä¸,ÔGØ-0Ð*Ü.5°mÐEnÐpsÓ.tÐ+Ü!Ð"=ÄÄU¸|ÔLØ25Ð/Ø&3×&HÑ&HØ?Ø$:Ø)Dð 'Ió '÷ !ð !�ñ
 Ø*×3Ñ3Ø&Ø.Ø%5Ø&7ð	 4ó ÷ ð õ ð 	ûð-üs[   ‚C$„# œ!�#  C$¡# £	C!¬BCÂ0B3Â1CÃCÃCÃC!ÃC$ÃCÃC!Ã!C$Újwt_claim_nameÚjwt_claim_valuec              ƒ   óŒ   K  — t        t        |«      «      j                  | |ddœ¬«      ƒ d{  –—† }|�|j                  S y7 Œ­w)z–
    Lookup a JWT-to-virtual-key mapping from the database.

    Returns the hashed token (str) if a matching active mapping is found, else None.
    T)r*  r+  Ú	is_activer…  N)rÂ   rd   r¬   r‡   )r*  r+  rí  Úmappings       r|   Úget_jwt_key_mapping_objectr/  �  sV   è ø€ ô 2Ô2IÈ-Ó2XÓY×dÑdà,Ø.Øñ
ð eó ÷ €Gð ÐØ�}‰}ÐØðús   ‚,A®A¯Ac              ƒ   ó®  K  — |€t        d«      ‚| }|j                  |t        ¬«      ƒ d{  –—† }|�t        |¬«      S |rt        d|› d�«      ‚t	        | |||¬«      ƒ d{  –—† }|€/t        d| › d	�t        j                  d
t        j                  ¬«      ‚t        j                  |j                  d¬«      «      }	|	j                  r4|	j                  s(	 t        |	j                  ||||¬«      ƒ d{  –—† |	_        t#        | |	||¬«      ƒ d{  –—†  |	S 7 Œé7 Œµ7 Œ&# t         $ r+}
t        j                   d|	j                  |
«       Y d}
~
ŒNd}
~
ww xY w7 ŒC­w)z–
    - Check if team id in proxy Team Table
    - if valid, return LiteLLM_TeamTable object with defined limits
    - if not, then raise an error
    NrÈ  r‚  r–  z8Key doesn't exist in cache + check_cache_only=True. key=rÊ  )r“  rí  r€  r~  z=Authentication Error, Invalid proxy server token passed. key=z7, not found in db. Create key via `/key/generate` call.rù   r   Trû  r¿  zIFailed to load object_permission for key with object_permission_id=%s: %s)r“  r”  rî  r~  )r  rû   r=   r—  r)  r:   r9   Útoken_not_found_in_dbr   ÚHTTP_401_UNAUTHORIZEDrŠ  rŒ   r¡  r×  rÁ  r   r2  r™  )r“  rí  rî  r€  r~  rÆ  rù   Úuser_api_key_authÚ_valid_tokenrÝ  r@  s              r|   Úget_key_objectr5  §  s¥  è ø€ ð ÐÜÐ`ÓaÐað €Cð &8×%GÑ%GØÜ!ð &Hó &÷  Ðð Ð$Ü0ÐBSÔTÐTáÜÐRÐSVÐRWÐWXÐYÓZÐZô 3[Ø!Ø#Ø)Ø+ô	3÷ -€Lð ÐÜØSÐT`ÐSað  bYð  ZÜ ×6Ñ6ØÜ×-Ñ-ô	
ð 	
ô &×4Ñ4°\×5LÑ5LÐZ^Ð5LÓ5_Ó`€Ið ×%Ò%¨i×.IÒ.Ið	Ü0EØ%.×%CÑ%CØ+Ø#5Ø!1Ø"3ô1÷ +ˆIÔ'ô Ø!Ø"Ø-Ø+ô	÷ ð ð Ððk øð-øð(+ùô ò 	Ü ×&Ñ&Ø[Ø×.Ñ.Ø÷ñ ûð	úðúsj   ‚*E¬D­5EÁ"DÁ#A2EÃD Ã3DÃ4	D Ã=EÄEÄEÄEÄD Ä	EÄ%!EÅEÅEÅEc                 ó^   — | j                  «       }d |_        d |_        d |_        d |_        |S rx   )rS  Úbudget_reservationÚbudget_throttle_pctr€  Úrequest_route)r”  Úcopied_key_objs     r|   r—  r—  õ  s8   € ð -×7Ñ7Ó9€NØ(,€NÔ%Ø)-€NÔ&Ø&*€NÔ#Ø#'€NÔ ØÐr   r¡  c              ƒ   ó¬  K  — |€t        d«      ‚t        | «      }|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 t	        t        |«      «      j                  d| i¬«      ƒ d{  –—† }|€yt        j                  |j                  «       «      }|j                  ||t        t        |«      ¬«      ƒ d{  –—†  |S 7 Œ‰7 ŒX7 Œ
# t         $ r Y yw xY w­w)z¦
    - Check if object permission id in proxy ObjectPermissionTable
    - if valid, return LiteLLM_ObjectPermissionTable object
    - if not, then raise an error
    NrÈ  r‚  r¡  r…  r†  )r  rO   rû   r-   r¿   r^   r¨   rŠ  r}   r‹  rK   )	r¡  rí  rî  r€  r~  rù   Údeserialized_permrÜ  Ú	_perm_objs	            r|   rÁ  rÁ     s  è ø€ ð ÐÜÐ`ÓaÐaô -Ð-AÓB€CØ%7×%GÑ%GØÜ0ð &Hó &÷  Ðð Ð$Ø Ð ðÜ /Ô0JÈ=Ó0YÓ Z× fÑ fØ)Ð+?Ð@ð !gó !
÷ 
ˆð ÐØä8×GÑGÈÏÉËÓXˆ	Ø ×0Ñ0ØØÜ4Ü)Ð*<Ó=ð	 1ó 
÷ 	
ð 	
ð Ðð1 øð
øð	
ùô ò Ùðüsc   ‚3CµB?¶C¿)C Á(CÁ)C Á/CÁ0AC Â8CÂ9C Â>CÃC ÃC Ã	CÃCÃCÃCÚuuidsc           	   ƒ   óè  K  — | r|€g S g }g }| D ]K  }d|› �}|j                  |t        ¬«      ƒ d{  –—† }	|	�|j                  |	«       Œ;|j                  |«       ŒM |s|S t        t	        |«      «      j                  dd|iit        |«      ¬«      ƒ d{  –—† }
|
D ]É  }t        |d«      r|j                  «       nt        |d«      r|j                  «       nd}t        |t        «      r|st        |d	«      rt        |«      ni }|sŒkt        j                  |«      }d|j                  › �}|j                  ||t        t        |«      ¬
«      ƒ d{  –—†  |j                  |«       ŒË |S 7 �Œ:7 Œ×7 Œ­w)aP  
    Fetch managed vector store rows by their internal UUIDs.

    Follows the get_team_object / get_key_object / get_object_permission pattern:
    cache-first lookup (in-memory / Redis), DB fallback only on cache miss.
    Critical-path DB access must go through this helper to avoid raw Prisma
    calls on the hot request path.
    Nzmanaged_vector_store_id:r‚  Úvector_store_idrþ  rÅ  rŒ   r}   Ú__dict__r†  )rû   r,   r{  rÉ   re   r¯   rv  r’  rŒ   r}   r(  rŠ  r@  r‹  rK   )r>  rí  rî  r€  r~  r¡  Úcache_missesÚuuidrù   Údeserialized_vsÚrowsrÈ  Úrow_dictÚ
cached_objs                 r|   Ú&get_managed_vector_store_rows_by_uuidsrH  /  sž  è ø€ ñ  �MÐ)Øˆ	à<>€FØ%'€Làò 	&ˆØ(¨¨Ð/ˆØ 2× BÑ BØÜ7ð !Có !
÷ 
ˆð Ð&Ø�M‰M˜/Õ*à×Ñ Õ%ð	&ñ Øˆä+Ô,IÈ-Ó,XÓY×cÑcØ  4¨Ð"6Ð7Ü�Óð dó ÷ €Dð
 ò "ˆÜ'.¨s°LÔ'A�3—>‘>Ô#ÔV]Ð^aÐciÔVjÈÏÉÌ
ÐptˆÜ˜(¤DÔ)±Ü$+¨C°Ô$<”t˜C”yÀ"ˆHÙØÜ5×DÑDÀXÓNˆ
Ø(¨×)CÑ)CÐ(DÐEˆØ ×0Ñ0ØØÜ7Ü)Ð*<Ó=ð	 1ó 
÷ 	
ð 	
ð 	�‰�jÕ!ð"ð  €MðC
ùðøð	
ús5   ‚/E2±E+²A$E2ÂE.ÂB:E2ÅE0ÅE2Å.E2Å0E2c                   ó   — e Zd ZdZy)ÚOrganizationNotFoundErrora^  The organization row is CONFIRMED absent, as opposed to a lookup that failed.

    Subclasses Exception so every existing except Exception caller keeps its current
    behavior; it exists so a caller that wants to treat "no such org" as "no restriction" can do
    that WITHOUT also swallowing an outage and silently dropping a real org ceiling.
    Nr¬  ry   r   r|   rJ  rJ  k  s   „ òr   rJ  Úorg_idÚinclude_budget_tablec              ƒ   óü  K  — |€t        d«      ‚t        | t        «      syd| › �}|rd| › d�}|j                  |t        ¬«      ƒ d{  –—† }|�|S 	 dd| ii}|rdd	i|d
<    t        t        |«      «      j                  di |¤Žƒ d{  –—† }	|	€t        d| › d�«      ‚t	        j                  |	j                  «       «      }
|j                  ||
t        t        ¬«      ƒ d{  –—†  |
S 7 ŒŸ7 Œa# t         $ r ‚ w xY w7 Œ­w)aÜ  
    - Check if org id in proxy Org Table
    - if valid, return LiteLLM_OrganizationTable object
    - if not, then raise an error

    Args:
        org_id: Organization ID to look up
        prisma_client: Database client
        user_api_key_cache: Cache for storing results
        parent_otel_span: Optional OpenTelemetry span
        proxy_logging_obj: Optional proxy logging object
        include_budget_table: If True, includes litellm_budget_table in the query
    NrÈ  rá  z:with_budgetr‚  r¥   r  ré   Tr¤   z/Organization doesn't exist in db. Organization=z3. Create organization via `/organization/new` call.r†  ry   )r  r(  rƒ   rû   r/   rÅ   r_   r¨   rJ  rŠ  rŒ   r‹  r   )rK  rí  rî  r€  r~  rL  rŒ  Údeserialized_orgÚquery_kwargsrÜ  Ú_org_objs              r|   Úget_org_objectrQ  t  sX  è ø€ ð, ÐÜÐ`ÓaÐaÜ�fœcÔ"Øð ˜&˜Ð"€IÙØ˜f˜X \Ð2ˆ	ð %7×$FÑ$FØÜ,ð %Gó %÷ Ðð Ð#ØÐðØ@GÐJ[Ð]cÐIdÐ?eˆÙØ'=¸tÐ&DˆL˜Ñ#à dÔ 1Ô2HÈÓ2WÓ X× dÑ dÑ tÐgsÑ t×tˆð ÐÜ'Ø=¸f¸XÐExÐyó
ð 	
ô 0×>Ñ>¸x×?RÑ?RÓ?TÓU€Hà
×
,Ñ
,ØØÜ,Ü!ð	 -ó ÷ ð ð €OðGøð uùÜò ð 	ðúðúsI   ‚AC<ÁC(Á	C<Á6C, ÂC*Â	C, ÂAC<Ã!C:Ã"C<Ã*C, Ã,C7Ã7C<Úaccess_group_idsÚresource_field)Úaccess_model_namesÚaccess_mcp_server_idsÚaccess_agent_idsc              ƒ   ó\  K  — | sg S |�|€$ddl m} ddl m} ddl m} |xs |}|xs |}|xs |}|€g S g }| D ]6  }		 t	        |	|||¬«      ƒ d{  –—† }
|j                  t        |
|g «      «       Œ8 t        t        |«      «      S 7 Œ6# t        $ r t        j                  d|	|«       Y Œqw xY w­w)a]  
    Fetch access groups by their IDs (from cache or DB) and collect
    the specified resource field across all of them.

    Args:
        access_group_ids: List of access group IDs to fetch
        resource_field: Which resource list to extract from each access group
            - "access_model_names": model names (for model access checks)
            - "access_mcp_server_ids": MCP server IDs (for MCP access checks)
            - "access_agent_ids": agent IDs (for agent access checks)
        prisma_client: Optional PrismaClient (lazy-imported from proxy_server if None)
        user_api_key_cache: Optional DualCache (lazy-imported from proxy_server if None)
        proxy_logging_obj: Optional ProxyLogging (lazy-imported from proxy_server if None)

    Returns:
        Deduplicated list of resource identifiers from all resolved access groups.
    Nr   ©rí  ©r~  ©rî  ©rÌ  rí  rî  r~  z5Could not fetch access group %s for resource field %s)r  rí  r~  rî  rÖ  ry  r'  r  r   r2  rÑ  rx  )rR  rS  rí  rî  r~  Ú_prisma_clientÚ_proxy_logging_objÚ_user_api_key_cacheÚ	resourcesÚag_idÚags              r|   Ú!_get_resources_from_access_groupsrb  »  sÞ   è ø€ ñ0 Øˆ	ð ÐÐ 2Ð :ÝNÝVÝXà%Ò7¨ˆØ/ÒFÐ3FÐØ-ÒCÐ1CÐàÐ!Øˆ	à"$€IØ!ò ˆð	Ü(Ø %Ø+Ø#5Ø"3ô	÷ ˆBð ×ÑœW R¨¸Ó<Õ=ðô ”�I“ÓÐðùô ò 	Ü ×&Ñ&ØGØØöð	üs:   ‚8B,»BÁBÁ BÁ.B,ÂBÂ B)Â&B,Â(B)Â)B,c              ƒ   ó>   K  — t        | d|||¬«      ƒ d{  –—† S 7 Œ­w)z{
    Collect model names from unified access groups.
    Models are matched by model name for backwards compatibility.
    rT  ©rR  rS  rí  rî  r~  N©rb  ©rR  rí  rî  r~  s       r|   Ú_get_models_from_access_groupsrg  ö  s.   è ø€ ô 3Ø)Ø+Ø#Ø-Ø+ô÷ ð ð úó   ‚–—c              ƒ   ó>   K  — t        | d|||¬«      ƒ d{  –—† S 7 Œ­w)z_
    Collect MCP server IDs from unified access groups.
    MCPs are matched by server ID.
    rU  rd  Nre  rf  s       r|   Ú&_get_mcp_server_ids_from_access_groupsrj  	  s.   è ø€ ô 3Ø)Ø.Ø#Ø-Ø+ô÷ ð ð úrh  c              ƒ   ó>   K  — t        | d|||¬«      ƒ d{  –—† S 7 Œ­w)z[
    Collect agent IDs from unified access groups.
    Agents are matched by agent ID.
    rV  rd  Nre  rf  s       r|   Ú!_get_agent_ids_from_access_groupsrl    s.   è ø€ ô 3Ø)Ø)Ø#Ø-Ø+ô÷ ð ð úrh  c                 ó  — t         j                  j                  | vs|�|€| S |j                  «       }| D �cg c]"  }|t         j                  j                  k7  sŒ!|‘Œ$ }}|s|xs | S t	        t
        j                  ||z   «      «      S c c}w rx   )r<   Úall_team_modelsr�   Úget_model_namesrÑ  r}   Úfromkeys)rq  r$  r
  Úproxy_modelsr*  Únon_sentinel_modelss         r|   Ú/_resolve_all_team_model_sentinel_for_auth_checkrs  /  s‹   € ô
 ×(Ñ(×.Ñ.°fÑ<ÀÀÐS]ÐSeØˆØ$×4Ñ4Ó6€LØ5;Ö!p¨E¸uÔHY×HiÑHi×HoÑHoÓ?o¢%Ð!pÐÐ!pÙØ"Ò, fÐ,Ü”—‘Ð1°LÑ@ÓAÓBÐBùò "qs   ·"B	ÁB	ró  c                 óÄ  — ddl m}  |t        «      }|r|j                  | |¬«      }t	        |||¬«      }t        |«      dkD  r|�t        |«      D ]  \  }}||v sŒ y |D �cg c]	  }||vsŒ|‘Œ }	}t        | |¬«      ryt        | |	¬«      ryd}
t        |	«      dk(  rt        |«      dk(  sd	|	v rd}
t        j                  j                  |	v rd}
| �	| |	vr|
du ryyc c}w )
Nr   r(  ©r:  r
  )rq  r$  r
  T©r*  ró  ©r*  Úallowed_model_listFÚ*)r*  r)  rÑ  r+  rs  rv  r,  Ú_model_in_team_aliasesÚ+_model_matches_any_wildcard_pattern_in_listr<   Úall_proxy_modelsr�   )r*  r$  rq  ró  r
  r)  r-  r.  r/  r0  Úall_model_accesss              r|   Ú_check_model_access_helperr~  =  s  € õ (á*5´dÓ*;€MáØ"×:Ñ:ÀeÐU\Ð:Ó]ˆä<ØØØô€Fô ˆ=Ó˜AÒ *Ð"8Ü Ó'ò 	‰FˆC�Ø�MÒ!Ùð	ð
 *0ÖJ A°1¸MÒ3IšaÐJ€OÐJä EÐ>PÕQØä2¸ÐSbÕcØà"ÐäˆOÓ Ò!¤c¨&£k°QÒ&6¸3À/Ñ;QØÐä×)Ñ)×/Ñ/°?ÑBØÐàÐ˜U¨/Ñ9Ð>NÐRWÑ>WØØùò% Ks   Á#	CÁ-CÚobject_type)r‘  r  rù   rä  ÚprojectÚfallback_depthTc                 ó  — |t         k\  rt        d| › �«      ‚t        | t        «      r| D ]  }t	        |||||||dz   ¬«       Œ y| g}| t
        j                  v r#|j                  t
        j                  |    «       n4|r2| |j                  v r$|j                  | «      }	|	r|j                  |	«       |D ]  }t        |||||¬«      sŒ y t        |› d|› d|› d| › �t        j                  |¬	«      d
t        j                  ¬«      ‚)aÅ  
    Checks if token can call a given model

    Args:
        - model: str
        - llm_router: Optional[Router]
        - models: List[str]
        - team_model_aliases: Optional[Dict[str, str]]
        - object_type: Literal["user", "team", "key", "org"]. We use the object type to raise the correct exception type

    Returns:
        - True: if token allowed to call model

    Raises:
        - Exception: If token not allowed to call model
    zEUnable to parse model, max fallback depth exceeded - received model: rn   )r*  r$  rq  ró  r
  r  r�  T)r*  r$  rq  ró  r
  z# not allowed to access model. This z can only access models=z. Tried to access )r  r*  r   )r   r  r(  rÑ  Ú_can_object_call_modelrJ  Úmodel_alias_mapr{  Úmodel_group_aliasÚ_get_model_from_aliasr~  r:   r9   Ú&get_model_access_error_type_for_objectr   rÓ  )
r*  r$  rq  ró  r
  r  r�  r/  Úpotential_modelsr{  s
             r|   rƒ  rƒ  m  sI  € ð2 Ô2Ò2ÜÐ_Ð`eÐ_fÐgÓhÐhÜ�%œÔØò 		ˆAÜ"ØØ%ØØ#5ØØ'Ø-°Ñ1öð		ð à$˜gÐØ”×'Ñ'Ñ'Ø×Ñ¤× 7Ñ 7¸Ñ >Õ?Ù	˜ ×!=Ñ!=Ñ=Ø"×8Ñ8¸Ó?ˆÙØ×#Ñ# FÔ+ð ò ˆÜ%ØØ!ØØ1Øö
ñ ðô Ø�-ÐBÀ;À-ÐOgÐhnÐgoð  pBð  CHð  BIð  JÜ×CÑCÐP[Ô\ØÜ×&Ñ&ô	ð r   c                 ó   — |r| |v ryy)a  
    Returns True if `model` being accessed is an alias of a team model

    - `model=gpt-4o`
    - `team_model_aliases={"gpt-4o": "gpt-4o-team-1"}`
        - returns True

    - `model=gp-4o`
    - `team_model_aliases={"o-3": "o3-preview"}`
        - returns False
    TFry   rv  s     r|   rz  rz  °  s   € ñ ØÐ&Ñ&ØØr   c                 ó¾   — t        | j                  xs g «      }t        j                  j                  |v r'| j
                  €g S t        | j                  xs g «      S |S )aJ  
    Expand key model sentinels before auth checks.

    ``all-team-models`` means inherit the parent team's allowlist -- same
    semantics as ``get_key_models`` in ``model_checks.py``.

    If the key has no team_id, it inherits the full proxy model list
    (equivalent to an empty models field, i.e. unrestricted access).
    )rÑ  rq  r<   rn  r�   r
  r&  )r}  rq  s     r|   Ú"_resolve_key_models_for_auth_checkr‹  Â  sY   € ô ˜×+Ñ+Ò1¨rÓ2€FÜ×(Ñ(×.Ñ.°&Ñ8Ø×ÑÐ&ØˆIÜ�K×+Ñ+Ò1¨rÓ2Ð2Ø€Mr   c                 ól   ‡‡— t        | t        «      r| fn
t        | «      }t        ˆˆfd„|D «       «      S )zHEvery model access group whose deployments serve the requested model(s).c              3   óR   •K  — | ]  }‰j                  |‰¬ «      D ]  }|–— Œ Œ  y­w)ru  N)r+  )r  Úrequested_modelr
  r$  r
  s      €€r|   r  z5_model_access_groups_serving_model.<locals>.<genexpr>Û  s?   øè ø€ ò àØ×7Ñ7À?Ð\cÐ7Ódòð ô 	ðØñùó   ƒ$')r(  rƒ   r—   r¶  )r*  r$  r
  Ú	requesteds    `` r|   Ú"_model_access_groups_serving_modelr‘  Ô  s5   ù€ ô $.¨e´SÔ#9˜‘x¼uÀU»|€IÜô à(ôó ð r   c              ƒ   ó¢   K  — |�| j                   €yt        | j                   |j                  |||¬«      ƒ d{  –—† }|€dS t        |«      S 7 Œ­w)z`The member's own ``allowed_models`` scope; empty when the member is not narrowed below the team.Nry   ©rš   r
  rí  rî  r~  )rš   r%  r
  rö   )r}  r·  rí  rî  r~  Úteam_memberships         r|   Ú_team_member_granted_modelsr•  â  sc   è ø€ ð Ð˜k×1Ñ1Ð9Øä#6Ø×#Ñ#Ø×#Ñ#Ø#Ø-Ø+ô$÷ €Oð !Ð(ˆ2ÐUÔ.DÀ_Ó.UÐUðús   ‚7A¹AºAc              ƒ   óø   K  — | j                   xs |�|j                  nd}|€y	 t        ||||¬«      ƒ d{  –—† }|�|j                  S dS 7 Œ# t        $ r }t	        j
                  d|«       Y d}~yd}~ww xY w­w)zYThe org allowlist reached through the key, or through its team when the key names no org.Nry   )rK  rí  rî  r~  z/access group attribution: org lookup failed: %s)rK  r  rQ  r  r   r2  rq  )r}  r·  rí  rî  r~  rK  Ú
org_objectr@  s           r|   Ú_org_granted_modelsr˜  ÷  s‘   è ø€ ð  ×&Ñ&ÒlÈ+ÐJa¨;×+FÒ+FÐgk€FØ€~Øð	Ü"0ØØ'Ø1Ø/ô	#
÷ 
ˆ
ð !+Ð 6ˆ:×ÑÐ>¸BÐ>ð
ùô ò Ü×"Ñ"Ð#TÐVWÔXÜûðüs=   ‚"A:¥A ·A¸A ¼A:ÁA Á	A7ÁA2Á-A:Á2A7Á7A:c              ƒ   óÄ   K  — t        | ¬«      |�|j                  ndt        | ||||¬«      ƒ d{  –—† |�|j                  ndt        | ||||¬«      ƒ d{  –—† fS 7 Œ+7 Œ­w)zKOne model allowlist per level that participates in authorizing the request.r  Nry   r  )r‹  rq  r•  r˜  ©r}  r·  rz  rí  rî  r~  s         r|   Ú_granted_model_listsr›    s   è ø€ ô 	+°{ÔCØ)Ð5ˆ×Ò¸2Ü)Ø#Ø#Ø'Ø1Ø/ô
÷ 	
ð "0Ð!;ˆ×ÒÀÜ!Ø#Ø#Ø'Ø1Ø/ô
÷ 	
ðð ð	
øð	
ús!   ‚.A °A±%A ÁAÁA ÁA c              ƒ   ó   K  — | �|�|�|€yt        ||¬«      ƒ d{  –—† }|�|syt        | ||j                  ¬«      }	|€|	n|	|z  }
|
syt        d„ t	        ||||||¬«      ƒ d{  –—† D «       «      }t        t        |
|z  «      «      S 7 Œm7 Œ&­w)a¤  
    The budgeted model access groups that authorized this request, sorted and deduplicated.

    A group is charged only when its name appears on an allowlist the caller was granted -- key,
    team, team-member scope, project or org -- *and* that group serves the requested model. Asking
    for a model that merely belongs to a group attributes nothing, because nothing about the caller
    named the group.

    Levels are unioned, never ranked: a team granted ``*`` whose member is scoped to one group is
    still a caller gated by that group. An unrestricted allowlist (empty, ``*``) names no group and
    so contributes nothing.

    The whole walk is gated on the budget registry, because collecting every match costs a full scan
    of each allowlist where the plain access check stops at the first hit. An empty registry means no
    group carries a budget, so there is nothing to attribute and no work worth doing.
    Nry   rì  )r*  r$  r
  c              3   ó.   K  — | ]  }|D ]  }|–— Œ Œ y ­wrx   ry   )r  Úgranted_modelsÚgranted_models      r|   r  z6collect_matched_model_access_groups.<locals>.<genexpr>[  s/   è ø€ ò àð ,òð ô 	ðØñùs   ‚rš  )rû  r‘  r
  r¶  r›  r—   Úsorted)r*  r}  r·  rz  r$  rí  rî  r~  rÓ  Úcovering_groupsÚbudgeted_groupsÚgranteds               r|   Ú#collect_matched_model_access_groupsr¤  .  sÉ   è ø€ ð4 €}˜Ð+¨zÐ/AÀ]ÐEZØä=Ø#Ø-ô÷ €Hð Ð¡HØä?ØØØ×#Ñ#ô€Oð
 19Ð0@™_ÀoÐX`ÑF`€OÙØäñ ä$8Ø#Ø#Ø)Ø'Ø1Ø/ô%
÷ 
ôó €Gô ”˜¨'Ñ1Ó2Ó3Ð3ð9øð$
ús"   ‚BœB
�ABÁ%B
Á&%BÂBc           
   ƒ   óÒ   K  — |€y	 t        | |||||||¬«      ƒ d{  –—† }|syt	        |«      }
|
|_        |S 7 Œ# t        $ r }	t        j                  d|	«       Y d}	~	yd}	~	ww xY w­w)z¬Record the groups that authorized this request on its auth object, for the post-call spend
    writer and the reservation counters, and hand them back for the budget check.Nry   rû  z)model access group attribution failed: %s)r¤  r  r   r2  rÑ  r  )r*  r}  r·  rz  r$  rí  rî  r~  Úmatchedr@  Úmatched_groupss              r|   r0  r0  j  s†   è ø€ ð ÐØðÜBØØ#Ø#Ø)Ø!Ø'Ø1Ø/ô	 
÷ 	
ˆñ ØÜ  ›M€NØ.<€KÔ+Ø€Nð#	
ùô ò Ü×"Ñ"Ð#NÐPQÔRÜûðüs7   ‚A'‡; �9ž; ¢A'¹; »	A$ÁAÁA'ÁA$Á$A'Úllm_model_listc           	   ƒ   ó*  K  — t        |¬«      }	 t        | |||j                  |j                  d¬«      S # t        $ rR |j
                  xs g }|r>t        |¬«      ƒ d{  –—†7  }|r't        | |||j                  |j                  d¬«      cY S ‚ w xY w­w)aM  
    Checks if token can call a given model

    1. First checks native key-level model permissions (current implementation)
    2. If not allowed natively, falls back to access_group_ids on the key

    Returns:
        - True: if token allowed to call model

    Raises:
        - Exception: If token not allowed to call model
    r  rù   ©r*  r$  rq  ró  r
  r  ©rR  N)r‹  rƒ  ró  r
  r:   rR  rg  )r*  r¨  r}  r$  Ú
key_modelsÚkey_access_group_idsÚmodels_from_groupss          r|   Úcan_key_call_modelr¯  Ž  s³   è ø€ ô$ ;À{ÔS€JðÜ%ØØ!ØØ*×=Ñ=Ø×'Ñ'Øô
ð 	
øô ò à&1×&BÑ&BÒ&HÀbÐÙÜ.LØ!5ô/÷ )ð )Ðñ "Ü-ØØ)Ø-Ø'2×'EÑ'EØ'×/Ñ/Ø %ôò ð 	ð!üs1   ‚B�$5 ´Bµ*BÁA"Á ,BÂBÂBÂBc           
   ƒ   ó:  K  — ddl m}m}m} |j                  xsB t        |j                  t        «      xr& t        j                  j                  |j                  v }|st        | |||¬«      ƒ d {  –—†  d }d}	|j                  �/	 t        |j                  |||j                  |¬«      ƒ d {  –—† }d}	|�J	 t/        | |||j0                  ¬«      ƒ d {  –—†  |j<                  �|	rt?        | ||||||¬
«      ƒ d {  –—†  |j@                  �LtC        |j@                  |||¬«      ƒ d {  –—† }|�(tE        |j                  «      dkD  rtG        | ||¬«       y y y y 7 Œè7 Œ­# t        $ r\ t!        |j                  |j"                  |j$                  |j&                  |j(                  |j*                  |j,                  ¬«      }Y �Œw xY w7 Œñ# t2        $ rB}
|
j4                  t6        j8                  k7  r‚ t;        | |||¬	«      ƒ d {  –—†7  s‚ Y d }
~
�Œ5d }
~
ww xY w7 �Œ7 Œï­w)Nr   )rí  r~  rî  )r*  r¨  r}  r$  F)r
  rí  rî  r€  r~  T)r
  rq  r�  rw  rž  r¡  r×  rò  rô  rõ  )r‚  rí  rî  r~  r€  )$r  rí  r~  rî  Úconfigr(  rq  rÑ  r<   rn  r�   r¯  r
  r  r€  r  r4   r&  Úteam_blockedrw  rÐ  Úteam_object_permission_idÚteam_object_permissionr'  ró  r:   r  r9   r(  r)  rš   r*  r‚  Úget_project_objectrv  rƒ  )r*  r¨  r}  r$  rí  r~  rî  Úskip_key_model_checkr·  Úteam_object_from_lookuprC  rz  s               r|   Úcan_key_call_resolved_modelr¸  ½  s^  è ø€ ÷ñ ð #.×"4Ñ"4ò #Ü�;×%Ñ%¤tÓ,ÒnÔ1B×1RÑ1R×1XÑ1XÐ\g×\nÑ\nÐ1nð ñ  Ü ØØ)Ø#Ø!ô	
÷ 	
ð 	
ð 6:€KØ#ÐØ×ÑÐ&ð	Ü /Ø#×+Ñ+Ø+Ø#5Ø!,×!=Ñ!=Ø"3ô!÷ ˆKð '+Ð#ð Ðð	Ü'ØØ'Ø%Ø#.×#AÑ#Aô	÷ ð ð" ×ÑÐ*Ñ/FÜ1ØØ'Ø'Ø%Ø+Ø#5Ø"3ô÷ ð ð ×ÑÐ)Ü&8Ø"×-Ñ-Ø'Ø1Ø/ô	'
÷ !
ˆð Ð%¬#¨n×.CÑ.CÓ*DÀqÒ*HÜ$ØØ-Ø%öð +IÐ%ð *ðy	
øðùô ò 		Ü4Ø#×+Ñ+Ø"×.Ñ.Ø#×0Ñ0Ø&×1Ñ1Ø$×2Ñ2Ø%0×%JÑ%JØ"-×"DÑ"Dô‹Kð		úðùô ò 		Ø×Ñ¤?×#KÑ#KÒKØÜ7ØØ'Ø'Ø%ô	÷ ñ ð õûð		úðùð!
ús¯   ‚A/HÁ1EÁ2HÂ'E Â.EÂ/E Â5HÂ8G ÃGÃG Ã#HÃ<HÃ=,HÄ)HÄ*1HÅE ÅA!GÆ?HÇGÇHÇG Ç	HÇ0HÈHÈHÈHÈHÈHÈHr—  c                 ó>   — t        | ||r|j                  ng |d¬«      S )z@
    Returns True if the team can access a specific model.

    rä  )r*  r$  rq  ró  r  ©rƒ  rq  )r*  r—  r$  ró  s       r|   Úcan_org_access_modelr»    s*   € ô "ØØÙ$.ˆz× Ò °BØ-Øôð r   c           	   ƒ   ó  K  — 	 t        | ||r|j                  ng ||r|j                  ndd¬«      S # t        $ rP |r|j                  xs g ng }|r8t        |¬«      ƒ d{  –—†7  }|r!t        | ||||r|j                  ndd¬«      cY S ‚ w xY w­w)zÜ
    Returns True if the team can access a specific model.

    1. First checks native team-level model permissions (current implementation)
    2. If not allowed natively, falls back to access_group_ids on the team
    Nr  rª  r«  )rƒ  rq  r
  r:   rR  rg  )r*  r·  r$  ró  Úteam_access_group_idsr®  s         r|   r'  r'  +  s²   è ø€ ðÜ%ØØ!Ù)4�;×%Ò%¸"Ø1Ù+6�K×'Ò'¸DØô
ð 	
øô ò áOZ¨×(DÑ(DÒ(JÉÐ`bÐÙ Ü.LØ!6ô/÷ )ð )Ðñ "Ü-ØØ)Ø-Ø'9Ù3>˜K×/Ò/ÀDØ &ôò ð 	ð!üs1   ‚B„,1 °B±.B
ÁA"Á &B
ÂBÂB
Â
Bc              ƒ   ó"  K  — | €g S t        | j                  xs g «      }|sg S ddlm} ddlm} ddlm} |�|€g S | j                  xs |�|j                  nd}| j                  }g }	|D ]}  }
	 t        |
|||¬«      ƒ d{  –—† }t        |xr ||j                  xs g v «      }t        |xr ||j                  xs g v «      }|s|sŒ^|	j                  t        ||g «      xs g «       Œ t        t        |	«      «      S 7 Œ}# t        $ r Y Œ¡w xY w­w)uÝ  
    For each access_group_id on the key, fetch the LiteLLM_AccessGroupTable row
    and contribute its `resource_field` only if the group authorizes the caller
    as an owner â€” that is, the group's `assigned_team_ids` includes the key's
    `team_id`, or the group's `assigned_key_ids` includes the key's token. This
    preserves the team-as-owner boundary while still letting a group reach the
    key without first being added to the team's `access_group_ids` list.
    Nr   rX  rY  rZ  r[  )rÑ  rR  r  rí  r~  rî  r
  r‡   rÖ  r  rQ  Úassigned_team_idsÚassigned_key_idsry  r'  rx  )r}  r·  rS  r­  r\  r]  r^  Úkey_team_idÚ	key_tokenÚauthorized_resourcesr`  ra  Úteam_authorizedÚkey_authorizeds                 r|   Ú/get_authorized_resources_from_key_access_groupsrÆ  S  s9  è ø€ ð ÐØˆ	Ü"& {×'CÑ'CÒ'IÀrÓ"JÐÙØˆ	åJÝRÝTàÐÐ!4Ð!<Øˆ	à$×,Ñ,ÒjÈÐH_°×1DÒ1DÐei€KØ"×(Ñ(€Ià-/ÐØ%ò Oˆð	Ü(Ø %Ø,Ø#6Ø"4ô	÷ ˆBô ˜{ÒZ¨{¸r×?SÑ?SÒ?YÐWYÐ/ZÓ[ˆÜ˜iÒT¨I¸"×:MÑ:MÒ:SÐQSÐ,TÓUˆÙšnØ ×'Ñ'¬°°NÀBÓ(GÒ(MÈ2ÕNðOô ”Ð(Ó)Ó*Ð*ðùô ò 	Ùð	üsC   ‚A+DÁ.D Â C>ÂD ÂADÃ6DÃ>D Ä 	DÄ	DÄDÄDc              ƒ   ó¼   K  — t        ||d¬«      ƒ d{  –—† }|sy	 t        | |||r|j                  nd|r|j                  ndd¬«       y7 Œ6# t        $ r Y yw xY w­w)zÆ
    Returns True if the key's `access_group_ids` expand to models that grant
    access to `model`. Used to let a key's access group override a team's
    model restriction in `common_checks`.
    rT  )r}  r·  rS  NFrù   rª  T)rÆ  rƒ  ró  r
  r:   )r*  r}  r·  r$  Úauthorized_modelss        r|   r)  r)  ƒ  s{   è ø€ ô &UØØØ+ô&÷  Ðñ
 ØðÜØØ!Ø$ÙAL˜{×=Ò=ÐRVÙ+6�K×'Ò'¸DØõ	
ð ð! ùô" ò Ùðüs2   ‚A”A•A�-A Á
AÁ	AÁAÁAÁAc                 óH   — t        | ||r|j                  d¬«      S g d¬«      S )zr
    Returns True if the project can access a specific model.

    Raises ProxyException if access is denied.
    r€  ©r*  r$  rq  r  rº  r€  s      r|   rƒ  rƒ  £  s7   € ô "ØØÙ(6ˆ~×$Ñ$Øô	ð ð =?Øô	ð r   c              ƒ   óê   K  — |€yt         j                  j                  |j                  v r.t	        d| › �t
        j                  dt        j                  ¬«      ‚t        | ||j                  d¬«      S ­w)NTzeUser not allowed to access model. No default model access, only team models allowed. Tried to access r*  r   r‘  rÊ  )
r<   Úno_default_modelsr�   rq  r:   r9   Úkey_model_access_deniedr   rÓ  rƒ  rú  s      r|   r/  r/  µ  s…   è ø€ ð
 ÐØä×*Ñ*×0Ñ0°K×4FÑ4FÑFÜØ{ð  }Bð  |Cð  DÜ ×8Ñ8ØÜ×*Ñ*ô	
ð 	
ô "ØØØ×!Ñ!Øô	ð ùs   ‚A1A3r×  c                 ó@   — | €g S | j                   }|sg S t        |«      S )zSReturn allowlisted search tool names from object_permission (empty = unrestricted).)Úsearch_toolsrÑ  )r×  Úraws     r|   Ú)_search_tool_names_from_object_permissionrÑ  Í  s,   € ð Ð Øˆ	Ø"×/Ñ/€CÙØˆ	Ü�‹9Ðr   Úsearch_tool_nameÚallowed_search_tools)rù   r  r€  c                 ó”   — |sy| |v ryt        |j                  «       › d| › d|› �t        j                  dt        j
                  ¬«      ‚)aÄ  
    Check if an object (key/team/project) can access a specific search tool.

    Similar to _can_object_call_model but for search tools.

    Args:
        search_tool_name: The search tool being requested
        allowed_search_tools: List of allowed search tool names for this object
        object_type: Type of object for error messaging

    Returns:
        True if access is allowed

    Raises:
        ProxyException if access is denied
    Tz$ not allowed to access search tool: z. Allowed search tools: rÒ  r   )r:   Ú
capitalizer9   rÍ  r   rÓ  ©rÒ  rÓ  r  s      r|   Ú_can_object_call_search_toolr×  Ù  se   € ñ,  Øð Ð/Ñ/Øô Ø×)Ñ)Ó+Ð,Ð,PÐQaÐPbð c!Ø!5Ð 6ð8ä×4Ñ4Ø Ü×&Ñ&ôð r   c              ƒ   óL   K  — t        | t        |j                  «      d¬«      S ­w)aL  
    Check if a key can access a specific search tool.

    Similar to can_key_call_model but for search tools.

    Args:
        search_tool_name: The search tool being requested
        valid_token: The authenticated key

    Returns:
        True if access is allowed

    Raises:
        ProxyException if access is denied
    rù   rÖ  ©r×  rÑ  r×  ©rÒ  r}  s     r|   Úcan_key_call_search_toolrÛ     s)   è ø€ ô& (Ø)ÜFÀ{×GdÑGdÓeØôð ùs   ‚"$c              ƒ   óR   K  — |€yt        | t        |j                  «      d¬«      S ­w)aJ  
    Check if a team can access a specific search tool.

    Similar to can_team_access_model but for search tools.

    Args:
        search_tool_name: The search tool being requested
        team_object: The team object

    Returns:
        True if access is allowed

    Raises:
        ProxyException if access is denied
    Tr  rÖ  rÙ  ©rÒ  r·  s     r|   Úcan_team_call_search_toolrÞ    s2   è ø€ ð& ÐØä'Ø)ÜFÀ{×GdÑGdÓeØôð ùs   ‚%'c              ƒ   óˆ   K  — 	 t        | |¬«      ƒ d{  –—†  t        | |¬«      ƒ d{  –—†  y7 Œ7 Œ# t        $ r Y yw xY w­w)z¨
    Boolean variant of the key + team authorization enforced on /search, used to
    scope /search_tools/list so a non-admin caller only sees tools it may invoke.
    rÚ  NrÝ  FT)rÛ  rÞ  r:   )rÒ  r}  r·  s      r|   Úcan_user_view_search_toolrà  7  s`   è ø€ ð
Ü&Ø-Ø#ô
÷ 	
ð 	
ô (Ø-Ø#ô
÷ 	
ð 	
ð ð	
øð	
ùô ò Ùðüs8   ‚A„3 ”/•3 ©1ª3 ®A¯3 ±3 ³	?¼A¾?¿AÚ
user_modelc              ƒ   óL   K  — t        | dddœgdœ||d¬«      ƒ d{  –—†  y7 Œ­w)	z€
    Try to route the fallback model request.

    Validate if it can't be routed.

    Help catch invalid fallback models.
    r‘  zWho was Alexander?)rT  Úcontent)r*  ÚmessagesÚacompletion)r°   r$  rá  Ú
route_typeNTrW   )r*  r$  rá  s      r|   Úis_valid_fallback_modelrç  N  sC   è ø€ ô àØ"(Ð5IÑJÐKñ
ð ØØ ô÷ ð ð ðús   ‚$œ"�$c                 óB   — t        «       }|�t        | «      sy|| _        y)a÷  
    Throttle an over-budget key instead of blocking it, when the key opted in
    via `throttle_on_budget_exceeded` and a global percentage is configured.

    Records the percentage on the request-scoped `budget_throttle_pct` so the
    rate limiter scales the key's TPM/RPM down to it; the persistent limits are
    left untouched so the throttle never compounds across requests. Returns True
    when the key was throttled (caller skips raising), False when it should still
    be hard-blocked.
    FT)r>   r?   r8  )r}  Úpcts     r|   Ú_apply_budget_exceeded_throttlerê  g  s'   € ô ,Ó-€CØ
€{Ô9¸+ÔFØØ&)€KÔ#Ør   c              ƒ   óx  K  — | j                   ��¦ddlm} | j                  xs d}d| j                  › �} |||| j                   ¬«      ƒ d{  –—† }d}|�|j
                  }t        | j                  || j                   | j                  | j                  | j                  | j                  || j                  t        j                  ¬«
      }t        j                  |j!                  d|¬	«      «       t#        j$                  | j                   «      r¥|| j                   k\  r•t'        | «      ry| j                  xs d
}	| j(                  r|	› d| j(                  › d�n|	}
t+        j,                  || j                   d|
› d|› d| j                   › �t        j                  j.                  | j                  ¬«      ‚yyy7 �Œj­w)zš
    Raises:
        BudgetExceededError if the token is over it's max budget.
        Triggers a budget alert if the token is over it's max budget.

    Nr   r   r  ú
spend:key:r  )
r‡   rç   rá   Úsoft_budgetrš   r
  r  rî  r÷  Úevent_groupÚtoken_budget©r  rë  rù   z (ú)zBudget has been exceeded! Key=ú Current cost: ú, Max budget: r  )rá   r  r  rç   r‡   rî  r&   rí  rš   r
  rK  r÷  r*   ÚKEYr<  rM  Úbudget_alertsr­  r®  rê  rö  rJ  r¯  r�   )r}  r~  r#  r  r  r  rç   rî  Ú	call_infoÚ	key_labelÚkey_descriptors              r|   Ú_virtual_key_max_budget_checkrù  y  sÑ  è ø€ ð ×ÑÑ)Ý@à +× 1Ñ 1Ò 8°SˆØ)¨+×*;Ñ*;Ð)<Ð=ˆñ /Ø#Ø)Ø"×-Ñ-ô
÷ 
ˆð ˆ
àÐØ!×,Ñ,ˆJä#Ø×#Ñ#ØØ"×-Ñ-Ø#×/Ñ/Ø×'Ñ'Ø×'Ñ'Ø'×.Ñ.Ø!Ø!×+Ñ+Ü*×.Ñ.ô
ˆ	ô 	×ÑØ×+Ñ+Ø#Ø#ð ,ó ô	
ô �=‰=˜×/Ñ/Ô0°U¸k×>TÑ>TÒ5TÜ.¨{Ô;Øð  +×4Ñ4Ò=¸ˆIØOZ×OcÒOc y k°°K×4HÑ4HÐ3IÈÑ$KÐirˆNÜ×-Ñ-Ø"Ø&×1Ñ1Ø8¸Ð8HÈÐX]ÐW^Ð^lÐmx÷  nDñ  nDð  mEð  FÜ.×2Ñ2×8Ñ8Ø%×+Ñ+ôð ð 6UÐ0ða *ð
ûs   ‚AF:ÁF7ÁE*F:c              ƒ   ó  K  — | j                   syddlm} | j                   D ]ã  }t        |t        «      r|n|j                  «       }d| j                  › d|d   › �} ||d|d   d	| j                  t        |d   «      t        |«      ¬
«      ƒ d{  –—† }t        j                  |d   «      sŒŒ||d   k\  sŒ•t        j                  ||d   d|d   › d|d›d|d   d›�t        j                  j                  | j                  ¬«      ‚ y7 Œx­w)aK  
    Raises BudgetExceededError if any budget window in valid_token.budget_limits is exceeded.

    Each window has its own Redis counter keyed by spend:key:{token}:window:{budget_duration}.
    Using budget_duration (not list index) keeps counters stable when windows are reordered
    or removed during a key update.

    Note: counters are not seeded from DB on Redis cold-start. After a Redis flush,
    per-window spend resets to zero within the current window period. This is an acceptable
    trade-off: the DB stores reset_at timestamps but not per-window accumulated spend.
    Nr   r   rì  ú:window:r_  r  rá   ÚKey©r  r  rá   Úwindow_entity_typeÚwindow_entity_idÚwindow_durationÚwindow_startzExceededBudget: Key over ú budget. Spend=$ú.4fú	, Limit=$ú.2fr  )Úbudget_limitsr  r  r(  r}   rŒ   r‡   rƒ   rY   r­  r®  rJ  r¯  r*   rô  r�   )r}  r  ÚwindowÚwr  Úwindow_spends         r|   r5  r5  Ä  s+  è ø€ ð ×$Ò$Øå<à×+Ñ+ò ˆÜ& v¬tÔ4‘&¸&×:KÑ:KÓ:MˆØ" ;×#4Ñ#4Ð"5°X¸aÐ@QÑ>RÐ=SÐTˆÙ.Ø#ØØ˜‘Ø$Ø(×.Ñ.Ü Ð"3Ñ 4Ó5Ü0°Ó3ô
÷ 
ˆô �=‰=˜˜<™Õ)¨l¸aÀ¹oÓ.MÜ×-Ñ-Ø)Ø˜\™?à/°Ð2CÑ0DÐ/Eð FØ*¨3Ð/¨y¸¸<¹ÈÐ8MðOô /×2Ñ2×8Ñ8Ø%×+Ñ+ô	ð 	ñð
ús   ‚BDÂD	ÂDÂ.DÂ7ADc              ƒ   ó,  K  — | j                   �r| j                  | j                   k\  rét        j                  d| j                  | j                  | j                   «       t        | j                  | j                  | j                  | j                   | j                  | j                  | j                  | j                  |r|j                  nd| j                  t        j                  ¬«      }t        j                   |j#                  d|¬«      «       yyy­w)zI
    Triggers a budget alert if the token is over it's soft budget.

    z:Crossed Soft Budget for token %s, spend %s, soft_budget %sN©r‡   rç   rá   rí  rš   r
  rw  r  rî  r÷  rî  rí  rð  )rí  rç   r   r2  r‡   r&   rá   rš   r
  rw  rK  rî  r÷  r*   rô  r<  rM  rõ  )r}  r~  r#  rö  s       r|   Ú_virtual_key_soft_budget_checkr  ð  sõ   è ø€ ð ×Ó ;×#4Ñ#4¸×8OÑ8OÒ#OÜ×"Ñ"ØHØ×ÑØ×ÑØ×#Ñ#ô		
ô $Ø×#Ñ#Ø×#Ñ#Ø"×-Ñ-Ø#×/Ñ/Ø×'Ñ'Ø×'Ñ'Ø"×-Ñ-Ø'×.Ñ.Ù.6�x×*Ò*¸DØ!×+Ñ+Ü*×.Ñ.ô
ˆ	ô 	×ÑØ×+Ñ+Ø"Ø#ð ,ó õ	
ð+ $PÐùs   ‚DDrÐ  c                 óV  — t        | t        «      r@| D �cg c]4  }t        |t        «      sŒ|j                  «       sŒ%|j                  «       ‘Œ6 c}S t        | t        «      r>| j	                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% c}S g S c c}w c c}w )z3Parse emails from a list or comma-separated string.ú,)r(  rÑ  rƒ   ÚstripÚsplit)rÐ  r@  s     r|   Ú_parse_email_listr    ss   € ä�#”tÔØ#&ÖK˜a¬*°Q¼Õ*<ÀÇÁÅ�—‘•	ÒKÐKÜ	�CœÔ	Ø#&§9¡9¨S£>Ö?˜a°Q·W±WµY�—‘•	Ò?Ð?Ø€Iùò Lùâ?s   •B!«B!¼B!Á4B&Â
B&Úcfgc                 óp   — | si S | j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}S c c}}w )uÝ   Coerce user-supplied thresholdâ†’recipients mapping to Dict[str, List[str]].

    Values may legitimately arrive as list, comma-separated string, or None
    from YAML/metadata; _parse_email_list tolerates all three.
    )rZ  r  )r  ÚkÚvs      r|   Ú_normalize_alert_emailsr     s5   € ñ Øˆ	Ø03·	±	³×<©¨¨1ˆAÔ  Ó#Ñ#Ó<Ð<ùÓ<s   ˜2Ú
global_cfgÚper_key_cfgc                 ó  — t        | «      }t        |«      }|s|syt        |«      t        |«      z  }|D �ci c]D  }|t        t        j	                  |j                  |g «      |j                  |g «      z   «      «      “ŒF c}S c c}w )z×
    Per-threshold additive merge: each threshold's recipient list is the union
    of global + per-key entries (deduped, global-first ordering). Missing
    thresholds on one side are inherited from the other.
    N)r  rx  rÑ  r}   rp  r0  )r  r  Úglobal_cfg_normalizedÚper_key_cfg_normalizedÚ
thresholdsrÛ  s         r|   Ú!_merge_budget_alert_email_configsr  -  sŒ   € ô $;¸:Ó#FÐÜ$;¸KÓ$HÐÙ Ñ)?ØÜÐ1Ó2´SÐ9OÓ5PÑP€JànxöØijˆŒ4”—‘Ð3×7Ñ7¸¸2Ó>ÐAW×A[ÑA[Ð\]Ð_aÓAbÑbÓcÓdÑdòð ùò s   ·A	Bc              ƒ   ó  K  — | j                   ��n| j                  ��`| j                  dkD  �rO|r|j                  nd}t        t        j
                  | j                  xs i j                  d«      ¬«      }t        |t        «      rÞ|rÜt        d„ |D «       d¬«      }|�| j                  | j                   |dz  z  k  ryt        | j                  | j                  | j                   | j                  | j                  | j                  | j                   | j"                  || j$                  t&        j(                  |¬«      }t+        j,                  |j/                  d	|¬
«      «       y| j                   t0        z  }| j                  |k\  rö| j                  | j                   k  rÜt3        j4                  d| j                  | j                  | j                   |«       t        | j                  | j                  | j                   | j                  | j                  | j                  | j                   | j"                  || j$                  t&        j(                  ¬«      }t+        j,                  |j/                  d	|¬
«      «       yyyyyy­w)zÜ
    Triggers a budget alert if the token has reached EMAIL_BUDGET_ALERT_MAX_SPEND_ALERT_PERCENTAGE
    (default 80%) of its max budget.
    This is a warning alert before the token actually exceeds the max budget.

    Nr   Úmax_budget_alert_emails)r  r  c              3   óT   K  — | ]   }|j                  «       sŒt        |«      –— Œ" y ­wrx   )Úisdigitr¶   )r  r  s     r|   r  z6_virtual_key_max_budget_alert_check.<locals>.<genexpr>V  s   è ø€ ÒC˜A°q·y±yµ{”�Q—ÑCùs   ‚(˜()Údefaultg      Y@)r‡   rç   rá   rí  rš   r
  rw  r  rî  r÷  rî  r  Úmax_budget_alertrð  z\Reached Max Budget Alert Threshold for token %s, spend %s, max_budget %s, alert_threshold %sr  )rá   rç   rî  r  rJ  Ú#default_key_max_budget_alert_emailsrž  r0  r(  r}   Úminr&   r‡   rí  rš   r
  rw  rK  r÷  r*   rô  r<  rM  rõ  r   r   r2  )r}  r~  r#  Úowner_emailÚalert_email_configÚmin_pctrö  Úalert_thresholds           r|   Ú#_virtual_key_max_budget_alert_checkr*  @  sZ  è ø€ ð ×ÑÑ)¨k×.?Ñ.?Ñ.KÐP[×PaÑPaÐdeÓPeÙ4<˜X×0Ò0À$ˆÜAbÜ×BÑBØ$×-Ñ-Ò3°×8Ñ8Ð9RÓSôB
Ðô
 Ð(¬$Ô/Ñ4Fä ÙCÐ!3ÔCØôˆGð ˆ +×"3Ñ"3°k×6LÑ6LÐPWÐZ_ÑP_Ñ6`Ò"`Øä Ø!×'Ñ'Ø!×'Ñ'Ø&×1Ñ1Ø'×3Ñ3Ø#×+Ñ+Ø#×+Ñ+Ø&×1Ñ1Ø +× 2Ñ 2Ø&Ø%×/Ñ/Ü.×2Ñ2Ø(:ôˆIô ×ÑØ!×/Ñ/Ø+Ø'ð 0ó õð &1×%;Ñ%;Ô>kÑ%kˆOà× Ñ  OÒ3¸×8IÑ8IÈK×LbÑLbÒ8bÜ$×*Ñ*ØrØ×%Ñ%Ø×%Ñ%Ø×*Ñ*Ø#ôô %Ø%×+Ñ+Ø%×+Ñ+Ø*×5Ñ5Ø +× 7Ñ 7Ø'×/Ñ/Ø'×/Ñ/Ø*×5Ñ5Ø$/×$6Ñ$6Ø*Ø)×3Ñ3Ü 2× 6Ñ 6ô�	ô ×#Ñ#Ø%×3Ñ3Ø/Ø"+ð 4ó õð- 9cÐ3ðQ QfÐ.KÐ)ùs   ‚I=I?c              ƒ   ó²  K  — | ��È| j                   ��º|��¶|j                  ��¨t        |j                  | j                   |||¬«      ƒ d{  –—† }d}|�9|j                  �-|j                  j                  �|j                  j                  }nn| j
                  xs i j                  d«      }t        |t        «      r?t        |||¬«      ƒ d{  –—† }	|	�'|	j                  �|	j                  dkD  r|	j                  }|�Î|�|j                  ndxs d}
ddlm}  |d|j                  › d	| j                   › �|
|¬
«      ƒ d{  –—† }
t        j                  |«      rq|
|k\  rkt        j                   |
|d|j                  › d| j                   › d|
› d|› �t"        j$                  j&                  |j                  › d	| j                   › �¬«      ‚yyyyyyy7 �Œ…7 �Œ7 Œ–­w)z>Check if team member is over their max budget within the team.Nr“  Úteam_member_budget_id)r„  rí  rî  r   r  r   r€  r�  r  zBudget has been exceeded! User=z	 in Team=rò  ró  r  )r
  rš   r%  ré   rá   rž  r0  r(  rƒ   r”  rç   r  r  r­  r®  rJ  r¯  r*   ÚTEAM_MEMBERr�   )r·  ré  r}  rí  rî  r~  r”  Úteam_member_budgetÚdefault_budget_idr–  Úteam_member_spendr  s               r|   r:  r:  ’  s5  è ø€ ð 	ÑØ×ÑÑ+ØÑ#Ø×ÑÑ+ä':Ø×'Ñ'Ø×'Ñ'Ø'Ø1Ø/ô(
÷ "
ˆð ,0ÐàÐ'Ø×4Ñ4Ð@Ø×4Ñ4×?Ñ?ÐKà!0×!EÑ!E×!PÑ!PÑà(3×(<Ñ(<Ò(BÀ×'GÑ'GÐH_Ó'`ÐÜÐ+¬SÔ1Ü.LØ/Ø"/Ø'9ô/÷ )�ð #Ð.Ø&×1Ñ1Ð=Ø&×1Ñ1°AÒ5à)7×)BÑ)BÐ&àÐ)Ø:IÐ:U ×!6Ò!6Ð[^Ò fÐcfÐõ Eá&7Ø0°×1DÑ1DÐ0EÀQÀ{×GZÑGZÐF[Ð\Ø0Ø-ô'÷ !Ðô �}‰}Ð/Ô0Ð5FÐJ\Ò5\Ü×1Ñ1Ø!2Ø1Ø=¸k×>QÑ>QÐ=RÐR[Ð\g×\oÑ\oÐ[pÐpð  ARð  @Sð  Sað  btð  auð  vÜ 2× >Ñ >× DÑ DØ!,×!4Ñ!4Ð 5°Q°{×7JÑ7JÐ6KÐLôð ð 6]Ð0ð *ðI ,ð $ð ,ð 	 ð
"
ùð()ùð(!ús9   ‚AGÁ
GÁBGÃGÃA1GÄ>GÄ?BGÇGÇGrZ   c              ƒ   óö  K  — |j                   �|j                  €yt        |j                   |j                  |||¬«      ƒ d{  –—† }|�"|j                  �|j                  j                  sy|j                  j                  }	 t        | ||d|j                  ¬«       y7 Œ[# t        $ rL t        d|j                   › d|j                  › d| › d|› �t        j                  d	t        j                  ¬
«      ‚w xY w­w)a  
    Check if a team member's per-member model scope allows access to the requested model.

    Only enforced when the member's budget table has a non-empty allowed_models list.
    If allowed_models is empty or absent, the team-level models list applies (no extra restriction).
    Nr“  r  )r*  r$  rq  r  r
  z.Team member not allowed to access model. User=z, Team=z, Model=z. Allowed member models = r*  r   )rš   r
  r%  ré   rï   rƒ  r:   r9   r(  r   rÓ  )	r*  r·  r}  r$  rí  rî  r~  r”  Úmember_allowed_modelss	            r|   r*  r*  Ù  s&  è ø€ ð ×ÑÐ" k×&9Ñ&9Ð&AØä#6Ø×#Ñ#Ø×#Ñ#Ø#Ø-Ø+ô$÷ €Oð 	ÐØ×/Ñ/Ð7Ø×3Ñ3×BÒBàà.=×.RÑ.R×.aÑ.aÐð
ÜØØ!Ø(ØØ×'Ñ'ö	
ð#ùô0 ò 
ÜØDÀ[×EXÑEXÐDYÐY`Ðal×atÑatÐ`uÐu}ð  Dð  ~Eð  E_ð  `uð  _vð  wÜ ×9Ñ9ØÜ×*Ñ*ô	
ð 	
ð
üs+   ‚AC9ÁBÁ?C9ÂB! ÂC9Â!AC6Ã6C9c           
   ƒ   óà  K  — | ��d| j                   ��Vddlm}  |d| j                  › �| j                  xs d| j                   ¬«      ƒ d{  –—† }t        j                  | j                   «      rø|| j                   kD  rè|rƒt        |j                  || j                   |j                  |j                  |j                  |j                  t        j                  ¬«      }t        j                  |j!                  d|¬	«      «       t#        j$                  || j                   d
| j                  › d|› d| j                   › �t        j                  j&                  | j                  ¬«      ‚yyyy7 �Œ­w)zÇ
    Check if the team is over it's max budget.

    Raises:
        BudgetExceededError if the team is over it's max budget.
        Triggers a budget alert if the team is over it's max budget.
    Nr   r   úspend:team:r  r  ©r‡   rç   rá   rš   r
  rw  r  rî  Úteam_budgetrð  zBudget has been exceeded! Team=rò  ró  r  )rá   r  r  r
  rç   r­  r®  r&   r‡   rš   rw  rK  r*   rn  r<  rM  rõ  rJ  r¯  r�   )r·  r}  r~  r  rç   rö  s         r|   r3  r3    su  è ø€ ð Ñ ;×#9Ñ#9Ñ#EÝ@ñ /Ø% k×&9Ñ&9Ð%:Ð;Ø&×,Ñ,Ò3°Ø"×-Ñ-ô
÷ 
ˆô �=‰=˜×/Ñ/Ô0°U¸[×=SÑ=SÒ5SÙÜ#+Ø%×+Ñ+ØØ*×5Ñ5Ø'×/Ñ/Ø'×/Ñ/Ø*×5Ñ5Ø$/×$6Ñ$6Ü 2× 7Ñ 7ô	$�	ô ×#Ñ#Ø%×3Ñ3Ø*Ø"+ð 4ó ôô ×-Ñ-Ø"Ø&×1Ñ1Ø9¸+×:MÑ:MÐ9NÈoÐ^cÐ]dÐdrÐs~÷  tJñ  tJð  sKð  LÜ.×3Ñ3×9Ñ9Ø%×-Ñ-ôð ð' 6TÐ0ð $FÐð
ûs   ‚A
E.ÁE+ÁDE.c              ƒ   ó8  K  — | �| j                   syddlm} | j                   D ]ð  }t        |t        «      r|n|j                  «       }d| j                  › d|d   › �} ||d|d   d	| j                  t        |d   «      t        |«      ¬
«      ƒ d{  –—† }t        j                  |d   «      sŒŒ||d   k\  sŒ•t        j                  ||d   d| j                  › d|d   › d|d›d|d   d›�t        j                  j                  | j                  ¬«      ‚ y7 Œ…­w)aG  
    Raises BudgetExceededError if any budget window in team_object.budget_limits is exceeded.

    Each window has its own Redis counter keyed by spend:team:{team_id}:window:{budget_duration}.
    Using budget_duration (not list index) keeps counters stable when windows are reordered
    or removed during a team update.
    Nr   r   r4  rû  r_  r  rá   ÚTeamrý  zExceededBudget: Team=z over r  r  r  r  r  )r  r  r  r(  r}   rŒ   r
  rƒ   rY   r­  r®  rJ  r¯  r*   rn  r�   )r·  r  r  r  r  r	  s         r|   r4  r4  >  s=  è ø€ ð Ð +×";Ò";Øå<à×+Ñ+ò ˆÜ& v¬tÔ4‘&¸&×:KÑ:KÓ:MˆØ# K×$7Ñ$7Ð#8¸ÀÐCTÑAUÐ@VÐWˆÙ.Ø#ØØ˜‘Ø%Ø(×0Ñ0Ü Ð"3Ñ 4Ó5Ü0°Ó3ô
÷ 
ˆô �=‰=˜˜<™Õ)¨l¸aÀ¹oÓ.MÜ×-Ñ-Ø)Ø˜\™?à+¨K×,?Ñ,?Ð+@ÀÀqÐIZÑG[ÐF\ð ]Ø*¨3Ð/¨y¸¸<¹ÈÐ8MðOô /×3Ñ3×9Ñ9Ø%×-Ñ-ô	ð 	ñð
ús   ‚BDÂDÂDÂ0DÂ9A Dc              ƒ   ó–  K  — | ��3| j                   ��%| j                  ��| j                  | j                   k\  �rüt        j                  d| j                  | j                  | j                   «       |�rÂd}| j
                  �Ýt        | j
                  t        «      rÃ| j
                  j                  d«      }|�¦t        |t        «      r2|D �cg c]&  }t        |t        «      sŒ|j                  «       sŒ%|‘Œ( }}nMt        |t        «      r=|j                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% }}|r|D �cg c]  }|sŒ|‘Œ	 }}nd}|�t        |«      dk(  r!t        j                  d| j                  «       yt        |j                  | j                  | j                   | j                   |j"                  |j                  |j$                  |j&                  d|j(                  t*        j,                  |¬«      }t/        j0                  |j3                  d|¬	«      «       yyyyyyc c}w c c}w c c}w ­w)
zG
    Triggers a budget alert if the team is over it's soft budget.
    Nz9Crossed Soft Budget for team %s, spend %s, soft_budget %sÚsoft_budget_alerting_emailsr  r   zoSkipping team soft budget alert for team %s: no alert_emails configured in metadata.soft_budget_alerting_emails)r‡   rç   rá   rí  rš   r
  rw  r  rî  r÷  rî  Úalert_emailsrí  rð  )rí  rç   r   r2  r
  rž  r(  r}   r0  rÑ  rƒ   r  r  rv  r&   r‡   rá   rš   rw  rK  r÷  r*   rn  r<  rM  rõ  )r·  r}  r~  r;  Úsoft_budget_alert_emailsÚemailrö  s          r|   r6  r6  f  s5  è ø€ ð 	ÑØ×#Ñ#Ñ/Ø×ÑÑ)Ø×Ñ ×!8Ñ!8Ó8ä×"Ñ"ØGØ×ÑØ×ÑØ×#Ñ#ô		
ò à-1ˆLØ×#Ñ#Ð/´J¸{×?SÑ?SÔUYÔ4ZØ2=×2FÑ2F×2JÑ2JÐKhÓ2iÐ(Ø+Ð7Ü!Ð":¼DÔAà/Gö(Ø&+Ì:ÐV[Ô]`ÕKaÐfk×fqÑfqÕfsšEð(˜ñ (ô $Ð$<¼cÔBàC[×CaÑCaÐbeÓCfÖ'x¸%Ðjo×juÑjuÕjw¨¯©­Ð'x˜Ð'xá#Ø;GÖ'Q°%Ê5ªÐ'Q˜Ñ'Qà'+˜ð Ð#¤s¨<Ó'8¸AÒ'=Ü$×*Ñ*ð FØ×'Ñ'ôð ä'Ø!×'Ñ'Ø!×'Ñ'Ø&×1Ñ1Ø'×3Ñ3Ø#×+Ñ+Ø#×+Ñ+Ø&×1Ñ1Ø +× 2Ñ 2ØØ%×/Ñ/Ü.×3Ñ3Ø)ô ˆIô ×ÑØ!×/Ñ/Ø&Ø'ð 0ó õðW ð 9ð *ð 0ð 	 ùò$(ùò
 (yùò (RùsC   ‚C
I	ÃH:Ã"H:Ã3H:Ã7&I	ÄH?Ä3H?ÅI	ÅIÅIÅC0I	c           
   ƒ   ó˜  K  — | €yd}| j                   �| j                   j                  }|��| j                  ��t        j                  |«      rø| j                  |kD  rè|rƒt        |j                  | j                  ||j                  |j                  |j                  |j                  t        j                  ¬«      }t        j                  |j                  d|¬«      «       t!        j"                  | j                  |d| j$                  › d| j                  › d|› �t        j                  j&                  | j$                  ¬«      ‚yyyy­w)	zÍ
    Check if the project is over its max budget.

    Raises:
        BudgetExceededError if the project is over its max budget.
        Triggers a budget alert if the project is over its max budget.
    Nr5  Úproject_budgetrð  z"Budget has been exceeded! Project=rò  ró  r  )ré   rá   rç   r­  r®  r&   r‡   rš   r
  rw  rK  r*   ÚPROJECTr<  rM  rõ  rJ  r¯  r‚  r�   )rz  r}  r~  rá   rö  s        r|   r„  r„  ­  s^  è ø€ ð ÐØà€JØ×*Ñ*Ð6Ø#×8Ñ8×CÑCˆ
ð 	ÑØ× Ñ Ñ,Ü�M‰M˜*Ô%Ø× Ñ  :Ò-áÜ'Ø!×'Ñ'Ø$×*Ñ*Ø%Ø#×+Ñ+Ø#×+Ñ+Ø&×1Ñ1Ø +× 2Ñ 2Ü.×6Ñ6ô	 ˆIô ×ÑØ!×/Ñ/Ø)Ø'ð 0ó ôô ×)Ñ)Ø'×-Ñ-Ø!Ø8¸×9RÑ9RÐ8SÐSbÐcq×cwÑcwÐbxð  yGð  HRð  GSð  TÜ*×2Ñ2×8Ñ8Ø$×/Ñ/ô
ð 	
ð) .ð &ð -ð 	ùs   ‚EE
c              ƒ   ó   K  — | €yd}| j                   �| j                   j                  }|�Ñ| j                  �Ä| j                  |k\  r´t        j                  d| j
                  | j                  |«       |r…t        |j                  | j                  d||j                  |j                  |j                  |j                  t        j                  ¬«	      }t        j                  |j!                  d|¬«      «       yyyyy­w)zy
    Triggers a budget alert if the project is over its soft budget.

    Mirrors _team_soft_budget_check() pattern.
    Nz<Crossed Soft Budget for project %s, spend %s, soft_budget %s)	r‡   rç   rá   rí  rš   r
  rw  r  rî  rí  rð  )ré   rí  rç   r   r2  r‚  r&   r‡   rš   r
  rw  rK  r*   r@  r<  rM  rõ  )rz  r}  r~  rí  rö  s        r|   r…  r…  á  s  è ø€ ð ÐØà€KØ×*Ñ*Ð6Ø$×9Ñ9×EÑEˆàÐ >×#7Ñ#7Ð#CÈ×H\ÑH\Ð`kÒHkÜ×"Ñ"ØJØ×%Ñ%Ø× Ñ Øô		
ñ Ü'Ø!×'Ñ'Ø$×*Ñ*ØØ'Ø#×+Ñ+Ø#×+Ñ+Ø&×1Ñ1Ø +× 2Ñ 2Ü.×6Ñ6ô
 ˆIô ×ÑØ!×/Ñ/Ø&Ø'ð 0ó õð ð IlÐ#CÐùs   ‚C<C>r‚  c                 ó   — d| › �S )Nzproject_id:ry   )r‚  s    r|   Ú_project_cache_keyrC    s   € Ø˜˜Ð%Ð%r   c              ƒ   ó”  K  — |€yt        | «      }|j                  |t        ¬«      ƒ d{  –—† }|�|S t        t	        |«      «      j                  d| iddi¬«      ƒ d{  –—† }|€yt        j                  |j                  «       «      }t        j                  «       |_	        t        ||||t        ¬«      ƒ d{  –—†  |S 7 Œ–7 Œc7 Œ
­w)zÀ
    Fetch project object from cache or DB.

    Follows get_team_object() caching pattern with TTL and last_refreshed_at.

    Returns LiteLLM_ProjectTableCachedObj or None if not found.
    Nr‚  r‚  ré   TrØ  rm  )rC  rû   r0   rÅ   ra   r¨   rŠ  rŒ   r4  rs  rn  )r‚  rí  rî  r~  rŒ  Údeserialized_projectÚproject_rowÚproject_objs           r|   rµ  rµ    só   è ø€ ð ÐØô *¨*Ó5€IØ(:×(JÑ(JØÜ0ð )Kó )÷ #Ðð Ð'Ø#Ð#ô  1Ô1BÀ=Ó1QÓR×^Ñ^Ø˜ZÐ(Ø'¨Ð.ð  _ó  ÷ €Kð ÐØä6×EÑEÀk×F\ÑF\ÓF^Ó_€Kô %)§I¡I£K€KÔ!Ü
"ØØØ-Ø+Ü0ô÷ ð ð Ðð7#øðøðús4   ‚)C«C¬4CÁ CÁ!ACÂ;CÂ<CÃCÃCc              ƒ   óT   K  — ddl m}  |t        | «      f|¬«      ƒ d{  –—†  y7 Œ­w)zÂ
    Every endpoint that mutates litellm_projecttable must call this, or a stale project (e.g. a
    pre-update empty model allowlist) keeps being enforced until the TTL expires (LIT-3803).
    r   )r}  r„  N)r†  r}  rC  )r‚  rî  r}  s      r|   Údelete_cached_project_objectrI  A  s,   è ø€ õ ^á
Ü& zÓ2Ð4Ø-ô÷ ò ús   ‚( &¡(c           
   ƒ   ó  K  — | �|€yd}| j                   �| j                   }n|�|j                  �|j                  }|€y	 t        ||||d¬«      ƒ d{  –—† }|€yd}|j                  �|j                  j
                  }|�|dk  ryddlm}  |d|› �|j                  xs d|¬«      ƒ d{  –—† }	t        j                  |«      r°|	|k\  rªt        | j                  |	|| j                  | j                  | j                  |t         j"                  ¬	«      }
t%        j&                  |j)                  d
|
¬«      «       t+        j,                  |	|d|› d|	› d|› �t         j"                  j.                  |¬«      ‚yy7 �Œ$# t        $ r Y yw xY w7 ŒÜ­w)a`  
    Check if the organization is over its max budget.

    This function checks the organization budget using:
    1. First, tries to use valid_token.org_id (if key has organization_id set)
    2. Falls back to team_object.organization_id (if key doesn't have org_id but team does)

    This ensures organization budget checks work even when keys don't have organization_id
    set directly, as long as their team belongs to an organization.

    Raises:
        BudgetExceededError if the organization is over its max budget.
        Triggers a budget alert if the organization is over its max budget.
    NT)rK  rí  rî  r~  rL  r   r   z
spend:org:r  r  r5  Úorganization_budgetrð  z'Budget has been exceeded! Organization=rò  ró  r  )rK  r  rQ  r  ré   rá   r  r  rç   r­  r®  r&   r‡   rš   r
  rw  r*   ÚORGANIZATIONr<  rM  rõ  rJ  r¯  r�   )r}  r·  rí  rî  r~  rK  Ú	org_tableÚorg_max_budgetr  Ú	org_spendrö  s              r|   r7  r7  Q  sÙ  è ø€ ð* Ð˜mÐ3Øð €FØ×ÑÐ%Ø×#Ñ#‰Ø	Ð	  [×%@Ñ%@Ð%LØ×,Ñ,ˆð €~Øð
Ü!/ØØ'Ø1Ø/Ø!%ô"
÷ 
ˆ	ð ÐØð $(€NØ×%Ñ%Ð1Ø"×7Ñ7×BÑBˆð Ð °1Ò!4Øõ =á.Ø   Ð)Ø —‘Ò-¨#Ø!ô÷ €Iô ‡}�}�^Ô$¨°nÒ)Dä#Ø×#Ñ#ØØ%Ø×'Ñ'Ø×'Ñ'Ø"×-Ñ-Ø"Ü*×7Ñ7ô	
ˆ	ô 	×ÑØ×+Ñ+Ø*Ø#ð ,ó ô	
ô ×)Ñ)Ø"Ø%Ø=¸f¸XÀ_ÐU^ÐT_Ð_mÐn|Ðm}Ð~Ü*×7Ñ7×=Ñ=Øô
ð 	
ð' *EÐ$ðC
úô ò áðúð&úsI   ‚>FÁE; ÁE8ÁE; ÁAFÂ-F
Â.C
FÅ8E; Å;	FÆFÆFÆFc              ƒ   ó`  K  — ddl m} |€y || ¬«      }|syt        ||||¬«      ƒ d{  –—† }|D ]õ  }|j                  |«      }	|	€Œ|	j                  €Œ$|	j                  j
                  €Œ;ddlm}
  |
d|› �|	j                  xs d|	j                  j
                  d	¬
«      ƒ d{  –—† }||	j                  j
                  k  rŒ”t        j                  ||	j                  j
                  d|› d|› d|	j                  j
                  › �t        j                  j                  |¬«      ‚ y7 Œÿ7 Œ…­w)zÔ
    Check if any tags in the request are over their max budget.

    Raises:
        BudgetExceededError if any tag is over its max budget.
        Triggers a budget alert if any tag is over its max budget.
    r   )Úget_tags_from_request_bodyNr  )r  rí  rî  r~  r   z
spend:tag:r  Tr™  zBudget has been exceeded! Tag=rò  ró  r  )Ú-litellm.proxy.common_utils.http_parsing_utilsrQ  r  r0  ré   rá   r  r  rç   rJ  r¯  r*   ÚTAGr�   )rÿ   rí  rî  r~  r}  rQ  rŸ  r  rÔ   Ú
tag_objectr  Ú	tag_spends               r|   r8  r8  ³  s`  è ø€ õ YàÐØñ -¸,ÔG€DÙØô  5ØØ#Ø-Ø+ô	 ÷ €Kð ò ˆØ —_‘_ XÓ.ˆ
ØÐØð ×*Ñ*Ñ6¸:×;ZÑ;Z×;eÑ;eÑ;qÝDá/Ø(¨¨
Ð3Ø)×/Ñ/Ò6°3Ø%×:Ñ:×EÑEØ'+ô	÷ ˆIð ˜J×;Ñ;×FÑFÒFØÜ×-Ñ-Ø&Ø%×:Ñ:×EÑEØ8¸¸
À/ÐR[ÐQ\Ð\jÐku÷  lKñ  lK÷  lVñ  lVð  kWð  XÜ.×2Ñ2×8Ñ8Ø"ôð ñ#ðøð"ús.   ‚(D.ªD*«)D.ÁD.Á,:D.Â&D,Â'BD.Ä,D.r  c              ƒ   óà  K  — |�| syt        | ||¬«      ƒ d{  –—† }ddlm} | D ]À  }|j                  |«      }|�|j                  �|j                  dk  rŒ2 |t        |«      |j                  |j                  d¬«      ƒ d{  –—† }||j                  k  rŒst        j                  ||j                  d|› d|› d	|j                  › �t        j                  j                  |¬
«      ‚ y7 ŒÐ7 Œg­w)a™  Block the request when a model access group that authorized it is over its max budget.

    Only the groups auth already matched are charged and therefore only they are checked, so a
    request that no budgeted group authorized costs nothing here.

    Like the tag check this is a plain read with no reservation, so concurrent requests can
    overshoot the ceiling slightly. The reservation counters are the precise path; this one covers
    the ``disable_budget_reservation`` case.

    The ceiling is exclusive, unlike the tag check it otherwise mirrors: a pool whose recorded
    spend has reached ``max_budget`` has nothing left to give, so the next request is refused.
    Keys and organizations already draw the line there. A non-positive budget means no budget,
    matching what the reservation path treats as unbudgeted.

    Raises:
        BudgetExceededError if a matched group is over its max budget.
    N)r  rí  rî  r   r   Tr™  z-Budget has been exceeded! Model access group=rò  ró  r  )r  r  r  r0  rá   rN   rç   rJ  r¯  r*   ÚMODEL_ACCESS_GROUPr�   )r  rí  rî  Úbudgetsr  r
  r“  Úgroup_spends           r|   r9  r9  î  s  è ø€ ð, ÐÑ$?Øä?Ø6Ø#Ø-ô÷ €Gõ =à,ò 
ˆØ—‘˜UÓ#ˆØˆ>˜V×.Ñ.Ð6¸&×:KÑ:KÈqÒ:PØá-Ü<¸UÓCØ!Ÿ<™<Ø×(Ñ(Ø#'ô	
÷ 
ˆð ˜×*Ñ*Ò*ØÜ×)Ñ)Ø$Ø×(Ñ(ØCÀEÀ7È/ÐZeÐYfÐftÐu{÷  vGñ  vGð  uHð  IÜ*×=Ñ=×CÑCØô
ð 	
ñ
ðøð
ús#   ‚C.™C*šA*C.ÂC,ÂA&C.Ã,C.Úallowed_model_patternc                 óv   — d|v r5d|j                  dd«      › d�}t        t        j                  || «      «      S y)a~  
    Check if a model matches an allowed pattern.
    Handles exact matches and wildcard patterns.

    Args:
        model (str): The model to check (e.g., "bedrock/anthropic.claude-3-5-sonnet-20240620")
        allowed_model_pattern (str): The allowed pattern (e.g., "bedrock/*", "*", "openai/*")

    Returns:
        bool: True if model matches the pattern, False otherwise
    ry  ú^z.*ú$F)r5  rQ  Úrerb  )r*  rZ  r_  s      r|   Úis_model_allowed_by_patternr_  %  sC   € ð Ð#Ñ#ØÐ2×:Ñ:¸3ÀÓEÐFÀaÐHˆÜ”B—H‘H˜W eÓ,Ó-Ð-àr   rx  c                 óZ   ‡ — t        ˆ fd„|D «       «      ryt        ˆ fd„|D «       «      ryy)ae  
    Returns True if a model matches any wildcard pattern in a list.

    eg.
    - model=`bedrock/us.amazon.nova-micro-v1:0`, allowed_models=`bedrock/*` returns True
    - model=`bedrock/us.amazon.nova-micro-v1:0`, allowed_models=`bedrock/us.*` returns True
    - model=`bedrockzzzz/us.amazon.nova-micro-v1:0`, allowed_models=`bedrock/*` returns False
    c              3   óR   •K  — | ]  }t        |«      xr t        ‰|¬ «      –— Œ  y­w©©r*  rZ  N)Ú_is_wildcard_patternr_  ©r  rZ  r*  s     €r|   r  z>_model_matches_any_wildcard_pattern_in_list.<locals>.<genexpr>B  s8   øè ø€ ò ð "ô 	Ð2Ó3ò 	bÜ'¨eÐK`Ôaó	bñùr�  Tc              3   óR   •K  — | ]  }t        |«      xr t        ‰|¬ «      –— Œ  y­wrb  )rd  Ú3_model_custom_llm_provider_matches_wildcard_patternre  s     €r|   r  z>_model_matches_any_wildcard_pattern_in_list.<locals>.<genexpr>I  s9   øè ø€ ò ð
 "ô	 	Ð2Ó3ò 	
Ü?ØÐ/Dô
ó	
ñùr�  Fr_  rw  s   ` r|   r{  r{  8  s@   ø€ ô ó ð &8ôô ð
 ä
ó ð
 &8ôô ð àr   c                 ó|   — 	 t        | ¬«      \  }}}}|| k(  rd| v ryt        |› d|› �|¬«      S # t        $ r Y yw xY w)a!  
    Returns True for this scenario:
    - `model=gpt-4o`
    - `allowed_model_pattern=openai/*`

    or
    - `model=claude-3-5-sonnet-20240620`
    - `allowed_model_pattern=anthropic/*`

    A model that already carries a namespace get_llm_provider did not consume
    (e.g. `bedrockz/anthropic.claude-...`) is never granted here: its provider was
    inferred from a fragment of the full string, so rebuilding
    `{provider}/{model}` would produce `bedrock/bedrockz/...` and slip an
    unrecognized namespace through a `bedrock/*` key.
    )r*  Fú/rc  )r#   r  r_  )r*  rZ  Ústripped_modelÚcustom_llm_providerrg  s        r|   rg  rg  U  sb   € ð Ü4DÈ5Ô4QÑ1ˆÐ+¨Q°ð ˜Ò 3¨%¡<Øä&Ø$Ð% Q ~Ð&6Ð7Ø3ôð øô ò Ùðús   ‚/ ¯	;º;c                 ó
   — d| v S )zb
    Returns True if the pattern is a wildcard pattern.

    Checks if `*` is in the pattern.
    ry  ry   )rZ  s    r|   rd  rd  s  s   € ð Ð'Ð'Ð'r   c              ƒ   ó†  K  — ddl m} |€t        j                  d«       yt        j
                  €t        j                  d«       yt        j
                  j                  | | j                  dd«      ¬«      }|€t        j                  d	«       y|�T|j                  �Ht        t        |«      «      j                  d
|j                  i¬«      ƒ d{  –—† }|�t        d||¬«       |�T|j                  �Ht        t        |«      «      j                  d
|j                  i¬«      ƒ d{  –—† }|�t        d||¬«       y7 Œk7 Œ­w)z²
    Checks if the object (key, team, org) has access to the vector store.

    Raises ProxyException if the object (key, team, org) cannot access the specific vector store.
    r   rX  Nz;Prisma client not found, skipping vector store access checkTzCVector store registry not found, skipping vector store access checkrÎ  )Únon_default_paramsrÎ  zAVector store to run not found, skipping vector store access checkr¡  r…  rù   )r  Úvector_store_ids_to_runÚobject_permissionsr  )r  rí  r   r2  rJ  Úvector_store_registryÚget_vector_store_ids_to_runr0  r¡  rÑ   r^   r¨   Ú_can_object_call_vector_stores)rÿ   r·  r}  rí  ro  Úkey_object_permissionr´  s          r|   r@  r@  |  s^  è ø€ õ 9ð
 ÐÜ×"Ñ"Ð#`ÔaØä×$Ñ$Ð,Ü×"Ñ"Ð#hÔiØä%,×%BÑ%B×%^Ñ%^Ø'¨|×/?Ñ/?ÀÈÓ/Nð &_ó &Ðð Ð&Ü×"Ñ"Ð#fÔgØð Ð ;×#CÑ#CÐ#OÜ-EÜ& }Ó5ó.
ç
‰+Ø)¨;×+KÑ+KÐLð ó 
÷(
Ðð
 !Ð,Ü*Ø!Ø(?Ø#8õð Ð ;×#CÑ#CÐ#OÜ.FÜ& }Ó5ó/
ç
‰+Ø)¨;×+KÑ+KÐLð ó 
÷)
Ðð
 "Ð-Ü*Ø"Ø(?Ø#9õð
 ð3(
øð)
ús%   ‚CEÃD=ÃAEÄ'D?Ä(EÄ?E)rù   r  rä  ro  rp  c                 ó   — |€y|j                   €yt        |j                   «      dk(  ry|D ]P  }||j                   vsŒt        d|› d|j                   › �t        j                  | «      dt
        j                  ¬«      ‚ y)zg
    Raises ProxyException if the object (key, team, org) cannot access the specific vector store.
    Tr   z9User not allowed to access vector store. Tried to access z. Only allowed to access Úvector_storer   )rÏ   rv  r:   r9   Ú-get_vector_store_access_error_type_for_objectr   r2  )r  ro  rp  r@  s       r|   rs  rs  »  s®   € ð Ð!Øà×'Ñ'Ð/Øô Ð×+Ñ+Ó,°Ò1Øà2ò ˆØÐ"4×"BÑ"BÒBÜ ØSÐTcÐSdÐd}ð  Q÷  _ñ  _ð  ~`ð  aÜ$×RÑRÐS^Ó_Ø$Ü×1Ñ1ô	ð ðð r   )FNrx   )r  NNN)NNr  )NNr  )NNN)NNF)NNr‘  r   (m  r­  r<  r­  r^  r4  Úcollections.abcr   r   r   r   r   Útypesr   Útypingr	   r
   r   r   r   r   r   Úfastapir   r   r   Úpydanticr   Útyping_extensionsr   r   rJ  Úlitellm._loggingr   Úlitellm.caching.dual_cacher   Úlitellm.constantsr   r   r   r   r   r   r   r   r    r!   Ú%litellm.litellm_core_utils.dd_tracingr"   Ú1litellm.litellm_core_utils.get_llm_provider_logicr#   Ú*litellm.litellm_core_utils.safe_json_loadsr$   r#  r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   Ú"litellm.proxy.auth.budget_throttler>   r?   Úlitellm.proxy.auth.route_checksr@   r†  rA   rR  rB   rC   Ú)litellm.proxy.common_utils.timezone_utilsrD   Ú-litellm.proxy.common_utils.user_api_key_cacherE   rF   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   Ú"litellm.proxy.db.exception_handlerrT   Ú-litellm.proxy.guardrails.tool_name_extractionrU   rV   Úlitellm.proxy.route_llm_requestrX   Ú/litellm.proxy.spend_tracking.budget_reservationrY   Úlitellm.proxy.utilsrZ   r[   r\   Ú&litellm.repositories.budget_repositoryr]   Ú1litellm.repositories.object_permission_repositoryr^   Ú,litellm.repositories.organization_repositoryr_   Ú%litellm.repositories.prisma_protocolsr`   Ú'litellm.repositories.project_repositoryra   Ú'litellm.repositories.table_repositoriesrb   rc   rd   re   rf   rg   rh   Ú$litellm.repositories.team_repositoryri   Ú$litellm.repositories.user_repositoryrj   Úlitellm.routerrk   Ú-litellm.types.proxy.model_access_group_budgetrl   Úlitellm.utilsrm   Úauth_checks_organizationro   rp   Ú
auth_utilsrq   rr   Úopentelemetry.tracers   Ú_Spanru   r†   rŠ   rŽ   r’   r™   r£   r¸   r¿   rÂ   rÅ   rÇ   rÉ   rË   rÍ   rÑ   rÓ   rØ   rÚ   rÝ   rß   rä   rë   rí   rñ   rƒ   rö   rø   rþ   r}   r„   r  r  r	  r
  rˆ   r  r  rk  r�   Úmanagement_routesr  r  r#  rQ  r)  rÑ  rA  rB  r7  r6  rO  rR  r\  r`  rf  rh  rk  r—   rp  ry  r‡  r›  r¦  râ   r±  r¶  rÈ  rß  r¶  rä  rè  rM  rU  r?  rX  rh  rq  rv  r  r�  r”  r—  r;  r¢  r¥  r©  r«  r®  ÚLockr¯  r°  r±  r·  rº  r¶   r¾  rÂ  rÍ  rÔ  rÞ  rà  rá  ré  rç  r÷  rû  r  r   r  r  r  r  r%  r1  r6  r9  r@  rE  rG  rN  rX  rï  r  rn  rz  r�  r’  r™  r›  r¢  r¤  r¦  r»  r½  rÂ  rÅ  r  rÐ  rÒ  rÖ  rÝ  ræ  rè  rê  r)  r/  r5  r—  rÁ  rH  rJ  rQ  rb  rg  rj  rl  rs  r~  rƒ  rz  r‹  r‘  r•  r˜  r›  r¤  r0  r¯  r¸  r»  r'  rÆ  r)  rƒ  r/  rÑ  r×  rÛ  rÞ  rà  rç  rê  rù  r5  r  r  r  r  r*  r:  r*  r3  r4  r6  r„  r…  rC  rµ  rI  r7  r8  r9  r_  r{  rg  rd  r@  rs  ry   r   r|   ú<module>rž     sÑ&  ðòó Û Û 	Û ß LÕ LÝ "ß O× OÑ Oç 2Ñ 2Ý ß 1ã Ý 1Ý =÷÷ ÷ õ 9Ý NÝ F÷÷ ÷ ÷ ÷ ÷ õ ÷6õ 8Ý e÷õ L÷÷ ÷ ÷ ñ õ" H÷õ :Ý Sß JÑ JÝ CÝ XÝ OÝ 9Ý E÷÷ ñ õ @Ý ?Ý !Ý PÝ *÷÷ KáÝ1à�Dà€Dô0˜ô 0ô˜hô ô6˜(ô 6ô6�Xô 6ô<˜Hô <ô	<�Xô 	<ôw�x Ñ(ô wô,6˜ 'Ñ*ô 6ð
Ð,Ð-?Ñ@ð ÐEUÐVhÑEió ðØ
Ð4Ñ
5ðàÐ-Ñ.óðÐ.Ð/BÑCð ÐHXÐYlÑHmó ðÐ(¨Ñ8ð Ð=MÈnÑ=]ó ðÐ0Ð1FÑGð ÐL\Ð]rÑLsó ðÐ(¨Ñ8ð Ð=MÈnÑ=]ó ô9 ô 9ð
Ø
Ð7Ñ
8ðàÐ0Ñ1óô0�Hô 0ðÐ'¨Ñ6ð Ð;KÈMÑ;Zó ô0˜ô 0ðÐ,Ð->Ñ?ð ÐDTÐUfÑDgó ô.˜(ô .ô
F xô FðØ
Ð=Ñ
>ðàÐ6Ñ7óô:˜ô :ô
D ô Dð
OÐ'@ð OÀXÈcÁ]ó Oô@�Hô @ð�mð ¨ó ð dð ¨w°s¸F°{Ñ/Có ô1�Hô 1ð˜-ð ¨Mó ñ 0°Ó@Ð �eÓ @ñ 4¸SÔAÐ �UÓ AØ.€�Ó .à!×/Ò/×5Ò5¸×8WÒ8W×8]Ò8]Ñ]€
ˆEÓ ]ð sð °9ð Àó ð.6¨Fð 6°t¸CÀ¸I±ÈÑ7Mó 6ð j˜s T¨#¡Y™°Ñ5ð jÀ6ÈDÁ=ð jÐUYó jñZ /?¸rÓ.B€��g˜c 6˜kÑ*Ñ+Ó Bð˜cð ¨xð ¸Dó ð¨#ð ¸8ð Èó ñ, 2BÀ"Ó1EÐ �5˜  f Ñ-Ñ.Ó EðY˜Vð Y¨ó Yð
 G¨C°¨KÑ$8ð 
¸Tó 
ðN ¨¨f¨Ñ!5ð N¸$ó Nð Cð °Xð À$ó ð2¨ð ¸(ð Àtó ð$
Q S¨4¡Zð 
Q¸VÀd¹]ð 
QÈtó 
Qð s¨T°#©Y¡¸Ñ'=ð È6ÐTXÉ=ð Ð]bÐcfÐhkÐckÑ]ló ð¨5°°c°©?ð ¸só ð*
Ø1°DÑ8ð*
à�$�s‘)‰O˜dÑ"ð*
ð ˜‘ð*
ð ð	*
ð
   $Ñ&ð*
ð $ð*
ð 
ó*
ðZv°ð v¸wð vÐVZð vÐcfð vÐkoó vð
¸Tð 
ÐQUð 
Ð^að 
Ðfjó 
ð$°5¸4±<ð ÐUYð Ðbeð Ðjnó ð".Ð ˜e E™ló ð3
°¸¸V¸Ñ0Dð 3
ÐSdÐgkÑSkð 3
Ðptó 3
ðl&
Øð&
à $Ñ&ð&
ð # TÑ)ð&
ð ð	&
ð
 
ó&
ñV !*òó	!Ð ˜ó 	ñ -6òó-Ð " Eó ð*  %Ø;?òxØðxà" TÑ)ðxð # TÑ)ðxð *¨DÑ0ð	xð
  ™ðxð ðxð ðxð ˜‘ðxð $ðxð   $Ñ&ðxð ðxð ðxð 2°DÑ8ðxð 
óxðv	Ø $Ñ&ðà˜Ñóð, *.òØðàðð ðð   $Ñ&ð	ð
   $Ñ&ðð 
óð6Ð#4°tÑ#;ó ð cð ¸4ð ÀDó ð,Øðàðð )ðð 
ó	ð@Ø%ðà˜T‘zðð 
óð  dð ¨tó ð$ %)ò9Ø $Ñ&ð9à'ð9ð ˜T‘kð9ð ˜4Ñó	9ðx ð4Øð4à $Ñ&ð4ð (ð4ð ˜4Ñò	4ó ð4ðv %)ò	(Ø&ð(àð(ð (ð(ð ˜T‘kð	(ð
 ó(ðV'
Ø&ð'
àð'
ð 
ó'
ðX lÐ �UÓ kð#˜3ð # 7¨3°¨;Ñ#7ó #ð
R G¨C°¨KÑ$8ó R÷
fñ fñ 1Ó2Ð �eÓ 2ð ". §¢£Ð ˜Ó /Ø&2 g§l¢l£nÐ ˜eÓ 4Ø0<°·²³Ð &¨Ó >ð Øð àð ð (ð ð ˆs�^�dÑÐ/Ñ/ó	 ð
VØð
Và��c�‰?˜SÑ ð
Vð 
ð
Vð (ð	
Vð
 
ó
Vð)#Øð)#àð)#ð ð)#ð ˜˜I e¨C°¨H¡oÑ6Ð6Ñ7ð	)#ð
 (ð)#ð ˆs�^�dÑó)#ðX
Øð
àð
ð ð
ð �|Š|ð	
ð
 ˜˜I e¨C°¨H¡oÑ6Ð6Ñ7ð
ð (ð
ð ˆs�^�dÑó
ðBØðà'ðð ˆs�^�dÑóð.@Øð@àð@ð (ð@ð  % t™|ð	@ð
 
ó@ð> ð
 Ø$(Ø-1Ø.2ò^Ø�t‘ð^à $Ñ&ð^ð (ð^ð �‰:ð	^ð
 ˜T‘kð^ð $ dÑ*ð^ð  % t™|ð^ð ˜DÑ ò^ó ñ^ðB ,.Ñ ! 5Ó -Ø+.Ñ ! 5Ó .ð %)Ø-1Øò>Ø˜4‘Zð>à $Ñ&ð>ð (ð>ð ˜T‘kð	>ð
 $ dÑ*ð>ð ð>ð 	ˆ4�Zô>ðJ %)Ø-1Øò'Øð'àð'ð (ð'ð ˜T‘kð	'ð
 $ dÑ*ð'ð ð'ð 
ô'ðTØðà'ðð ˆs�^�dÑôð,Øðà'ðð ˆs�^�dÑôð,!Ø˜c‘]ð!àð!ð (ð!ð ˆ5�Ð,Ð,Ñ-¨sÐ2Ñ3ô	!ðHÐ$Dð ÐI_ô ð ðZØ  ™ðZà $Ñ&ðZð (ðZð 
ˆ#Ð%Ð
%Ñ&ò	Zó ñZð>$Ø˜C‘=ð$àð$ð (ð$ð ˆ5�Ð&Ð&Ñ'¨Ð,Ñ-ô	$ðN ð
 %)Ø-1ò(cØ�C‰yð(cà $Ñ&ð(cð (ð(cð ˜T‘kð	(cð
 $ dÑ*ð(cð 
ˆ#ÐÐ
Ñ ò(có ñ(cðV ð
 %)Ø-1ò"%Ø�D‰jð"%à $Ñ&ð"%ð (ð"%ð ˜T‘kð	"%ð
 $ dÑ*ð"%ð ˜Ñò"%ó ñ"%ðJ ð %)Ø-1ò7Øð7àð7ð   $Ñ&ð7ð (ð	7ð
 ˜T‘kð7ð $ dÑ*ð7ð Ð&Ñ'ò7ó ñ7ðt ð °4¸±9¸tÑ3Cð ÐQWÐZ^ÑQ^ð Ðcgô ð8˜#ð Ð4Jð Ð]`ð Ðeiô ð4 Sð 4°¸$±ð 4ÐUkô 4ðØðàðð 
Ð#Ñ	$ðð 
ˆ#�Y�Ñô	ð,Øðàðð 
ˆ#�Y�Ñôð"Øðàðð 
ˆ#�Y�Ñôð" #Ø!ò'Øð'à�t‘ð'ð �d‘
ð'ð ô	'ðTØ $Ñ&ðà'ðð  ðð �d‘
ð	ð
 ôð8 ð %)Ø-1Ø"Ø!Ø!%òP
Ø�4‰ZðP
à $Ñ&ðP
ð (ðP
ð ð	P
ð
 ˜T‘kðP
ð $ dÑ*ðP
ð �t‘ðP
ð �d‘
ðP
ð ˜$‘;ðP
ð ˜ÑòP
ó ñP
ðfØ	ðà�w˜s F˜{Ñ+Ñ+ðð (ðð $ dÑ*ð	ñ �Y‘ôð*8Øð8à*ð8ð (ð8ð $ dÑ*ô	8ð~ #ò	kØðkàðkð (ðkð �t‰|ð	kð
 
ôkð\#=Øð#=à�d‘
ð#=ð (ð#=ð $ dÑ*ð	#=ð
 
ô#=ðLØðà$ðð (ðð $ dÑ*ô	ð*"9Øð"9à'ð"9ð $ dÑ*õ"9ñJ#Ø˜C‘=ð#à'ð#ð $ dÑ*ð#ð 
õ	#öL˜)õ ö9˜õ 9ð" àMQòØðØ!-ñØ?CÀd¹{ðáóó ñð,d¨Cð dÀð dÑQhõ dð #'ò?Øð?àð?ð (ð?ð 0ð	?ð
 ð?ð $ dÑ*ð?ð 
ñ?ð ˜4‘Kð?ð  õ?ðD
Ø	ð
à'ð
ð ˜T‘kð
ð   $Ñ&õ	
ð" %)Ø-1Ø$(Ø!%Ø"&ò:
Øð:
à $Ñ&ð:
ð (ð:
ð ˜T‘kð	:
ð
 $ dÑ*ñ:
ð ˜T‘kð:
ð ˜$‘;ñ:
ð ˜4‘Kð:
ð  õ:
ðB .2ó	Øñà0ðð (ðð $ dÑ*õ	ð$ .2ó\Øð\à'ð\ð $ dÑ*õ\ð ð
 .2ó	?
Øð?
à $Ñ&ð?
ð (ð?
ð $ dÑ*ð	?
ð
 ó?
ó ñ?
ðD ð
 *.Ø-1òh
Øðh
à $Ñ&ðh
ð (ðh
ð ™vÑ&ð	h
ð
 $ dÑ*ðh
ð  óh
ó ñh
ðV ð
 *.Ø-1óT
ØðT
à $Ñ&ðT
ð (ðT
ð ™vÑ&ð	T
ð
 $ dÑ*ðT
ð  Ñ%óT
ó ñT
ñn '7Ñ ˜eÔ 6÷xyô xyðv&Øð&àð&ð ˜T‘kð&ð $ dÑ*ð	&ð
 �Ñõ&ðR ñØñàðð  ðð 	ˆ4�Zó	ó ñð, ð
 %)Ø-1Ø$(òJØðJà $Ñ&ðJð (ðJð ˜T‘kð	Jð
 $ dÑ*ñJð ˜T‘kðJð óJó ñJðZØ$ðàõð ð
 %)Ø-1ó+Øð+à $Ñ&ð+ð (ð+ð ˜T‘kð	+ð
 $ dÑ*ð+ð # TÑ)ó+ó ñ+ð\ ð
 %)Ø-1ó8Ø�‰9ð8à $Ñ&ð8ð (ð8ð ˜T‘kð	8ð
 $ dÑ*ð8ð 
Ð
*Ñ+ó8ó ñ8öv 	õ ð ð
 %)Ø-1Ø!&óCØðCà $Ñ&ðCð (ðCð ˜T‘kð	Cð
 $ dÑ*ñCð ðCð  Ñ%óCó ñCðR *.Ø15Ø-1ó8 Ø˜s‘mñ8 àÑ]Ñ^ð8 ð   $Ñ&ð8 ð (¨$Ñ.ð	8 ð
 $ dÑ*ð8 ð 
ˆ#�Yõ8 ðz *.Ø15Ø-1ó	Ø˜s‘mðà $Ñ&ðð (¨$Ñ.ðð $ dÑ*ð	ð
 
ˆ#�Yõð* *.Ø15Ø-1ó	Ø˜3‘iðà $Ñ&ðð (¨$Ñ.ðð $ dÑ*ð	ð
 
ˆ#�Yõð* *.Ø15Ø-1ó	Ø˜3‘iðà $Ñ&ðð (¨$Ñ.ðð $ dÑ*ð	ð
 
ˆ#�Yõð&CØ�‰IðCà˜‘ðCð �4‰ZðCð 
ˆ#�Yõ	Cð$ 15Øò-Øð-à˜‘ð-ð �‰Iñ-ð ˜S #˜X™¨Ñ-ð	-ð
 �4‰Zð-ð 
õ-ðh 15ØØDJØò@Ø��c‘‰?ð@à˜‘ð@ð �‰Iñ@ð ˜S #˜X™¨Ñ-ð	@ð
 �4‰Zñ@ð Ñ@ÑAñ@ð ð@ð ‰T�]õ@òF #ñ ¸4ÀÀSÀ¹>ÈDÑ;Pð Ð\`õ ð$°Nð ÀtÈCÁyõ ð$Ø�˜#‘Ñðàðð �4‰Zðð ˆs�^õ	ðVØðVà" TÑ)ðVð  ðVð (ð	Vð
 $ðVð ˆc�]õVð*?Øð?à" TÑ)ð?ð  ð?ð (ð	?ð
 $ð?ð ˆc�]õ?ð2Øðà" TÑ)ðð 2°DÑ8ðð  ð	ð
 (ðð $ðð ˆ8�C‰=˜#ÐÑõð<94Ø�˜#‘Ñ Ñ%ð94à $Ñ&ð94ð # TÑ)ð94ð 2°DÑ8ð	94ð
 ˜‘ð94ð   $Ñ&ð94ð (ð94ð $ð94ð ˆ3�ˆ8�_õ94ðx!Ø�˜#‘Ñ Ñ%ð!à $Ñ&ð!ð # TÑ)ð!ð 2°DÑ8ð	!ð
 ˜‘ð!ð   $Ñ&ð!ð (ð!ð $ð!ð ˆ3�ˆ8�_õ!ðH,Ø��c‘‰?ñ,à˜4‘Kð,ð  ð,ð —’ Ñ%ð	,ð
 ‰T�]õ,ð^XØñXà˜4‘KðXð  ðXð —’ Ñ%ð	Xð
 
õXð~ 15ò	Øñà)¨DÑ0ðð ˜‘ñð ˜S #˜X™¨Ñ-ð	ð
 ‰T�]õð. 15ò	%Ø��c‘‰?ð%à" TÑ)ð%ð ˜‘ñ%ð ˜S #˜X™¨Ñ-ð	%ð
 ‰T�]õ%ðP-+Ø $Ñ&ð-+à" TÑ)ñ-+ð Ñ]Ñ^ð-+ð 
ˆ#�Yõ	-+ð`Ø��c‘‰?ðà $Ñ&ðð # TÑ)ðð ˜‘ð	ð
 
õð@Ø��c‘‰?ðà1ðð ˜‘ðð ‰T�]õ	ð$Ø��c‘‰?ðà˜‘ðð # TÑ)ðð ‰T�]õ	ñ0	Ø4°tÑ;ð	à	ˆ#�Yõ	ñ$Øñ$à˜s™)ñ$ð Ñ1Ñ2ð$ð ‰T�]õ	$ñNØðàðð ‰T�]õñ4Øðà" TÑ)ðð ‰T�]õñ:Øðàðð # TÑ)ðð 
õ	ð.Øðà˜‘ñð �d‘
ðð ‰T�]õ	ð2°ð ÀDõ ð* *.òHØðHà#ðHð   $Ñ&õHðV)Øõ)ð^ *.ò$
Øð$
à#ð$
ð   $Ñ&õ$
ñN˜3 ¨&Ñ!1Ñ1°DÑ8ð ¸TÀ#¹Yõ ñ
=Ø	��c˜H VÑ,Ñ,¨tÑ3Ð3Ñ	4°tÑ	;ð
=à	ˆ#ˆt�C‰yˆ.Ñõ
=ñØ˜˜S 8¨FÑ#3Ñ3°dÑ:Ð:Ñ;¸dÑBñà˜˜c H¨VÑ$4Ñ4°tÑ;Ð;Ñ<¸tÑCðð 
ˆ#ˆt�C‰yˆ.Ñ˜DÑ õð, *.òOØðOà#ðOð   $Ñ&õOðdDØ" TÑ)ðDà" TÑ)ðDð   $Ñ&ðDð   $Ñ&ð	Dð
 (ðDð $õDðN0
Ø��c‘‰?ð0
à"ð0
ð  ð0
ð ˜‘ð	0
ð
 ™NÑ+ð0
ð (ð0
ð $ð0
ð 
õ0
ðf/Ø" TÑ)ð/à $Ñ&ð/ð $õ/ðd%Ø" TÑ)õ%ðPDØ" TÑ)ðDà $Ñ&ðDð $õDðN1
Ø1°DÑ8ð1
à $Ñ&ð1
ð $õ1
ðh)Ø1°DÑ8ð)à $Ñ&ð)ð $õ)ñX& 3ð &¨3õ &ð .2ó	-Øð-à $Ñ&ð-ð (ð-ð $ dÑ*ð	-ð
 # TÑ)õ-ñ`Øðà'ðð 
õð _
Ø $Ñ&ð_
à" TÑ)ð_
ð   $Ñ&ð_
ð (ð	_
ð
 $õ_
ðD8Øð8à $Ñ&ð8ð (ð8ð $ð	8ð
   $Ñ&õ8ñv4
Ø!)¨#¡ð4
à $Ñ&ð4
ð (ð4
ð 
õ	4
ðn sñ À3ð È4õ ð&°sñ ÐPTð ÐY]õ ð:¸sñ Ð[^ð Ðcgõ ñ<(°ð (¸õ (ð<Øð<à" TÑ)ð<ð   $Ñ&õ<ñ~ØÑ-Ñ.ñà! #™Yñð 3°TÑ9ör   